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"
69 #define COL_FOLDER_WIDTH 150
70 #define COL_NUM_WIDTH 32
72 static GList *folderview_list = NULL;
74 static GtkStyle *normal_style;
75 static GtkStyle *normal_color_style;
76 static GtkStyle *bold_style;
77 static GtkStyle *bold_color_style;
78 static GtkStyle *bold_tgtfold_style;
80 static GdkPixmap *inboxxpm;
81 static GdkBitmap *inboxxpmmask;
82 static GdkPixmap *inboxhrmxpm;
83 static GdkBitmap *inboxhrmxpmmask;
84 static GdkPixmap *inboxopenxpm;
85 static GdkBitmap *inboxopenxpmmask;
86 static GdkPixmap *inboxopenhrmxpm;
87 static GdkBitmap *inboxopenhrmxpmmask;
88 static GdkPixmap *outboxxpm;
89 static GdkBitmap *outboxxpmmask;
90 static GdkPixmap *outboxhrmxpm;
91 static GdkBitmap *outboxhrmxpmmask;
92 static GdkPixmap *outboxopenxpm;
93 static GdkBitmap *outboxopenxpmmask;
94 static GdkPixmap *outboxopenhrmxpm;
95 static GdkBitmap *outboxopenhrmxpmmask;
96 static GdkPixmap *folderxpm;
97 static GdkBitmap *folderxpmmask;
98 static GdkPixmap *folderhrmxpm;
99 static GdkBitmap *folderhrmxpmmask;
100 static GdkPixmap *folderopenxpm;
101 static GdkBitmap *folderopenxpmmask;
102 static GdkPixmap *folderopenhrmxpm;
103 static GdkBitmap *folderopenhrmxpmmask;
104 static GdkPixmap *trashopenxpm;
105 static GdkBitmap *trashopenxpmmask;
106 static GdkPixmap *trashopenhrmxpm;
107 static GdkBitmap *trashopenhrmxpmmask;
108 static GdkPixmap *trashxpm;
109 static GdkBitmap *trashxpmmask;
110 static GdkPixmap *trashhrmxpm;
111 static GdkBitmap *trashhrmxpmmask;
112 static GdkPixmap *queuexpm;
113 static GdkBitmap *queuexpmmask;
114 static GdkPixmap *queuehrmxpm;
115 static GdkBitmap *queuehrmxpmmask;
116 static GdkPixmap *queueopenxpm;
117 static GdkBitmap *queueopenxpmmask;
118 static GdkPixmap *queueopenhrmxpm;
119 static GdkBitmap *queueopenhrmxpmmask;
120 static GdkPixmap *draftsxpm;
121 static GdkBitmap *draftsxpmmask;
122 static GdkPixmap *draftsopenxpm;
123 static GdkBitmap *draftsopenxpmmask;
124 static GdkPixmap *noselectxpm;
125 static GdkBitmap *noselectxpmmask;
127 static GdkPixmap *m_inboxxpm;
128 static GdkBitmap *m_inboxxpmmask;
129 static GdkPixmap *m_inboxhrmxpm;
130 static GdkBitmap *m_inboxhrmxpmmask;
131 static GdkPixmap *m_inboxopenxpm;
132 static GdkBitmap *m_inboxopenxpmmask;
133 static GdkPixmap *m_inboxopenhrmxpm;
134 static GdkBitmap *m_inboxopenhrmxpmmask;
135 static GdkPixmap *m_outboxxpm;
136 static GdkBitmap *m_outboxxpmmask;
137 static GdkPixmap *m_outboxhrmxpm;
138 static GdkBitmap *m_outboxhrmxpmmask;
139 static GdkPixmap *m_outboxopenxpm;
140 static GdkBitmap *m_outboxopenxpmmask;
141 static GdkPixmap *m_outboxopenhrmxpm;
142 static GdkBitmap *m_outboxopenhrmxpmmask;
143 static GdkPixmap *m_folderxpm;
144 static GdkBitmap *m_folderxpmmask;
145 static GdkPixmap *m_folderhrmxpm;
146 static GdkBitmap *m_folderhrmxpmmask;
147 static GdkPixmap *m_folderopenxpm;
148 static GdkBitmap *m_folderopenxpmmask;
149 static GdkPixmap *m_folderopenhrmxpm;
150 static GdkBitmap *m_folderopenhrmxpmmask;
151 static GdkPixmap *m_trashopenxpm;
152 static GdkBitmap *m_trashopenxpmmask;
153 static GdkPixmap *m_trashopenhrmxpm;
154 static GdkBitmap *m_trashopenhrmxpmmask;
155 static GdkPixmap *m_trashxpm;
156 static GdkBitmap *m_trashxpmmask;
157 static GdkPixmap *m_trashhrmxpm;
158 static GdkBitmap *m_trashhrmxpmmask;
159 static GdkPixmap *m_queuexpm;
160 static GdkBitmap *m_queuexpmmask;
161 static GdkPixmap *m_queuehrmxpm;
162 static GdkBitmap *m_queuehrmxpmmask;
163 static GdkPixmap *m_queueopenxpm;
164 static GdkBitmap *m_queueopenxpmmask;
165 static GdkPixmap *m_queueopenhrmxpm;
166 static GdkBitmap *m_queueopenhrmxpmmask;
167 static GdkPixmap *m_draftsxpm;
168 static GdkBitmap *m_draftsxpmmask;
169 static GdkPixmap *m_draftsopenxpm;
170 static GdkBitmap *m_draftsopenxpmmask;
172 static GdkPixmap *newxpm;
173 static GdkBitmap *newxpmmask;
174 static GdkPixmap *unreadxpm;
175 static GdkBitmap *unreadxpmmask;
176 static GdkPixmap *readxpm;
177 static GdkBitmap *readxpmmask;
180 static void folderview_select_node (FolderView *folderview,
182 static void folderview_set_folders (FolderView *folderview);
183 static void folderview_sort_folders (FolderView *folderview,
186 static void folderview_append_folder (FolderView *folderview,
188 static void folderview_update_node (FolderView *folderview,
191 static gint folderview_clist_compare (GtkCList *clist,
195 /* callback functions */
196 static gboolean folderview_button_pressed (GtkWidget *ctree,
197 GdkEventButton *event,
198 FolderView *folderview);
199 static gboolean folderview_button_released (GtkWidget *ctree,
200 GdkEventButton *event,
201 FolderView *folderview);
202 static gboolean folderview_key_pressed (GtkWidget *widget,
204 FolderView *folderview);
205 static void folderview_selected (GtkCTree *ctree,
208 FolderView *folderview);
209 static void folderview_tree_expanded (GtkCTree *ctree,
211 FolderView *folderview);
212 static void folderview_tree_collapsed (GtkCTree *ctree,
214 FolderView *folderview);
215 static void folderview_popup_close (GtkMenuShell *menu_shell,
216 FolderView *folderview);
217 static void folderview_col_resized (GtkCList *clist,
220 FolderView *folderview);
222 static void mark_all_read_cb (FolderView *folderview,
226 static void folderview_empty_trash_cb (FolderView *folderview,
230 static void folderview_send_queue_cb (FolderView *folderview,
234 static void folderview_search_cb (FolderView *folderview,
238 static void folderview_property_cb (FolderView *folderview,
242 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
243 GdkDragContext *context,
247 FolderView *folderview);
248 static void folderview_drag_leave_cb (GtkWidget *widget,
249 GdkDragContext *context,
251 FolderView *folderview);
252 static void folderview_drag_received_cb (GtkWidget *widget,
253 GdkDragContext *drag_context,
256 GtkSelectionData *data,
259 FolderView *folderview);
260 static void folderview_start_drag (GtkWidget *widget, gint button, GdkEvent *event,
261 FolderView *folderview);
262 static void folderview_drag_data_get (GtkWidget *widget,
263 GdkDragContext *drag_context,
264 GtkSelectionData *selection_data,
267 FolderView *folderview);
268 static void folderview_drag_end_cb (GtkWidget *widget,
269 GdkDragContext *drag_context,
270 FolderView *folderview);
272 void folderview_create_folder_node (FolderView *folderview,
274 gboolean folderview_update_folder (gpointer source,
276 gboolean folderview_update_item_claws (gpointer source,
278 static void folderview_processing_cb(FolderView *folderview, guint action,
281 GHashTable *folderview_popups;
283 static GtkItemFactoryEntry folderview_common_popup_entries[] =
285 {N_("/Mark all re_ad"), NULL, mark_all_read_cb, 0, NULL},
286 {N_("/_Search folder..."), NULL, folderview_search_cb, 0, NULL},
287 {N_("/_Properties..."), NULL, folderview_property_cb, 0, NULL},
288 {N_("/Process_ing..."), NULL, folderview_processing_cb, 0, NULL},
291 static GtkItemFactoryEntry folder_view_trash_popup_entries[] = {
292 {N_("/------trashsep"), NULL, NULL, 0, "<Separator>"},
293 {N_("/Empty _trash..."), NULL, folderview_empty_trash_cb, 0, NULL},
296 static GtkItemFactoryEntry folder_view_queue_popup_entries[] = {
297 {N_("/------queuesep"), NULL, NULL, 0, "<Separator>"},
298 {N_("/Send _queue..."), NULL, folderview_send_queue_cb, 0, NULL},
302 GtkTargetEntry folderview_drag_types[] =
304 {"sylpheed-claws/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY},
305 {"text/uri-list", 0, TARGET_MAIL_URI_LIST}
308 void folderview_initialize(void)
310 FolderViewPopup *fpopup;
312 GSList *entries = NULL;
314 fpopup = g_new0(FolderViewPopup, 1);
316 n_entries = sizeof(folderview_common_popup_entries) /
317 sizeof(folderview_common_popup_entries[0]);
318 for (i = 0; i < n_entries; i++)
319 entries = g_slist_append(entries, &folderview_common_popup_entries[i]);
321 fpopup->klass = "common";
322 fpopup->path = "<CommonFolder>";
323 fpopup->entries = entries;
324 fpopup->set_sensitivity = NULL;
326 folderview_popups = g_hash_table_new(g_str_hash, g_str_equal);
327 g_hash_table_insert(folderview_popups, "common", fpopup);
330 static GtkItemFactory *create_ifactory(FolderView *folderview, FolderViewPopup *fpopup)
333 GtkItemFactory *factory;
334 FolderViewPopup *fpopup_common;
337 factory = gtk_item_factory_new(GTK_TYPE_MENU, fpopup->path, NULL);
338 gtk_item_factory_set_translate_func(factory, menu_translate,
341 for (entries = fpopup->entries; entries != NULL; entries = g_slist_next(entries))
342 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
344 fpopup_common = g_hash_table_lookup(folderview_popups, "common");
345 if (fpopup_common != fpopup)
346 for (entries = fpopup_common->entries; entries != NULL; entries = g_slist_next(entries))
347 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
349 popup = gtk_item_factory_get_widget(factory, fpopup->path);
350 g_signal_connect(G_OBJECT(popup), "selection_done",
351 G_CALLBACK(folderview_popup_close),
357 static void create_ifactories(gpointer key, gpointer value, gpointer data)
359 FolderView *folderview = data;
360 FolderViewPopup *fpopup = value;
361 GtkItemFactory *factory;
363 factory = create_ifactory(folderview, fpopup);
364 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
367 static void folderview_column_set_titles(FolderView *folderview)
369 GtkWidget *ctree = folderview->ctree;
370 GtkWidget *label_new;
371 GtkWidget *label_unread;
372 GtkWidget *label_total;
374 GtkWidget *hbox_unread;
375 GtkWidget *hbox_total;
376 gint *col_pos = folderview->col_pos;
378 debug_print("setting titles...\n");
379 gtk_widget_realize(folderview->ctree);
380 gtk_widget_show_all(folderview->scrolledwin);
382 /* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
383 * instead text (text overflows making them unreadable and ugly) */
384 stock_pixmap_gdk(ctree, STOCK_PIXMAP_NEW,
385 &newxpm, &newxpmmask);
386 stock_pixmap_gdk(ctree, STOCK_PIXMAP_UNREAD,
387 &unreadxpm, &unreadxpmmask);
388 stock_pixmap_gdk(ctree, STOCK_PIXMAP_READ,
389 &readxpm, &readxpmmask);
391 label_new = gtk_pixmap_new(newxpm, newxpmmask);
392 label_unread = gtk_pixmap_new(unreadxpm, unreadxpmmask);
393 label_total = gtk_pixmap_new(readxpm, readxpmmask);
395 hbox_new = gtk_hbox_new(FALSE, 4);
396 hbox_unread = gtk_hbox_new(FALSE, 4);
397 hbox_total = gtk_hbox_new(FALSE, 4);
400 gtk_box_pack_start(GTK_BOX(hbox_new), label_new, TRUE, TRUE, 0);
401 gtk_misc_set_alignment (GTK_MISC (label_new), 1, 0.5);
402 gtk_box_pack_start(GTK_BOX(hbox_unread), label_unread, TRUE, TRUE, 0);
403 gtk_misc_set_alignment (GTK_MISC (label_unread), 1, 0.5);
404 gtk_box_pack_start(GTK_BOX(hbox_total), label_total, TRUE, TRUE, 0);
405 gtk_misc_set_alignment (GTK_MISC (label_total), 1, 0.5);
407 gtk_widget_show_all(hbox_new);
408 gtk_widget_show_all(hbox_unread);
409 gtk_widget_show_all(hbox_total);
411 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_NEW],hbox_new);
412 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_UNREAD],hbox_unread);
413 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_TOTAL],hbox_total);
416 GtkWidget *folderview_ctree_create(FolderView *folderview)
420 FolderColumnState *col_state;
421 FolderColumnType type;
422 gchar *titles[N_FOLDER_COLS];
424 GtkWidget *scrolledwin = folderview->scrolledwin;
426 debug_print("creating tree...\n");
427 memset(titles, 0, sizeof(titles));
429 col_state = prefs_folder_column_get_config();
430 memset(titles, 0, sizeof(titles));
432 col_pos = folderview->col_pos;
434 for (i = 0; i < N_FOLDER_COLS; i++) {
435 folderview->col_state[i] = col_state[i];
436 type = col_state[i].type;
440 titles[col_pos[F_COL_FOLDER]] = _("Folder");
441 titles[col_pos[F_COL_NEW]] = _("New");
442 titles[col_pos[F_COL_UNREAD]] = _("Unread");
443 /* TRANSLATORS: This in Number sign in American style */
444 titles[col_pos[F_COL_TOTAL]] = _("#");
446 ctree = gtk_sctree_new_with_titles(N_FOLDER_COLS, col_pos[F_COL_FOLDER],
449 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
450 gtk_clist_set_column_justification(GTK_CLIST(ctree), col_pos[F_COL_NEW],
452 gtk_clist_set_column_justification(GTK_CLIST(ctree),
453 col_pos[F_COL_UNREAD],
455 gtk_clist_set_column_justification(GTK_CLIST(ctree),
456 col_pos[F_COL_TOTAL],
458 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
459 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
460 GTK_CTREE_EXPANDER_SQUARE);
461 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
462 gtk_clist_set_compare_func(GTK_CLIST(ctree), folderview_clist_compare);
464 /* don't let title buttons take key focus */
465 for (i = 0; i < N_FOLDER_COLS; i++) {
466 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[i].button,
468 gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[i],
469 prefs_common.folder_col_size[i]);
470 gtk_clist_set_column_visibility
471 (GTK_CLIST(ctree), i, col_state[i].visible);
474 g_signal_connect(G_OBJECT(ctree), "key_press_event",
475 G_CALLBACK(folderview_key_pressed),
477 g_signal_connect(G_OBJECT(ctree), "button_press_event",
478 G_CALLBACK(folderview_button_pressed),
480 g_signal_connect(G_OBJECT(ctree), "button_release_event",
481 G_CALLBACK(folderview_button_released),
483 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
484 G_CALLBACK(folderview_selected), folderview);
485 g_signal_connect(G_OBJECT(ctree), "start_drag",
486 G_CALLBACK(folderview_start_drag), folderview);
487 g_signal_connect(G_OBJECT(ctree), "drag_data_get",
488 G_CALLBACK(folderview_drag_data_get),
491 g_signal_connect_after(G_OBJECT(ctree), "tree_expand",
492 G_CALLBACK(folderview_tree_expanded),
494 g_signal_connect_after(G_OBJECT(ctree), "tree_collapse",
495 G_CALLBACK(folderview_tree_collapsed),
498 g_signal_connect(G_OBJECT(ctree), "resize_column",
499 G_CALLBACK(folderview_col_resized),
503 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
504 folderview_drag_types, 2,
505 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
506 g_signal_connect(G_OBJECT(ctree), "drag_motion",
507 G_CALLBACK(folderview_drag_motion_cb),
509 g_signal_connect(G_OBJECT(ctree), "drag_leave",
510 G_CALLBACK(folderview_drag_leave_cb),
512 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
513 G_CALLBACK(folderview_drag_received_cb),
515 g_signal_connect(G_OBJECT(ctree), "drag_end",
516 G_CALLBACK(folderview_drag_end_cb),
519 gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
524 void folderview_set_column_order(FolderView *folderview)
527 FolderItem *item = folderview_get_selected_item(folderview);
528 GtkWidget *scrolledwin = folderview->scrolledwin;
530 debug_print("recreating tree...\n");
531 gtk_widget_destroy(folderview->ctree);
533 folderview->ctree = ctree = folderview_ctree_create(folderview);
534 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
535 GTK_CLIST(ctree)->hadjustment);
536 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
537 GTK_CLIST(ctree)->vadjustment);
538 gtk_widget_show(ctree);
540 folderview_set(folderview);
541 folderview_column_set_titles(folderview);
543 folderview_select(folderview,item);
546 FolderView *folderview_create(void)
548 FolderView *folderview;
549 GtkWidget *scrolledwin;
552 debug_print("Creating folder view...\n");
553 folderview = g_new0(FolderView, 1);
555 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
556 gtk_scrolled_window_set_policy
557 (GTK_SCROLLED_WINDOW(scrolledwin),
558 GTK_POLICY_AUTOMATIC,
559 prefs_common.folderview_vscrollbar_policy);
560 gtk_widget_set_size_request(scrolledwin,
561 prefs_common.folderview_width,
562 prefs_common.folderview_height);
564 folderview->scrolledwin = scrolledwin;
565 ctree = folderview_ctree_create(folderview);
567 /* create popup factories */
568 folderview->popups = g_hash_table_new(g_str_hash, g_str_equal);
569 g_hash_table_foreach(folderview_popups, create_ifactories, folderview);
571 folderview->ctree = ctree;
573 folderview->folder_update_callback_id =
574 hooks_register_hook(FOLDER_UPDATE_HOOKLIST, folderview_update_folder, (gpointer) folderview);
575 folderview->folder_item_update_callback_id =
576 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item_claws, (gpointer) folderview);
578 gtk_widget_show_all(scrolledwin);
580 folderview->target_list = gtk_target_list_new(folderview_drag_types, 2);
581 folderview_list = g_list_append(folderview_list, folderview);
586 void folderview_init(FolderView *folderview)
588 GtkWidget *ctree = folderview->ctree;
591 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE, &inboxxpm, &inboxxpmmask);
592 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM, &inboxhrmxpm, &inboxhrmxpmmask);
593 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN, &inboxopenxpm, &inboxopenxpmmask);
594 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM, &inboxopenhrmxpm, &inboxopenhrmxpmmask);
595 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE, &outboxxpm, &outboxxpmmask);
596 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM, &outboxhrmxpm, &outboxhrmxpmmask);
597 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN, &outboxopenxpm, &outboxopenxpmmask);
598 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM, &outboxopenhrmxpm, &outboxopenhrmxpmmask);
599 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
600 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM, &folderhrmxpm, &folderhrmxpmmask);
601 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
602 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM, &folderopenhrmxpm, &folderopenhrmxpmmask);
603 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN, &trashopenxpm, &trashopenxpmmask);
604 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM, &trashopenhrmxpm, &trashopenhrmxpmmask);
605 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE, &trashxpm, &trashxpmmask);
606 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM, &trashhrmxpm, &trashhrmxpmmask);
607 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE, &queuexpm, &queuexpmmask);
608 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM, &queuehrmxpm, &queuehrmxpmmask);
609 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN, &queueopenxpm, &queueopenxpmmask);
610 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM, &queueopenhrmxpm, &queueopenhrmxpmmask);
611 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE, &draftsxpm, &draftsxpmmask);
612 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN, &draftsopenxpm, &draftsopenxpmmask);
613 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_NOSELECT, &noselectxpm, &noselectxpmmask);
615 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_MARK, &m_inboxxpm, &m_inboxxpmmask);
616 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK, &m_inboxhrmxpm, &m_inboxhrmxpmmask);
617 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_MARK, &m_inboxopenxpm, &m_inboxopenxpmmask);
618 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM_MARK, &m_inboxopenhrmxpm, &m_inboxopenhrmxpmmask);
619 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_MARK, &m_outboxxpm, &m_outboxxpmmask);
620 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK, &m_outboxhrmxpm, &m_outboxhrmxpmmask);
621 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_MARK, &m_outboxopenxpm, &m_outboxopenxpmmask);
622 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK, &m_outboxopenhrmxpm, &m_outboxopenhrmxpmmask);
623 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_MARK, &m_folderxpm, &m_folderxpmmask);
624 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM_MARK, &m_folderhrmxpm, &m_folderhrmxpmmask);
625 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_MARK, &m_folderopenxpm, &m_folderopenxpmmask);
626 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM_MARK, &m_folderopenhrmxpm, &m_folderopenhrmxpmmask);
627 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_MARK, &m_trashopenxpm, &m_trashopenxpmmask);
628 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM_MARK, &m_trashopenhrmxpm, &m_trashopenhrmxpmmask);
629 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_MARK, &m_trashxpm, &m_trashxpmmask);
630 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK, &m_trashhrmxpm, &m_trashhrmxpmmask);
631 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_MARK, &m_queuexpm, &m_queuexpmmask);
632 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK, &m_queuehrmxpm, &m_queuehrmxpmmask);
633 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_MARK, &m_queueopenxpm, &m_queueopenxpmmask);
634 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK, &m_queueopenhrmxpm, &m_queueopenhrmxpmmask);
635 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE_MARK, &m_draftsxpm, &m_draftsxpmmask);
636 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN_MARK, &m_draftsopenxpm, &m_draftsopenxpmmask);
639 PangoFontDescription *font_desc;
640 normal_style = gtk_style_copy(gtk_widget_get_style(ctree));
641 font_desc = pango_font_description_from_string(NORMAL_FONT);
643 if (normal_style->font_desc)
644 pango_font_description_free
645 (normal_style->font_desc);
646 normal_style->font_desc = font_desc;
648 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
649 normal_color_style = gtk_style_copy(normal_style);
650 normal_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
652 gtk_widget_set_style(ctree, normal_style);
656 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
657 bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
658 pango_font_description_set_weight
659 (bold_style->font_desc, PANGO_WEIGHT_BOLD);
660 bold_color_style = gtk_style_copy(bold_style);
661 bold_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
663 bold_tgtfold_style = gtk_style_copy(bold_style);
664 bold_tgtfold_style->fg[GTK_STATE_NORMAL] = folderview->color_op;
668 void folderview_set(FolderView *folderview)
670 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
671 MainWindow *mainwin = folderview->mainwin;
676 debug_print("Setting folder info...\n");
677 STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
679 main_window_cursor_wait(mainwin);
681 folderview->selected = NULL;
682 folderview->opened = NULL;
684 gtk_clist_freeze(GTK_CLIST(ctree));
685 gtk_clist_clear(GTK_CLIST(ctree));
686 gtk_clist_thaw(GTK_CLIST(ctree));
687 gtk_clist_freeze(GTK_CLIST(ctree));
689 folderview_set_folders(folderview);
691 gtk_clist_thaw(GTK_CLIST(ctree));
692 main_window_cursor_normal(mainwin);
693 STATUSBAR_POP(mainwin);
696 void folderview_set_all(void)
700 for (list = folderview_list; list != NULL; list = list->next)
701 folderview_set((FolderView *)list->data);
704 void folderview_select(FolderView *folderview, FolderItem *item)
706 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
708 GtkCTreeNode *old_selected = folderview->selected;
712 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
713 if (node) folderview_select_node(folderview, node);
715 if (old_selected != node)
716 folder_update_op_count();
719 static void mark_all_read_cb(FolderView *folderview, guint action,
725 item = folderview_get_selected_item(folderview);
729 if (folderview->summaryview->folder_item != item
730 && prefs_common.ask_mark_all_read) {
731 val = alertpanel_full(_("Mark all as read"),
732 _("Do you really want to mark all mails in this "
733 "folder as read ?"), GTK_STOCK_NO, GTK_STOCK_YES, NULL,
734 TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT);
736 if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
738 else if (val & G_ALERTDISABLE)
739 prefs_common.ask_mark_all_read = FALSE;
742 summary_lock(folderview->summaryview);
743 folder_item_update_freeze();
744 if (folderview->summaryview->folder_item == item)
745 gtk_clist_freeze(GTK_CLIST(folderview->summaryview->ctree));
746 folderutils_mark_all_read(item);
747 if (folderview->summaryview->folder_item == item)
748 gtk_clist_thaw(GTK_CLIST(folderview->summaryview->ctree));
749 folder_item_update_thaw();
750 summary_unlock(folderview->summaryview);
753 static void folderview_select_node(FolderView *folderview, GtkCTreeNode *node)
755 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
757 g_return_if_fail(node != NULL);
759 folderview->open_folder = TRUE;
760 gtkut_ctree_set_focus_row(ctree, node);
761 gtk_ctree_select(ctree, node);
762 if (folderview->summaryview->folder_item &&
763 folderview->summaryview->folder_item->total_msgs > 0)
764 gtk_widget_grab_focus(folderview->summaryview->ctree);
766 gtk_widget_grab_focus(folderview->ctree);
768 gtkut_ctree_expand_parent_all(ctree, node);
771 void folderview_unselect(FolderView *folderview)
773 if (folderview->opened && !GTK_CTREE_ROW(folderview->opened)->children)
775 (GTK_CTREE(folderview->ctree), folderview->opened);
777 folderview->selected = folderview->opened = NULL;
780 static GtkCTreeNode *folderview_find_next_unread(GtkCTree *ctree,
786 node = gtkut_ctree_node_next(ctree, node);
788 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
790 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
791 item = gtk_ctree_node_get_row_data(ctree, node);
792 if (item && item->unread_msgs > 0 && item->stype != F_TRASH)
799 void folderview_select_next_unread(FolderView *folderview)
801 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
802 GtkCTreeNode *node = NULL;
804 if ((node = folderview_find_next_unread(ctree, folderview->opened))
806 folderview_select_node(folderview, node);
810 if (!folderview->opened ||
811 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list))
813 /* search again from the first node */
814 if ((node = folderview_find_next_unread(ctree, NULL)) != NULL)
815 folderview_select_node(folderview, node);
818 static GtkCTreeNode *folderview_find_next_new(GtkCTree *ctree,
824 node = gtkut_ctree_node_next(ctree, node);
826 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
828 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
829 item = gtk_ctree_node_get_row_data(ctree, node);
830 if (item && item->new_msgs > 0 && item->stype != F_TRASH)
837 void folderview_select_next_new(FolderView *folderview)
839 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
840 GtkCTreeNode *node = NULL;
842 if ((node = folderview_find_next_new(ctree, folderview->opened))
844 folderview_select_node(folderview, node);
848 if (!folderview->opened ||
849 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list))
851 /* search again from the first node */
852 if ((node = folderview_find_next_new(ctree, NULL)) != NULL)
853 folderview_select_node(folderview, node);
856 FolderItem *folderview_get_selected_item(FolderView *folderview)
858 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
860 if (!folderview->selected) return NULL;
861 return gtk_ctree_node_get_row_data(ctree, folderview->selected);
864 void folderview_update_msg_num(FolderView *folderview, GtkCTreeNode *row)
866 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
867 static GtkCTreeNode *prev_row = NULL;
869 gint new, unread, total;
870 gchar *new_str, *unread_str, *total_str;
871 gint *col_pos = folderview->col_pos;
875 item = gtk_ctree_node_get_row_data(ctree, row);
878 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_NEW], &new_str);
879 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_UNREAD], &unread_str);
880 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_TOTAL], &total_str);
882 unread = atoi(unread_str);
883 total = atoi(total_str);
887 folderview_update_node(folderview, row);
890 void folderview_append_item(FolderItem *item)
894 g_return_if_fail(item != NULL);
895 g_return_if_fail(item->folder != NULL);
896 if (folder_item_parent(item)) return;
898 for (list = folderview_list; list != NULL; list = list->next) {
899 FolderView *folderview = (FolderView *)list->data;
900 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
901 GtkCTreeNode *node, *child;
902 gint *col_pos = folderview->col_pos;
904 node = gtk_ctree_find_by_row_data(ctree, NULL,
905 folder_item_parent(item));
907 child = gtk_ctree_find_by_row_data(ctree, node, item);
909 gchar *text[N_FOLDER_COLS] =
910 {NULL, "0", "0", "0"};
912 gtk_clist_freeze(GTK_CLIST(ctree));
914 text[col_pos[F_COL_FOLDER]] = item->name;
915 child = gtk_sctree_insert_node
916 (ctree, node, NULL, text,
918 folderxpm, folderxpmmask,
919 folderopenxpm, folderopenxpmmask,
921 gtk_ctree_node_set_row_data(ctree, child, item);
922 gtk_ctree_expand(ctree, node);
923 folderview_update_node(folderview, child);
924 folderview_sort_folders(folderview, node,
927 gtk_clist_thaw(GTK_CLIST(ctree));
933 static void folderview_set_folders(FolderView *folderview)
936 #ifndef HAVE_LIBETPAN
937 static gboolean missing_imap_warning = TRUE;
939 list = folder_get_list();
941 for (; list != NULL; list = list->next) {
942 #ifndef HAVE_LIBETPAN
943 if ((FOLDER(list->data))
944 && (FOLDER(list->data))->klass
945 && (FOLDER(list->data))->klass->type == F_IMAP
946 && missing_imap_warning) {
947 missing_imap_warning = FALSE;
949 _("You have one or more IMAP accounts "
950 "defined. However this version of "
951 "Sylpheed-Claws has been built without "
952 "IMAP support; your IMAP account(s) are "
954 "You probably need to "
955 "install libetpan and recompile "
959 folderview_append_folder(folderview, FOLDER(list->data));
963 static gchar *get_scan_str(FolderItem *item)
966 return g_strdup_printf(_("Scanning folder %s%c%s ..."),
967 item->folder->name, G_DIR_SEPARATOR,
970 return g_strdup_printf(_("Scanning folder %s ..."),
973 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
977 for (list = folderview_list; list != NULL; list = list->next) {
978 FolderView *folderview = (FolderView *)list->data;
979 MainWindow *mainwin = folderview->mainwin;
980 gchar *str = get_scan_str(item);
982 STATUSBAR_PUSH(mainwin, str);
983 STATUSBAR_POP(mainwin);
988 void folderview_rescan_tree(Folder *folder, gboolean rebuild)
992 g_return_if_fail(folder != NULL);
994 if (!folder->klass->scan_tree) return;
997 alertpanel_full(_("Rebuild folder tree"),
998 _("Rebuilding the folder tree will remove "
999 "local caches. Do you want to continue?"),
1000 GTK_STOCK_NO, GTK_STOCK_YES, NULL, FALSE,
1001 NULL, ALERT_WARNING, G_ALERTDEFAULT)
1002 != G_ALERTALTERNATE) {
1008 window = label_window_create(_("Rebuilding folder tree..."));
1010 window = label_window_create(_("Scanning folder tree..."));
1012 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1013 folder_scan_tree(folder, rebuild);
1014 folder_set_ui_func(folder, NULL, NULL);
1016 folderview_set_all();
1018 gtk_widget_destroy(window);
1022 /** folderview_check_new()
1023 * Scan and update the folder and return the
1024 * count the number of new messages since last check.
1025 * \param folder the folder to check for new messages
1026 * \return the number of new messages since last check
1028 gint folderview_check_new(Folder *folder)
1032 FolderView *folderview;
1036 gint former_new_msgs = 0;
1037 gint former_new = 0, former_unread = 0, former_total;
1039 for (list = folderview_list; list != NULL; list = list->next) {
1040 folderview = (FolderView *)list->data;
1041 ctree = GTK_CTREE(folderview->ctree);
1044 main_window_lock(folderview->mainwin);
1046 for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1047 node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
1049 item = gtk_ctree_node_get_row_data(ctree, node);
1050 if (!item || !item->path || !item->folder) continue;
1051 if (item->no_select) continue;
1052 if (folder && folder != item->folder) continue;
1053 if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
1054 if (!item->prefs->newmailcheck) continue;
1055 if (item->processing_pending == TRUE) {
1056 debug_print("skipping %s, processing pending\n",
1057 item->path ? item->path : item->name);
1061 str = get_scan_str(item);
1063 STATUSBAR_PUSH(folderview->mainwin, str);
1067 folderview_scan_tree_func(item->folder, item, NULL);
1068 former_new = item->new_msgs;
1069 former_unread = item->unread_msgs;
1070 former_total = item->total_msgs;
1072 if (item->folder->klass->scan_required &&
1073 (item->folder->klass->scan_required(item->folder, item) ||
1074 item->folder->inbox == item ||
1075 item->opened == TRUE ||
1076 item->processing_pending == TRUE)) {
1077 if (folder_item_scan(item) < 0) {
1078 summaryview_unlock(folderview->summaryview, item);
1079 if (folder && !FOLDER_IS_LOCAL(folder)) {
1080 STATUSBAR_POP(folderview->mainwin);
1084 } else if (!item->folder->klass->scan_required) {
1085 if (folder_item_scan(item) < 0) {
1086 summaryview_unlock(folderview->summaryview, item);
1087 if (folder && !FOLDER_IS_LOCAL(folder)) {
1088 STATUSBAR_POP(folderview->mainwin);
1093 if (former_new != item->new_msgs ||
1094 former_unread != item->unread_msgs ||
1095 former_total != item->total_msgs)
1096 folderview_update_node(folderview, node);
1098 new_msgs += item->new_msgs;
1099 former_new_msgs += former_new;
1100 STATUSBAR_POP(folderview->mainwin);
1103 main_window_unlock(folderview->mainwin);
1107 folder_write_list();
1108 /* Number of new messages since last check is the just the difference
1109 * between former_new_msgs and new_msgs. If new_msgs is less than
1110 * former_new_msgs, that would mean another session accessed the folder
1111 * and the result is not well defined.
1113 new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
1117 void folderview_check_new_all(void)
1121 FolderView *folderview;
1123 folderview = (FolderView *)folderview_list->data;
1126 main_window_lock(folderview->mainwin);
1127 window = label_window_create
1128 (_("Checking for new messages in all folders..."));
1130 list = folder_get_list();
1131 for (; list != NULL; list = list->next) {
1132 Folder *folder = list->data;
1134 folderview_check_new(folder);
1137 folder_write_list();
1138 folderview_set_all();
1140 gtk_widget_destroy(window);
1141 main_window_unlock(folderview->mainwin);
1145 static gboolean folderview_have_new_children_sub(FolderView *folderview,
1151 if (!item || !item->folder || !item->folder->node)
1154 node = item->folder->node;
1156 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1157 node = node->children;
1160 (item->new_msgs > 0 ||
1161 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1165 while (node != NULL) {
1166 if (node && node->data) {
1167 FolderItem *next_item = (FolderItem*) node->data;
1169 if (folderview_have_new_children_sub(folderview,
1178 static gboolean folderview_have_new_children(FolderView *folderview,
1181 return folderview_have_new_children_sub(folderview, item, FALSE);
1184 static gboolean folderview_have_unread_children_sub(FolderView *folderview,
1190 if (!item || !item->folder || !item->folder->node)
1193 node = item->folder->node;
1195 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1196 node = node->children;
1199 (item->unread_msgs > 0 ||
1200 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1204 while (node != NULL) {
1205 if (node && node->data) {
1206 FolderItem *next_item = (FolderItem*) node->data;
1208 if (folderview_have_unread_children_sub(folderview,
1218 static gboolean folderview_have_unread_children(FolderView *folderview,
1221 return folderview_have_unread_children_sub(folderview, item, FALSE);
1224 static gboolean folderview_have_matching_children_sub(FolderView *folderview,
1230 if (!item || !item->folder || !item->folder->node)
1233 node = item->folder->node;
1235 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1236 node = node->children;
1238 if (in_sub && item->search_match){
1242 while (node != NULL) {
1243 if (node && node->data) {
1244 FolderItem *next_item = (FolderItem*) node->data;
1246 if (folderview_have_matching_children_sub(folderview,
1256 static gboolean folderview_have_matching_children(FolderView *folderview,
1259 return folderview_have_matching_children_sub(folderview, item, FALSE);
1262 static gboolean folderview_have_marked_children_sub(FolderView *folderview,
1268 if (!item || !item->folder || !item->folder->node)
1271 node = item->folder->node;
1273 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1274 node = node->children;
1276 if (item->marked_msgs != 0) {
1280 while (node != NULL) {
1281 if (node && node->data) {
1282 FolderItem *next_item = (FolderItem*) node->data;
1284 if (folderview_have_marked_children_sub(folderview,
1293 static gboolean folderview_have_marked_children(FolderView *folderview,
1296 return folderview_have_marked_children_sub(folderview, item, FALSE);
1299 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
1301 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1302 GtkStyle *style = NULL;
1303 GtkStyle *color_style = NULL;
1305 GdkPixmap *xpm, *openxpm;
1306 GdkBitmap *mask, *openmask;
1307 static GdkPixmap *searchicon;
1308 static GdkBitmap *searchmask;
1309 gboolean mark = FALSE;
1312 gboolean add_unread_mark;
1313 gboolean add_sub_match_mark;
1314 gboolean use_bold, use_color;
1315 gint *col_pos = folderview->col_pos;
1316 SpecialFolderItemType stype;
1318 item = gtk_ctree_node_get_row_data(ctree, node);
1319 g_return_if_fail(item != NULL);
1321 if (!GTK_CTREE_ROW(node)->expanded)
1322 mark = folderview_have_marked_children(folderview, item);
1324 mark = (item->marked_msgs != 0);
1326 stype = item->stype;
1327 if (stype == F_NORMAL) {
1328 if (folder_has_parent_of_type(item, F_TRASH))
1330 else if (folder_has_parent_of_type(item, F_DRAFT))
1332 else if (folder_has_parent_of_type(item, F_OUTBOX))
1334 else if (folder_has_parent_of_type(item, F_QUEUE))
1339 if (item->hide_read_msgs) {
1340 xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
1341 mask = mark?m_inboxhrmxpmmask:inboxhrmxpmmask;
1342 openxpm = mark?m_inboxopenhrmxpm:inboxopenhrmxpm;
1343 openmask = mark?m_inboxopenhrmxpmmask:inboxopenhrmxpmmask;
1345 xpm = mark?m_inboxxpm:inboxxpm;
1346 mask = mark?m_inboxxpmmask:inboxxpmmask;
1347 openxpm = mark?m_inboxopenxpm:inboxopenxpm;
1348 openmask = mark?m_inboxopenxpmmask:inboxopenxpmmask;
1352 if (item->hide_read_msgs) {
1353 xpm = mark?m_outboxhrmxpm:outboxhrmxpm;
1354 mask = mark?m_outboxhrmxpmmask:outboxhrmxpmmask;
1355 openxpm = mark?m_outboxopenhrmxpm:outboxopenhrmxpm;
1356 openmask = mark?m_outboxopenhrmxpmmask:outboxopenhrmxpmmask;
1358 xpm = mark?m_outboxxpm:outboxxpm;
1359 mask = mark?m_outboxxpmmask:outboxxpmmask;
1360 openxpm = mark?m_outboxopenxpm:outboxopenxpm;
1361 openmask = mark?m_outboxopenxpmmask:outboxopenxpmmask;
1365 if (item->hide_read_msgs) {
1366 xpm = mark?m_queuehrmxpm:queuehrmxpm;
1367 mask = mark?m_queuehrmxpmmask:queuehrmxpmmask;
1368 openxpm = mark?m_queueopenhrmxpm:queueopenhrmxpm;
1369 openmask = mark?m_queueopenhrmxpmmask:queueopenhrmxpmmask;
1371 xpm = mark?m_queuexpm:queuexpm;
1372 mask = mark?m_queuexpmmask:queuexpmmask;
1373 openxpm = mark?m_queueopenxpm:queueopenxpm;
1374 openmask = mark?m_queueopenxpmmask:queueopenxpmmask;
1378 if (item->hide_read_msgs) {
1379 xpm = mark?m_trashhrmxpm:trashhrmxpm;
1380 mask = mark?m_trashhrmxpmmask:trashhrmxpmmask;
1381 openxpm = mark?m_trashopenhrmxpm:trashopenhrmxpm;
1382 openmask = mark?m_trashopenhrmxpmmask:trashopenhrmxpmmask;
1384 xpm = mark?m_trashxpm:trashxpm;
1385 mask = mark?m_trashxpmmask:trashxpmmask;
1386 openxpm = mark?m_trashopenxpm:trashopenxpm;
1387 openmask = mark?m_trashopenxpmmask:trashopenxpmmask;
1391 xpm = mark?m_draftsxpm:draftsxpm;
1392 mask = mark?m_draftsxpmmask:draftsxpmmask;
1393 openxpm = mark?m_draftsopenxpm:draftsopenxpm;
1394 openmask = mark?m_draftsopenxpmmask:draftsopenxpmmask;
1397 if (item->hide_read_msgs) {
1398 xpm = mark?m_folderhrmxpm:folderhrmxpm;
1399 mask = mark?m_folderhrmxpmmask:folderhrmxpmmask;
1400 openxpm = mark?m_folderopenhrmxpm:folderopenhrmxpm;
1401 openmask = mark?m_folderopenhrmxpmmask:folderopenhrmxpmmask;
1403 xpm = mark?m_folderxpm:folderxpm;
1404 mask = mark?m_folderxpmmask:folderxpmmask;
1405 openxpm = mark?m_folderopenxpm:folderopenxpm;
1406 openmask = mark?m_folderopenxpmmask:folderopenxpmmask;
1410 if (item->no_select) {
1411 xpm = openxpm = noselectxpm;
1412 mask = openmask = noselectxpmmask;
1415 name = folder_item_get_name(item);
1417 if (!GTK_CTREE_ROW(node)->expanded) {
1418 add_unread_mark = folderview_have_unread_children(
1420 add_sub_match_mark = folderview_have_matching_children(
1423 add_unread_mark = FALSE;
1424 add_sub_match_mark = FALSE;
1427 if (item->search_match) {
1429 stock_pixmap_gdk(folderview->ctree, STOCK_PIXMAP_QUICKSEARCH,
1430 &searchicon, &searchmask);
1432 xpm = openxpm = searchicon;
1433 mask = openmask = searchmask;
1436 if (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0 &&
1437 prefs_common.display_folder_unread) {
1438 str = g_strdup_printf("%s (%d%s)", name, item->total_msgs,
1439 add_unread_mark ? "+" : "");
1440 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1441 xpm, mask, openxpm, openmask,
1442 FALSE, GTK_CTREE_ROW(node)->expanded);
1444 } else if (((item->unread_msgs > 0 || add_unread_mark) &&
1445 prefs_common.display_folder_unread)
1446 || add_sub_match_mark) {
1448 if (item->unread_msgs > 0)
1449 str = g_strdup_printf("%s (%d%s%s)", name, item->unread_msgs,
1450 add_unread_mark || add_sub_match_mark ? "+" : "",
1451 item->unreadmarked_msgs > 0 ? "!":"");
1453 str = g_strdup_printf("%s (+)", name);
1454 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1455 xpm, mask, openxpm, openmask,
1456 FALSE, GTK_CTREE_ROW(node)->expanded);
1459 str = g_strdup_printf("%s%s", name,
1460 item->unreadmarked_msgs > 0 ? " (!)":"");
1462 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1463 xpm, mask, openxpm, openmask,
1464 FALSE, GTK_CTREE_ROW(node)->expanded);
1469 if (!folder_item_parent(item)) {
1470 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], "-");
1471 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
1472 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], "-");
1474 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], itos(item->new_msgs));
1475 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], itos(item->unread_msgs));
1476 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], itos(item->total_msgs));
1479 if (folder_has_parent_of_type(item, F_OUTBOX) ||
1480 folder_has_parent_of_type(item, F_DRAFT) ||
1481 folder_has_parent_of_type(item, F_TRASH)) {
1482 use_bold = use_color = FALSE;
1483 } else if (folder_has_parent_of_type(item, F_QUEUE)) {
1484 /* highlight queue folder if there are any messages */
1485 use_bold = use_color = (item->total_msgs > 0);
1487 /* if unread messages exist, print with bold font */
1488 use_bold = (item->unread_msgs > 0|| item->new_msgs > 0)
1490 /* if new messages exist, print with colored letter */
1492 (item->new_msgs > 0) ||
1494 folderview_have_new_children(folderview, item));
1497 gtk_ctree_node_set_foreground(ctree, node, NULL);
1502 if (item->prefs->color > 0 && !use_color) {
1503 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1504 color_style = gtk_style_copy(bold_style);
1505 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1506 style = color_style;
1507 } else if (use_color) {
1508 style = bold_color_style;
1511 if (item->op_count > 0) {
1512 style = bold_tgtfold_style;
1514 } else if (use_color) {
1515 style = normal_color_style;
1516 gtk_ctree_node_set_foreground(ctree, node,
1517 &folderview->color_new);
1518 } else if (item->op_count > 0) {
1519 style = bold_tgtfold_style;
1520 } else if (item->prefs->color > 0) {
1522 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1523 color_style = gtk_style_copy(normal_style);
1524 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1525 style = color_style;
1527 style = normal_style;
1530 gtk_ctree_node_set_row_style(ctree, node, style);
1532 if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1533 folderview_update_node(folderview, node);
1536 #if !CLAWS /* keep it here for syncs */
1537 void folderview_update_item(FolderItem *item, gboolean update_summary)
1540 FolderView *folderview;
1544 g_return_if_fail(item != NULL);
1546 for (list = folderview_list; list != NULL; list = list->next) {
1547 folderview = (FolderView *)list->data;
1548 ctree = GTK_CTREE(folderview->ctree);
1550 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1552 folderview_update_node(folderview, node);
1553 if (update_summary && folderview->opened == node)
1554 summary_show(folderview->summaryview,
1561 void folderview_update_search_icon(FolderItem *item, gboolean matches)
1564 FolderView *folderview;
1568 g_return_if_fail(item != NULL);
1570 for (list = folderview_list; list != NULL; list = list->next) {
1571 folderview = (FolderView *)list->data;
1572 ctree = GTK_CTREE(folderview->ctree);
1574 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1576 item->search_match = matches;
1577 folderview_update_node(folderview, node);
1582 gboolean folderview_update_item_claws(gpointer source, gpointer data)
1584 FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1585 FolderView *folderview = (FolderView *)data;
1588 g_return_val_if_fail(update_info != NULL, TRUE);
1589 g_return_val_if_fail(update_info->item != NULL, TRUE);
1590 g_return_val_if_fail(folderview != NULL, FALSE);
1592 ctree = GTK_CTREE(folderview->ctree);
1594 node = gtk_ctree_find_by_row_data(ctree, NULL, update_info->item);
1596 if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
1597 folderview_update_node(folderview, node);
1598 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) && (folderview->opened == node))
1599 summary_show(folderview->summaryview, update_info->item);
1605 static void folderview_update_item_foreach_func(gpointer key, gpointer val,
1608 /* CLAWS: share this joy with other hook functions ... */
1609 folder_item_update((FolderItem *)key,
1610 (FolderItemUpdateFlags)GPOINTER_TO_INT(data));
1613 void folderview_update_item_foreach(GHashTable *table, gboolean update_summary)
1616 FolderItemUpdateFlags flags;
1618 flags = update_summary ? F_ITEM_UPDATE_CONTENT | F_ITEM_UPDATE_MSGCNT
1620 for (list = folderview_list; list != NULL; list = list->next)
1621 g_hash_table_foreach(table, folderview_update_item_foreach_func,
1622 GINT_TO_POINTER(flags));
1625 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1626 GNode *gnode, GtkCTreeNode *cnode,
1629 FolderView *folderview = (FolderView *)data;
1630 FolderItem *item = FOLDER_ITEM(gnode->data);
1632 g_return_val_if_fail(item != NULL, FALSE);
1634 gtk_ctree_node_set_row_data(ctree, cnode, item);
1635 folderview_update_node(folderview, cnode);
1640 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1643 FolderView *folderview = (FolderView *)data;
1646 if (GTK_CTREE_ROW(node)->children) {
1647 item = gtk_ctree_node_get_row_data(ctree, node);
1648 g_return_if_fail(item != NULL);
1650 if (!item->collapsed)
1651 gtk_ctree_expand(ctree, node);
1653 folderview_update_node(folderview, node);
1657 static void set_special_folder(GtkCTree *ctree, FolderItem *item,
1658 GtkCTreeNode *root, GtkCTreeNode **prev)
1661 GtkCTreeNode *node, *parent, *sibling;
1663 node = gtk_ctree_find_by_row_data(ctree, root, item);
1665 g_warning("%s not found.\n", item->path);
1667 parent = GTK_CTREE_ROW(node)->parent;
1668 if (*prev && parent == GTK_CTREE_ROW(*prev)->parent)
1669 sibling = GTK_CTREE_ROW(*prev)->sibling;
1671 sibling = GTK_CTREE_ROW(parent)->children;
1675 tmp = gtk_ctree_node_get_row_data
1677 if (tmp->stype != F_NORMAL)
1678 sibling = GTK_CTREE_ROW(sibling)->sibling;
1682 if (node != sibling)
1683 gtk_ctree_move(ctree, node, parent, sibling);
1690 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1693 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1694 GtkCTreeNode *prev = NULL;
1696 gtk_sctree_sort_recursive(ctree, root);
1698 if (root && GTK_CTREE_ROW(root)->parent) return;
1700 set_special_folder(ctree, folder->inbox, root, &prev);
1701 set_special_folder(ctree, folder->outbox, root, &prev);
1702 set_special_folder(ctree, folder->draft, root, &prev);
1703 set_special_folder(ctree, folder->queue, root, &prev);
1704 set_special_folder(ctree, folder->trash, root, &prev);
1707 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1709 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1712 g_return_if_fail(folder != NULL);
1714 root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
1715 folderview_gnode_func, folderview);
1716 gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1718 folderview_sort_folders(folderview, root, folder);
1721 /* callback functions */
1723 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1724 FolderView *folderview)
1726 GtkCList *clist = GTK_CLIST(ctree);
1727 gint prev_row = -1, row = -1, column = -1;
1730 FolderViewPopup *fpopup;
1731 GtkItemFactory *fpopup_factory;
1733 FolderItem *special_trash = NULL, *special_queue = NULL;
1736 if (!event) return FALSE;
1738 if (event->button == 1 || event->button == 2) {
1739 folderview->open_folder = TRUE;
1741 if (event->type == GDK_2BUTTON_PRESS) {
1742 if (clist->selection) {
1745 node = GTK_CTREE_NODE(clist->selection->data);
1747 gtk_ctree_toggle_expansion(
1755 if (event->button == 2 || event->button == 3) {
1757 if (clist->selection) {
1760 node = GTK_CTREE_NODE(clist->selection->data);
1762 prev_row = gtkut_ctree_get_nth_from_node
1763 (GTK_CTREE(ctree), node);
1766 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1769 if (prev_row != row) {
1770 gtk_clist_unselect_all(clist);
1771 if (event->button == 2)
1772 folderview_select_node
1774 gtk_ctree_node_nth(GTK_CTREE(ctree),
1777 gtk_clist_select_row(clist, row, column);
1781 if (event->button != 3) return FALSE;
1783 item = gtk_clist_get_row_data(clist, row);
1784 g_return_val_if_fail(item != NULL, FALSE);
1785 g_return_val_if_fail(item->folder != NULL, FALSE);
1786 folder = item->folder;
1788 fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1790 fpopup_factory = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1792 fpopup = g_hash_table_lookup(folderview_popups, "common");
1793 fpopup_factory = g_hash_table_lookup(folderview->popups, "common");
1796 if (fpopup->set_sensitivity != NULL)
1797 fpopup->set_sensitivity(fpopup_factory, item);
1799 if (NULL != (ac = account_find_from_item(item))) {
1800 special_trash = account_get_special_folder(ac, F_TRASH);
1801 special_queue = account_get_special_folder(ac, F_QUEUE);
1804 if ((item == folder->trash || item == special_trash
1805 || folder_has_parent_of_type(item, F_TRASH)) &&
1806 gtk_item_factory_get_item(fpopup_factory, "/Empty trash...") == NULL) {
1807 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[0], folderview, 1);
1808 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[1], folderview, 1);
1809 } else if (item != folder->trash && (special_trash == NULL || item != special_trash)
1810 && !folder_has_parent_of_type(item, F_TRASH)) {
1811 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[0]);
1812 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[1]);
1815 if ((item == folder->queue || item == special_queue
1816 || folder_has_parent_of_type(item, F_QUEUE)) &&
1817 gtk_item_factory_get_item(fpopup_factory, "/Send queue...") == NULL) {
1818 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[0], folderview, 1);
1819 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[1], folderview, 1);
1820 } else if (item != folder->queue && (special_queue == NULL || item != special_queue)
1821 && !folder_has_parent_of_type(item, F_QUEUE)) {
1822 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[0]);
1823 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[1]);
1826 #define SET_SENS(name, sens) \
1827 menu_set_sensitive(fpopup_factory, name, sens)
1829 SET_SENS("/Mark all read", item->unread_msgs >= 1);
1830 SET_SENS("/Search folder...", item->total_msgs >= 1 &&
1831 folderview->selected == folderview->opened);
1832 SET_SENS("/Properties...", TRUE);
1833 SET_SENS("/Processing...", item->node->parent != NULL);
1834 if (item == folder->trash || item == special_trash
1835 || folder_has_parent_of_type(item, F_TRASH)) {
1836 GSList *msglist = folder_item_get_msg_list(item);
1837 SET_SENS("/Empty trash...", msglist != NULL);
1838 procmsg_msg_list_free(msglist);
1840 if (item == folder->queue || item == special_queue
1841 || folder_has_parent_of_type(item, F_QUEUE)) {
1842 GSList *msglist = folder_item_get_msg_list(item);
1843 SET_SENS("/Send queue...", msglist != NULL);
1844 procmsg_msg_list_free(msglist);
1848 popup = gtk_item_factory_get_widget(fpopup_factory, fpopup->path);
1849 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1850 event->button, event->time);
1855 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1856 FolderView *folderview)
1858 if (!event) return FALSE;
1860 if (event->button == 1 && folderview->open_folder == FALSE &&
1861 folderview->opened != NULL) {
1862 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1863 folderview->opened);
1864 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1870 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1871 FolderView *folderview)
1873 if (!event) return FALSE;
1875 if (quicksearch_has_focus(folderview->summaryview->quicksearch))
1878 switch (event->keyval) {
1880 if (folderview->selected) {
1881 folderview_select_node(folderview,
1882 folderview->selected);
1886 if (folderview->selected) {
1887 if (folderview->opened == folderview->selected &&
1888 (!folderview->summaryview->folder_item ||
1889 folderview->summaryview->folder_item->total_msgs == 0))
1890 folderview_select_next_unread(folderview);
1892 folderview_select_node(folderview,
1893 folderview->selected);
1903 typedef struct _PostponedSelectData
1908 FolderView *folderview;
1909 } PostponedSelectData;
1911 static gboolean postpone_select(void *data)
1913 PostponedSelectData *psdata = (PostponedSelectData *)data;
1914 debug_print("trying again\n");
1915 psdata->folderview->open_folder = TRUE;
1916 main_window_cursor_normal(psdata->folderview->mainwin);
1917 STATUSBAR_POP(psdata->folderview->mainwin);
1918 folderview_selected(psdata->ctree, psdata->row,
1919 psdata->column, psdata->folderview);
1924 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
1925 gint column, FolderView *folderview)
1927 static gboolean can_select = TRUE; /* exclusive lock */
1933 folderview->selected = row;
1935 if (folderview->opened == row) {
1936 folderview->open_folder = FALSE;
1940 if (!can_select || summary_is_locked(folderview->summaryview)) {
1941 if (folderview->opened) {
1942 gtkut_ctree_set_focus_row(ctree, folderview->opened);
1943 gtk_ctree_select(ctree, folderview->opened);
1948 if (!folderview->open_folder) return;
1950 item = gtk_ctree_node_get_row_data(ctree, row);
1951 if (!item || item->no_select) return;
1955 /* Save cache for old folder */
1956 /* We don't want to lose all caches if sylpheed crashed */
1957 if (folderview->opened) {
1958 FolderItem *olditem;
1960 olditem = gtk_ctree_node_get_row_data(ctree, folderview->opened);
1962 /* will be null if we just moved the previously opened folder */
1963 summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
1964 summary_show(folderview->summaryview, NULL);
1965 folder_item_close(olditem);
1969 /* CLAWS: set compose button type: news folder items
1970 * always have a news folder as parent */
1972 toolbar_set_compose_button
1973 (folderview->mainwin->toolbar,
1974 FOLDER_TYPE(item->folder) == F_NEWS ?
1975 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
1978 debug_print("Folder %s is selected\n", item->path);
1980 if (!GTK_CTREE_ROW(row)->children)
1981 gtk_ctree_expand(ctree, row);
1982 if (folderview->opened &&
1983 !GTK_CTREE_ROW(folderview->opened)->children)
1984 gtk_ctree_collapse(ctree, folderview->opened);
1986 /* ungrab the mouse event */
1987 if (GTK_WIDGET_HAS_GRAB(ctree)) {
1988 gtk_grab_remove(GTK_WIDGET(ctree));
1989 if (gdk_pointer_is_grabbed())
1990 gdk_pointer_ungrab(GDK_CURRENT_TIME);
1994 buf = g_strdup_printf(_("Opening Folder %s..."), item->path ?
1995 item->path : "(null)");
1996 debug_print("%s\n", buf);
1997 STATUSBAR_PUSH(folderview->mainwin, buf);
2000 main_window_cursor_wait(folderview->mainwin);
2002 res = folder_item_open(item);
2004 main_window_cursor_normal(folderview->mainwin);
2005 STATUSBAR_POP(folderview->mainwin);
2007 alertpanel_error(_("Folder could not be opened."));
2009 folderview->open_folder = FALSE;
2013 } else if (res == -2) {
2014 PostponedSelectData *data = g_new0(PostponedSelectData, 1);
2015 data->ctree = ctree;
2017 data->column = column;
2018 data->folderview = folderview;
2019 debug_print("postponing open of %s till end of scan\n",
2020 item->path ? item->path:item->name);
2021 folderview->open_folder = FALSE;
2023 g_timeout_add(500, postpone_select, data);
2027 main_window_cursor_normal(folderview->mainwin);
2030 summary_set_prefs_from_folderitem(folderview->summaryview, item);
2031 opened = summary_show(folderview->summaryview, item);
2033 folder_clean_cache_memory(item);
2036 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2037 gtk_ctree_select(ctree, folderview->opened);
2039 folderview->opened = row;
2040 if (gtk_ctree_node_is_visible(ctree, row)
2041 != GTK_VISIBILITY_FULL)
2042 gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0);
2045 STATUSBAR_POP(folderview->mainwin);
2047 folderview->open_folder = FALSE;
2051 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
2052 FolderView *folderview)
2056 item = gtk_ctree_node_get_row_data(ctree, node);
2057 g_return_if_fail(item != NULL);
2058 item->collapsed = FALSE;
2059 folderview_update_node(folderview, node);
2062 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
2063 FolderView *folderview)
2067 item = gtk_ctree_node_get_row_data(ctree, node);
2068 g_return_if_fail(item != NULL);
2069 item->collapsed = TRUE;
2070 folderview_update_node(folderview, node);
2073 static void folderview_popup_close(GtkMenuShell *menu_shell,
2074 FolderView *folderview)
2076 if (!folderview->opened) return;
2078 gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
2081 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
2082 FolderView *folderview)
2084 FolderColumnType type = folderview->col_state[column].type;
2086 prefs_common.folder_col_size[type] = width;
2089 void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item)
2093 folderview_create_folder_node(folderview, item);
2095 if (!item || !item->folder || !item->folder->node)
2098 srcnode = item->folder->node;
2099 srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item);
2100 srcnode = srcnode->children;
2101 while (srcnode != NULL) {
2102 if (srcnode && srcnode->data) {
2103 FolderItem *next_item = (FolderItem*) srcnode->data;
2104 folderview_create_folder_node_recursive(folderview, next_item);
2106 srcnode = srcnode->next;
2110 void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
2112 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2113 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2114 GtkCTreeNode *node, *parent_node;
2115 gint *col_pos = folderview->col_pos;
2116 FolderItemUpdateData hookdata;
2118 parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
2119 if (parent_node == NULL)
2122 gtk_clist_freeze(GTK_CLIST(ctree));
2124 text[col_pos[F_COL_FOLDER]] = item->name;
2125 node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
2127 folderxpm, folderxpmmask,
2128 folderopenxpm, folderopenxpmmask,
2130 gtk_ctree_expand(ctree, parent_node);
2131 gtk_ctree_node_set_row_data(ctree, node, item);
2133 gtk_ctree_node_set_row_style(ctree, node, normal_style);
2134 folderview_sort_folders(folderview, parent_node, item->folder);
2136 hookdata.item = item;
2137 hookdata.update_flags = F_ITEM_UPDATE_NAME;
2138 hookdata.msg = NULL;
2139 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
2141 gtk_clist_thaw(GTK_CLIST(ctree));
2144 static void folderview_empty_trash_cb(FolderView *folderview, guint action,
2147 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2149 GSList *mlist = NULL;
2151 FolderItem *special_trash = NULL;
2154 if (!folderview->selected) return;
2155 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2156 g_return_if_fail(item != NULL);
2157 g_return_if_fail(item->folder != NULL);
2159 if (NULL != (ac = account_find_from_item(item)))
2160 special_trash = account_get_special_folder(ac, F_TRASH);
2162 if (item != item->folder->trash && item != special_trash
2163 && !folder_has_parent_of_type(item, F_TRASH)) return;
2165 if (prefs_common.ask_on_clean) {
2166 if (alertpanel(_("Empty trash"),
2167 _("Delete all messages in trash?"),
2168 GTK_STOCK_CANCEL, _("+_Empty trash"), NULL) != G_ALERTALTERNATE)
2172 mlist = folder_item_get_msg_list(item);
2174 for (cur = mlist ; cur != NULL ; cur = cur->next) {
2175 MsgInfo * msginfo = (MsgInfo *) cur->data;
2176 if (MSG_IS_LOCKED(msginfo->flags))
2178 /* is it partially received? (partial_recv isn't cached) */
2179 if (msginfo->total_size != 0 &&
2180 msginfo->size != (off_t)msginfo->total_size)
2181 partial_mark_for_delete(msginfo);
2183 procmsg_msg_list_free(mlist);
2185 folder_item_remove_all_msg(item);
2188 static void folderview_send_queue_cb(FolderView *folderview, guint action,
2191 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2193 FolderItem *special_queue = NULL;
2195 gchar *errstr = NULL;
2197 if (!folderview->selected) return;
2198 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2199 g_return_if_fail(item != NULL);
2200 g_return_if_fail(item->folder != NULL);
2202 if (NULL != (ac = account_find_from_item(item)))
2203 special_queue = account_get_special_folder(ac, F_QUEUE);
2205 if (item != item->folder->queue && item != special_queue
2206 && !folder_has_parent_of_type(item, F_QUEUE)) return;
2208 if (procmsg_queue_is_empty(item))
2211 if (prefs_common.work_offline)
2212 if (alertpanel(_("Offline warning"),
2213 _("You're working offline. Override?"),
2214 GTK_STOCK_NO, GTK_STOCK_YES,
2215 NULL) != G_ALERTALTERNATE)
2218 /* ask for confirmation before sending queued messages only
2219 in online mode and if there is at least one message queued
2220 in any of the folder queue
2222 if (prefs_common.confirm_send_queued_messages) {
2223 if (!prefs_common.work_offline) {
2224 if (alertpanel(_("Send queued messages"),
2225 _("Send all queued messages?"),
2226 GTK_STOCK_CANCEL, _("_Send"),
2227 NULL) != G_ALERTALTERNATE)
2232 if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
2234 alertpanel_error_log(_("Some errors occurred while "
2235 "sending queued messages."));
2237 gchar *tmp = g_strdup_printf(_("Some errors occurred "
2238 "while sending queued messages:\n%s"), errstr);
2240 alertpanel_error_log(tmp);
2246 static void folderview_search_cb(FolderView *folderview, guint action,
2249 summary_search(folderview->summaryview);
2252 static void folderview_property_cb(FolderView *folderview, guint action,
2255 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2258 if (!folderview->selected) return;
2260 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2261 g_return_if_fail(item != NULL);
2262 g_return_if_fail(item->folder != NULL);
2264 prefs_folder_item_open(item);
2267 static void folderview_recollapse_nodes(FolderView *folderview, GtkCTreeNode *node)
2269 GSList *list = NULL;
2270 GSList *done = NULL;
2271 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2273 for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2274 if (!gtkut_ctree_node_is_parent(GTK_CTREE_NODE(list->data), node)
2275 && list->data != node) {
2276 gtk_ctree_collapse(ctree, GTK_CTREE_NODE(list->data));
2277 done = g_slist_append(done, GTK_CTREE_NODE(list->data));
2280 for (list = done; list != NULL; list = g_slist_next(list)) {
2281 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse,
2287 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
2288 FolderItem *to_folder)
2290 FolderItem *from_parent = NULL;
2291 FolderItem *new_folder = NULL;
2292 GtkCTreeNode *src_node = NULL;
2296 g_return_if_fail(folderview != NULL);
2297 g_return_if_fail(from_folder != NULL);
2298 g_return_if_fail(to_folder != NULL);
2300 src_node = gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), NULL, from_folder);
2301 from_parent = folder_item_parent(from_folder);
2303 if (prefs_common.warn_dnd) {
2304 buf = g_strdup_printf(_("Do you really want to make folder '%s' a "
2305 "sub-folder of '%s' ?"), from_folder->name,
2307 status = alertpanel_full(_("Move folder"), buf,
2308 GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE,
2309 NULL, ALERT_QUESTION, G_ALERTDEFAULT);
2312 if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
2314 else if (status & G_ALERTDISABLE)
2315 prefs_common.warn_dnd = FALSE;
2318 buf = g_strdup_printf(_("Moving %s to %s..."), from_folder->name, to_folder->name);
2319 STATUSBAR_PUSH(folderview->mainwin, buf);
2321 summary_clear_all(folderview->summaryview);
2322 folderview->opened = NULL;
2323 folderview->selected = NULL;
2324 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2326 main_window_cursor_wait(folderview->mainwin);
2327 statusbar_verbosity_set(TRUE);
2328 folder_item_update_freeze();
2329 if ((status = folder_item_move_to(from_folder, to_folder, &new_folder)) == F_MOVE_OK) {
2330 statusbar_verbosity_set(FALSE);
2331 main_window_cursor_normal(folderview->mainwin);
2332 STATUSBAR_POP(folderview->mainwin);
2333 folder_item_update_thaw();
2334 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2336 folderview_sort_folders(folderview,
2337 gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree),
2338 NULL, to_folder), new_folder->folder);
2339 folderview_select(folderview, new_folder);
2341 statusbar_verbosity_set(FALSE);
2342 main_window_cursor_normal(folderview->mainwin);
2343 STATUSBAR_POP(folderview->mainwin);
2344 folder_item_update_thaw();
2346 case F_MOVE_FAILED_DEST_IS_PARENT:
2347 alertpanel_error(_("Source and destination are the same."));
2349 case F_MOVE_FAILED_DEST_IS_CHILD:
2350 alertpanel_error(_("Can't move a folder to one of its children."));
2352 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2353 alertpanel_error(_("Folder moving cannot be done between different mailboxes."));
2356 alertpanel_error(_("Move failed!"));
2361 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2364 static gint folderview_clist_compare(GtkCList *clist,
2365 gconstpointer ptr1, gconstpointer ptr2)
2367 FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
2368 FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
2371 return (item2->name != NULL);
2375 return g_utf8_collate(item1->name, item2->name);
2378 static void folderview_processing_cb(FolderView *folderview, guint action,
2381 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2385 if (!folderview->selected) return;
2387 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2388 g_return_if_fail(item != NULL);
2389 g_return_if_fail(item->folder != NULL);
2391 id = folder_item_get_identifier(item);
2392 title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2395 prefs_filtering_open(&item->prefs->processing, title, NULL, NULL);
2399 void folderview_set_target_folder_color(gint color_op)
2403 FolderView *folderview;
2405 for (list = folderview_list; list != NULL; list = list->next) {
2406 folderview = (FolderView *)list->data;
2407 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2409 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2410 folderview->color_op;
2416 static gchar *last_font = NULL;
2417 void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
2425 void folderview_reflect_prefs(void)
2427 gboolean update_font = TRUE;
2428 FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2429 FolderItem *item = folderview_get_selected_item(folderview);
2430 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2431 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2432 gint height = pos->value;
2434 if (last_font && !strcmp(last_font, NORMAL_FONT))
2435 update_font = FALSE;
2438 last_font = g_strdup(NORMAL_FONT);
2441 normal_style = normal_color_style = bold_style =
2442 bold_color_style = bold_tgtfold_style = NULL;
2444 folderview_init(folderview);
2446 gtk_clist_freeze(GTK_CLIST(folderview->ctree));
2447 folderview_column_set_titles(folderview);
2448 folderview_set_all();
2450 g_signal_handlers_block_by_func
2451 (G_OBJECT(folderview->ctree),
2452 G_CALLBACK(folderview_selected), folderview);
2455 GtkCTreeNode *node = gtk_ctree_find_by_row_data(
2456 GTK_CTREE(folderview->ctree), NULL, item);
2458 folderview_select(folderview, item);
2459 folderview->selected = node;
2462 g_signal_handlers_unblock_by_func
2463 (G_OBJECT(folderview->ctree),
2464 G_CALLBACK(folderview_selected), folderview);
2466 pos = gtk_scrolled_window_get_vadjustment(
2467 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2468 gtk_adjustment_set_value(pos, height);
2469 gtk_clist_thaw(GTK_CLIST(folderview->ctree));
2472 static void drag_state_stop(FolderView *folderview)
2474 if (folderview->drag_timer)
2475 gtk_timeout_remove(folderview->drag_timer);
2476 folderview->drag_timer = 0;
2477 folderview->drag_node = NULL;
2480 static gint folderview_defer_expand(FolderView *folderview)
2482 if (folderview->drag_node) {
2483 folderview_recollapse_nodes(folderview, folderview->drag_node);
2484 if (folderview->drag_item->collapsed) {
2485 gtk_ctree_expand(GTK_CTREE(folderview->ctree), folderview->drag_node);
2486 folderview->nodes_to_recollapse = g_slist_append
2487 (folderview->nodes_to_recollapse, folderview->drag_node);
2490 folderview->drag_item = NULL;
2491 folderview->drag_timer = 0;
2495 static void drag_state_start(FolderView *folderview, GtkCTreeNode *node, FolderItem *item)
2497 /* the idea is that we call drag_state_start() whenever we want expansion to
2498 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2499 * we need to call drag_state_stop() */
2500 drag_state_stop(folderview);
2501 /* request expansion */
2502 if (0 != (folderview->drag_timer = gtk_timeout_add
2503 (prefs_common.hover_timeout,
2504 (GtkFunction)folderview_defer_expand,
2506 folderview->drag_node = node;
2507 folderview->drag_item = item;
2511 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2512 FolderView *folderview)
2514 GdkDragContext *context;
2516 g_return_if_fail(folderview != NULL);
2517 if (folderview->selected == NULL) return;
2518 if (folderview->nodes_to_recollapse)
2519 g_slist_free(folderview->nodes_to_recollapse);
2520 folderview->nodes_to_recollapse = NULL;
2521 context = gtk_drag_begin(widget, folderview->target_list,
2522 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2523 gtk_drag_set_icon_default(context);
2526 static void folderview_drag_data_get(GtkWidget *widget,
2527 GdkDragContext *drag_context,
2528 GtkSelectionData *selection_data,
2531 FolderView *folderview)
2535 gchar *source = NULL;
2536 if (info == TARGET_DUMMY) {
2537 for (cur = GTK_CLIST(folderview->ctree)->selection;
2538 cur != NULL; cur = cur->next) {
2539 item = gtk_ctree_node_get_row_data
2540 (GTK_CTREE(folderview->ctree),
2541 GTK_CTREE_NODE(cur->data));
2543 source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2544 gtk_selection_data_set(selection_data,
2545 selection_data->target, 8,
2546 source, strlen(source));
2552 g_warning("unknown info %d\n", info);
2556 gboolean folderview_update_folder(gpointer source, gpointer userdata)
2558 FolderUpdateData *hookdata;
2559 FolderView *folderview;
2563 folderview = (FolderView *) userdata;
2564 g_return_val_if_fail(hookdata != NULL, FALSE);
2565 g_return_val_if_fail(folderview != NULL, FALSE);
2567 ctree = folderview->ctree;
2568 g_return_val_if_fail(ctree != NULL, FALSE);
2570 if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2571 folderview_create_folder_node(folderview, hookdata->item);
2572 else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2573 GtkCTreeNode *node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree),
2574 NULL, folder_item_parent(hookdata->item));
2575 folderview_sort_folders(folderview, node, hookdata->folder);
2576 } else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2579 node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree), NULL, hookdata->item);
2581 gtk_ctree_remove_node(GTK_CTREE(ctree), node);
2582 } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
2583 folderview_set(folderview);
2588 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2589 GdkDragContext *context,
2593 FolderView *folderview)
2596 FolderItem *item = NULL, *src_item = NULL;
2597 GtkCTreeNode *node = NULL;
2598 gboolean acceptable = FALSE;
2599 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2600 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2601 int height = (int)pos->page_size;
2602 int total_height = (int)pos->upper;
2603 int vpos = (int) pos->value;
2605 if (gtk_clist_get_selection_info
2606 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
2607 GtkWidget *srcwidget;
2609 if (y > height - 24 && height + vpos < total_height)
2610 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
2612 if (y < 48 && y > 0)
2613 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
2615 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2616 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2617 src_item = folderview->summaryview->folder_item;
2619 srcwidget = gtk_drag_get_source_widget(context);
2620 if (srcwidget == folderview->summaryview->ctree) {
2621 /* comes from summaryview */
2622 /* we are copying messages, so only accept folder items that are not
2623 the source item, are no root items and can copy messages */
2624 if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
2625 src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)
2627 } else if (srcwidget == folderview->ctree) {
2628 /* comes from folderview */
2629 /* we are moving folder items, only accept folders that are not
2630 the source items and can copy messages and create folder items */
2631 if (item && item->folder && src_item && src_item != item &&
2632 FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2633 FOLDER_CLASS(item->folder)->create_folder != NULL)
2636 /* comes from another app */
2637 /* we are adding messages, so only accept folder items that are
2638 no root items and can copy messages */
2639 if (item && item->folder && folder_item_parent(item) != NULL
2640 && FOLDER_CLASS(item->folder)->add_msg != NULL)
2645 if (acceptable || (src_item && src_item == item))
2646 drag_state_start(folderview, node, item);
2649 g_signal_handlers_block_by_func
2651 G_CALLBACK(folderview_selected), folderview);
2652 gtk_ctree_select(GTK_CTREE(widget), node);
2653 g_signal_handlers_unblock_by_func
2655 G_CALLBACK(folderview_selected), folderview);
2656 gdk_drag_status(context,
2657 (context->actions == GDK_ACTION_COPY ?
2658 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2660 if (folderview->opened)
2661 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2662 gdk_drag_status(context, 0, time);
2668 static void folderview_drag_leave_cb(GtkWidget *widget,
2669 GdkDragContext *context,
2671 FolderView *folderview)
2673 drag_state_stop(folderview);
2674 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2677 static void free_info (gpointer stuff, gpointer data)
2682 void folderview_finish_dnd(const gchar *data, GdkDragContext *drag_context,
2683 guint time, FolderItem *item)
2686 GSList *msglist = NULL;
2687 list = uri_list_extract_filenames(data);
2688 if (!(item && item->folder && folder_item_parent(item) != NULL
2689 && FOLDER_CLASS(item->folder)->add_msg != NULL))
2691 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2695 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2698 for (tmp = list; tmp != NULL; tmp = tmp->next) {
2699 MsgFileInfo *info = NULL;
2701 if (file_is_email((gchar *)tmp->data)) {
2702 info = g_new0(MsgFileInfo, 1);
2703 info->msginfo = NULL;
2704 info->file = (gchar *)tmp->data;
2705 msglist = g_slist_prepend(msglist, info);
2709 msglist = g_slist_reverse(msglist);
2710 folder_item_add_msgs(item, msglist, FALSE);
2711 g_slist_foreach(msglist, free_info, NULL);
2712 g_slist_free(msglist);
2713 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2715 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2717 list_free_strings(list);
2721 static void folderview_drag_received_cb(GtkWidget *widget,
2722 GdkDragContext *drag_context,
2725 GtkSelectionData *data,
2728 FolderView *folderview)
2731 FolderItem *item = NULL, *src_item;
2734 if (info == TARGET_DUMMY) {
2735 drag_state_stop(folderview);
2736 if ((void *)strstr(data->data, "FROM_OTHER_FOLDER") != (void *)data->data) {
2737 /* comes from summaryview */
2738 if (gtk_clist_get_selection_info
2739 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2742 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2743 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2744 src_item = folderview->summaryview->folder_item;
2746 /* re-check (due to acceptable possibly set for folder moves */
2747 if (!(item && item->folder && item->path && !item->no_select &&
2748 src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) {
2751 if (item && src_item) {
2752 switch (drag_context->action) {
2753 case GDK_ACTION_COPY:
2754 summary_copy_selected_to(folderview->summaryview, item);
2755 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2757 case GDK_ACTION_MOVE:
2758 case GDK_ACTION_DEFAULT:
2760 if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL)
2761 summary_copy_selected_to(folderview->summaryview, item);
2763 summary_move_selected_to(folderview->summaryview, item);
2764 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2767 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2769 /* comes from folderview */
2771 gboolean folder_is_normal = TRUE;
2773 source = data->data + 17;
2774 if (gtk_clist_get_selection_info
2775 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0
2777 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2780 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2781 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2782 src_item = folder_find_item_from_identifier(source);
2786 src_item->stype == F_NORMAL &&
2787 !folder_has_parent_of_type(src_item, F_OUTBOX) &&
2788 !folder_has_parent_of_type(src_item, F_DRAFT) &&
2789 !folder_has_parent_of_type(src_item, F_QUEUE) &&
2790 !folder_has_parent_of_type(src_item, F_TRASH);
2791 if (!item || item->no_select || !src_item
2792 || !folder_is_normal) {
2793 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2797 folderview_move_folder(folderview, src_item, item);
2798 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2800 folderview->nodes_to_recollapse = NULL;
2801 } else if (info == TARGET_MAIL_URI_LIST) {
2802 if (gtk_clist_get_selection_info
2803 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2806 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2808 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2811 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2813 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2816 folderview_finish_dnd(data->data, drag_context, time, item);
2820 static void folderview_drag_end_cb(GtkWidget *widget,
2821 GdkDragContext *drag_context,
2822 FolderView *folderview)
2824 drag_state_stop(folderview);
2825 g_slist_free(folderview->nodes_to_recollapse);
2826 folderview->nodes_to_recollapse = NULL;
2829 void folderview_register_popup(FolderViewPopup *fpopup)
2833 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2834 FolderView *folderview = folderviews->data;
2835 GtkItemFactory *factory;
2837 factory = create_ifactory(folderview, fpopup);
2838 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
2840 g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
2843 void folderview_unregister_popup(FolderViewPopup *fpopup)
2847 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2848 FolderView *folderview = folderviews->data;
2850 g_hash_table_remove(folderview->popups, fpopup->klass);
2852 g_hash_table_remove(folderview_popups, fpopup->klass);