2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include <glib/gi18n.h>
24 #include <gdk/gdkkeysyms.h>
25 #include <gtk/gtkwidget.h>
26 #include <gtk/gtkscrolledwindow.h>
27 #include <gtk/gtkctree.h>
28 #include <gtk/gtkcontainer.h>
29 #include <gtk/gtkclist.h>
30 #include <gtk/gtkstyle.h>
31 #include <gtk/gtksignal.h>
32 #include <gtk/gtkmain.h>
33 #include <gtk/gtkstatusbar.h>
34 #include <gtk/gtkmenu.h>
35 #include <gtk/gtkmenuitem.h>
36 #include <gtk/gtkitemfactory.h>
42 #include "mainwindow.h"
43 #include "folderview.h"
44 #include "summaryview.h"
45 #include "summary_search.h"
46 #include "inputdialog.h"
47 #include "manage_window.h"
48 #include "alertpanel.h"
50 #include "stock_pixmap.h"
54 #include "prefs_common.h"
55 #include "prefs_account.h"
56 #include "prefs_filtering.h"
57 #include "prefs_folder_item.h"
60 #include "foldersel.h"
62 #include "statusbar.h"
64 #include "folderutils.h"
65 #include "partial_download.h"
66 #include "prefs_folder_column.h"
67 #include "filtering.h"
68 #include "quicksearch.h"
73 #define COL_FOLDER_WIDTH 150
74 #define COL_NUM_WIDTH 32
76 static GList *folderview_list = NULL;
78 static GtkStyle *normal_style;
79 static GtkStyle *normal_color_style;
80 static GtkStyle *bold_style;
81 static GtkStyle *bold_color_style;
82 static GtkStyle *bold_tgtfold_style;
84 static GdkPixmap *inboxxpm;
85 static GdkBitmap *inboxxpmmask;
86 static GdkPixmap *inboxhrmxpm;
87 static GdkBitmap *inboxhrmxpmmask;
88 static GdkPixmap *inboxopenxpm;
89 static GdkBitmap *inboxopenxpmmask;
90 static GdkPixmap *inboxopenhrmxpm;
91 static GdkBitmap *inboxopenhrmxpmmask;
92 static GdkPixmap *outboxxpm;
93 static GdkBitmap *outboxxpmmask;
94 static GdkPixmap *outboxhrmxpm;
95 static GdkBitmap *outboxhrmxpmmask;
96 static GdkPixmap *outboxopenxpm;
97 static GdkBitmap *outboxopenxpmmask;
98 static GdkPixmap *outboxopenhrmxpm;
99 static GdkBitmap *outboxopenhrmxpmmask;
100 static GdkPixmap *folderxpm;
101 static GdkBitmap *folderxpmmask;
102 static GdkPixmap *folderhrmxpm;
103 static GdkBitmap *folderhrmxpmmask;
104 static GdkPixmap *folderopenxpm;
105 static GdkBitmap *folderopenxpmmask;
106 static GdkPixmap *folderopenhrmxpm;
107 static GdkBitmap *folderopenhrmxpmmask;
108 static GdkPixmap *trashopenxpm;
109 static GdkBitmap *trashopenxpmmask;
110 static GdkPixmap *trashopenhrmxpm;
111 static GdkBitmap *trashopenhrmxpmmask;
112 static GdkPixmap *trashxpm;
113 static GdkBitmap *trashxpmmask;
114 static GdkPixmap *trashhrmxpm;
115 static GdkBitmap *trashhrmxpmmask;
116 static GdkPixmap *queuexpm;
117 static GdkBitmap *queuexpmmask;
118 static GdkPixmap *queuehrmxpm;
119 static GdkBitmap *queuehrmxpmmask;
120 static GdkPixmap *queueopenxpm;
121 static GdkBitmap *queueopenxpmmask;
122 static GdkPixmap *queueopenhrmxpm;
123 static GdkBitmap *queueopenhrmxpmmask;
124 static GdkPixmap *draftsxpm;
125 static GdkBitmap *draftsxpmmask;
126 static GdkPixmap *draftsopenxpm;
127 static GdkBitmap *draftsopenxpmmask;
128 static GdkPixmap *noselectxpm;
129 static GdkBitmap *noselectxpmmask;
131 static GdkPixmap *m_inboxxpm;
132 static GdkBitmap *m_inboxxpmmask;
133 static GdkPixmap *m_inboxhrmxpm;
134 static GdkBitmap *m_inboxhrmxpmmask;
135 static GdkPixmap *m_inboxopenxpm;
136 static GdkBitmap *m_inboxopenxpmmask;
137 static GdkPixmap *m_inboxopenhrmxpm;
138 static GdkBitmap *m_inboxopenhrmxpmmask;
139 static GdkPixmap *m_outboxxpm;
140 static GdkBitmap *m_outboxxpmmask;
141 static GdkPixmap *m_outboxhrmxpm;
142 static GdkBitmap *m_outboxhrmxpmmask;
143 static GdkPixmap *m_outboxopenxpm;
144 static GdkBitmap *m_outboxopenxpmmask;
145 static GdkPixmap *m_outboxopenhrmxpm;
146 static GdkBitmap *m_outboxopenhrmxpmmask;
147 static GdkPixmap *m_folderxpm;
148 static GdkBitmap *m_folderxpmmask;
149 static GdkPixmap *m_folderhrmxpm;
150 static GdkBitmap *m_folderhrmxpmmask;
151 static GdkPixmap *m_folderopenxpm;
152 static GdkBitmap *m_folderopenxpmmask;
153 static GdkPixmap *m_folderopenhrmxpm;
154 static GdkBitmap *m_folderopenhrmxpmmask;
155 static GdkPixmap *m_trashopenxpm;
156 static GdkBitmap *m_trashopenxpmmask;
157 static GdkPixmap *m_trashopenhrmxpm;
158 static GdkBitmap *m_trashopenhrmxpmmask;
159 static GdkPixmap *m_trashxpm;
160 static GdkBitmap *m_trashxpmmask;
161 static GdkPixmap *m_trashhrmxpm;
162 static GdkBitmap *m_trashhrmxpmmask;
163 static GdkPixmap *m_queuexpm;
164 static GdkBitmap *m_queuexpmmask;
165 static GdkPixmap *m_queuehrmxpm;
166 static GdkBitmap *m_queuehrmxpmmask;
167 static GdkPixmap *m_queueopenxpm;
168 static GdkBitmap *m_queueopenxpmmask;
169 static GdkPixmap *m_queueopenhrmxpm;
170 static GdkBitmap *m_queueopenhrmxpmmask;
171 static GdkPixmap *m_draftsxpm;
172 static GdkBitmap *m_draftsxpmmask;
173 static GdkPixmap *m_draftsopenxpm;
174 static GdkBitmap *m_draftsopenxpmmask;
176 static GdkPixmap *newxpm;
177 static GdkBitmap *newxpmmask;
178 static GdkPixmap *unreadxpm;
179 static GdkBitmap *unreadxpmmask;
180 static GdkPixmap *readxpm;
181 static GdkBitmap *readxpmmask;
184 static void folderview_select_node (FolderView *folderview,
186 static void folderview_set_folders (FolderView *folderview);
187 static void folderview_sort_folders (FolderView *folderview,
190 static void folderview_append_folder (FolderView *folderview,
192 static void folderview_update_node (FolderView *folderview,
195 static gint folderview_clist_compare (GtkCList *clist,
199 /* callback functions */
200 static gboolean folderview_button_pressed (GtkWidget *ctree,
201 GdkEventButton *event,
202 FolderView *folderview);
203 static gboolean folderview_button_released (GtkWidget *ctree,
204 GdkEventButton *event,
205 FolderView *folderview);
206 static gboolean folderview_key_pressed (GtkWidget *widget,
208 FolderView *folderview);
209 static void folderview_selected (GtkCTree *ctree,
212 FolderView *folderview);
213 static void folderview_tree_expanded (GtkCTree *ctree,
215 FolderView *folderview);
216 static void folderview_tree_collapsed (GtkCTree *ctree,
218 FolderView *folderview);
219 static void folderview_popup_close (GtkMenuShell *menu_shell,
220 FolderView *folderview);
221 static void folderview_col_resized (GtkCList *clist,
224 FolderView *folderview);
226 static void mark_all_read_cb (FolderView *folderview,
230 static void folderview_empty_trash_cb (FolderView *folderview,
234 static void folderview_send_queue_cb (FolderView *folderview,
238 static void folderview_search_cb (FolderView *folderview,
242 static void folderview_property_cb (FolderView *folderview,
246 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
247 GdkDragContext *context,
251 FolderView *folderview);
252 static void folderview_drag_leave_cb (GtkWidget *widget,
253 GdkDragContext *context,
255 FolderView *folderview);
256 static void folderview_drag_received_cb (GtkWidget *widget,
257 GdkDragContext *drag_context,
260 GtkSelectionData *data,
263 FolderView *folderview);
264 static void folderview_start_drag (GtkWidget *widget, gint button, GdkEvent *event,
265 FolderView *folderview);
266 static void folderview_drag_data_get (GtkWidget *widget,
267 GdkDragContext *drag_context,
268 GtkSelectionData *selection_data,
271 FolderView *folderview);
272 static void folderview_drag_end_cb (GtkWidget *widget,
273 GdkDragContext *drag_context,
274 FolderView *folderview);
276 void folderview_create_folder_node (FolderView *folderview,
278 gboolean folderview_update_folder (gpointer source,
280 gboolean folderview_update_item_claws (gpointer source,
282 static void folderview_processing_cb(FolderView *folderview, guint action,
284 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
285 GdkEventButton *event);
287 GHashTable *folderview_popups;
289 static GtkItemFactoryEntry folderview_common_popup_entries[] =
291 {N_("/Mark all re_ad"), NULL, mark_all_read_cb, 0, NULL},
292 {"/---", NULL, NULL, 0, "<Separator>"},
293 {N_("/_Search folder..."), NULL, folderview_search_cb, 0, NULL},
294 {N_("/_Properties..."), NULL, folderview_property_cb, 0, NULL},
295 {N_("/Process_ing..."), NULL, folderview_processing_cb, 0, NULL},
298 static GtkItemFactoryEntry folder_view_trash_popup_entries[] = {
299 {"/------trashsep", NULL, NULL, 0, "<Separator>"},
300 {N_("/Empty _trash..."), NULL, folderview_empty_trash_cb, 0, NULL},
303 static GtkItemFactoryEntry folder_view_queue_popup_entries[] = {
304 {"/------queuesep", NULL, NULL, 0, "<Separator>"},
305 {N_("/Send _queue..."), NULL, folderview_send_queue_cb, 0, NULL},
309 GtkTargetEntry folderview_drag_types[] =
311 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY},
312 {"text/uri-list", 0, TARGET_MAIL_URI_LIST}
315 void folderview_initialize(void)
317 FolderViewPopup *fpopup;
319 GSList *entries = NULL;
321 fpopup = g_new0(FolderViewPopup, 1);
323 n_entries = sizeof(folderview_common_popup_entries) /
324 sizeof(folderview_common_popup_entries[0]);
325 for (i = 0; i < n_entries; i++)
326 entries = g_slist_append(entries, &folderview_common_popup_entries[i]);
328 fpopup->klass = "common";
329 fpopup->path = "<CommonFolder>";
330 fpopup->entries = entries;
331 fpopup->set_sensitivity = NULL;
333 folderview_popups = g_hash_table_new(g_str_hash, g_str_equal);
334 g_hash_table_insert(folderview_popups, "common", fpopup);
337 static GtkItemFactory *create_ifactory(FolderView *folderview, FolderViewPopup *fpopup)
340 GtkItemFactory *factory;
341 FolderViewPopup *fpopup_common;
344 factory = gtk_item_factory_new(GTK_TYPE_MENU, fpopup->path, NULL);
345 gtk_item_factory_set_translate_func(factory, menu_translate,
348 for (entries = fpopup->entries; entries != NULL; entries = g_slist_next(entries))
349 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
351 fpopup_common = g_hash_table_lookup(folderview_popups, "common");
352 if (fpopup_common != fpopup)
353 for (entries = fpopup_common->entries; entries != NULL; entries = g_slist_next(entries))
354 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
356 popup = gtk_item_factory_get_widget(factory, fpopup->path);
357 g_signal_connect(G_OBJECT(popup), "selection_done",
358 G_CALLBACK(folderview_popup_close),
364 static void create_ifactories(gpointer key, gpointer value, gpointer data)
366 FolderView *folderview = data;
367 FolderViewPopup *fpopup = value;
368 GtkItemFactory *factory;
370 factory = create_ifactory(folderview, fpopup);
371 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
374 static void folderview_column_set_titles(FolderView *folderview)
376 GtkWidget *ctree = folderview->ctree;
377 GtkWidget *label_new;
378 GtkWidget *label_unread;
379 GtkWidget *label_total;
381 GtkWidget *hbox_unread;
382 GtkWidget *hbox_total;
383 gint *col_pos = folderview->col_pos;
385 debug_print("setting titles...\n");
386 gtk_widget_realize(folderview->ctree);
387 gtk_widget_show_all(folderview->scrolledwin);
389 /* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
390 * instead text (text overflows making them unreadable and ugly) */
391 stock_pixmap_gdk(ctree, STOCK_PIXMAP_NEW,
392 &newxpm, &newxpmmask);
393 stock_pixmap_gdk(ctree, STOCK_PIXMAP_UNREAD,
394 &unreadxpm, &unreadxpmmask);
395 stock_pixmap_gdk(ctree, STOCK_PIXMAP_READ,
396 &readxpm, &readxpmmask);
398 label_new = gtk_image_new_from_pixmap(newxpm, newxpmmask);
399 label_unread = gtk_image_new_from_pixmap(unreadxpm, unreadxpmmask);
400 label_total = gtk_image_new_from_pixmap(readxpm, readxpmmask);
402 gtk_clist_column_titles_active(GTK_CLIST(ctree));
404 hbox_new = gtk_hbox_new(FALSE, 4);
405 hbox_unread = gtk_hbox_new(FALSE, 4);
406 hbox_total = gtk_hbox_new(FALSE, 4);
409 gtk_box_pack_start(GTK_BOX(hbox_new), label_new, TRUE, TRUE, 0);
410 gtk_misc_set_alignment (GTK_MISC (label_new), 1, 0.5);
411 gtk_box_pack_start(GTK_BOX(hbox_unread), label_unread, TRUE, TRUE, 0);
412 gtk_misc_set_alignment (GTK_MISC (label_unread), 1, 0.5);
413 gtk_box_pack_start(GTK_BOX(hbox_total), label_total, TRUE, TRUE, 0);
414 gtk_misc_set_alignment (GTK_MISC (label_total), 1, 0.5);
416 gtk_widget_show_all(hbox_new);
417 gtk_widget_show_all(hbox_unread);
418 gtk_widget_show_all(hbox_total);
420 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_NEW],hbox_new);
421 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_UNREAD],hbox_unread);
422 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_TOTAL],hbox_total);
424 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_NEW], _("New"));
425 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_UNREAD], _("Unread"));
426 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_TOTAL], _("Total"));
429 static gboolean folderview_popup_menu(GtkWidget *widget, gpointer data)
431 FolderView *folderview = (FolderView *)data;
432 GdkEventButton event;
433 if (folderview_get_selected_item(folderview) == NULL)
437 event.time = gtk_get_current_event_time();
439 folderview_set_sens_and_popup_menu(folderview, -1,
446 GtkWidget *folderview_ctree_create(FolderView *folderview)
450 FolderColumnState *col_state;
451 FolderColumnType type;
452 gchar *titles[N_FOLDER_COLS];
454 GtkWidget *scrolledwin = folderview->scrolledwin;
456 debug_print("creating tree...\n");
457 memset(titles, 0, sizeof(titles));
459 col_state = prefs_folder_column_get_config();
460 memset(titles, 0, sizeof(titles));
462 col_pos = folderview->col_pos;
464 for (i = 0; i < N_FOLDER_COLS; i++) {
465 folderview->col_state[i] = col_state[i];
466 type = col_state[i].type;
470 titles[col_pos[F_COL_FOLDER]] = _("Folder");
471 titles[col_pos[F_COL_NEW]] = _("New");
472 titles[col_pos[F_COL_UNREAD]] = _("Unread");
473 /* TRANSLATORS: This in Number sign in American style */
474 titles[col_pos[F_COL_TOTAL]] = _("#");
476 ctree = gtk_sctree_new_with_titles(N_FOLDER_COLS, col_pos[F_COL_FOLDER],
479 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
480 gtk_clist_set_column_justification(GTK_CLIST(ctree), col_pos[F_COL_NEW],
482 gtk_clist_set_column_justification(GTK_CLIST(ctree),
483 col_pos[F_COL_UNREAD],
485 gtk_clist_set_column_justification(GTK_CLIST(ctree),
486 col_pos[F_COL_TOTAL],
488 if (prefs_common.enable_dotted_lines) {
489 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
490 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
491 GTK_CTREE_EXPANDER_SQUARE);
493 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_NONE);
494 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
495 GTK_CTREE_EXPANDER_TRIANGLE);
498 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
499 gtk_sctree_set_recursive_expand(GTK_SCTREE(ctree), FALSE);
501 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
502 gtk_clist_set_compare_func(GTK_CLIST(ctree), folderview_clist_compare);
504 /* don't let title buttons take key focus */
505 for (i = 0; i < N_FOLDER_COLS; i++) {
506 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[i].button,
508 gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[i],
509 prefs_common.folder_col_size[i]);
510 gtk_clist_set_column_visibility
511 (GTK_CLIST(ctree), i, col_state[i].visible);
514 g_signal_connect(G_OBJECT(ctree), "key_press_event",
515 G_CALLBACK(folderview_key_pressed),
517 g_signal_connect(G_OBJECT(ctree), "button_press_event",
518 G_CALLBACK(folderview_button_pressed),
520 g_signal_connect(G_OBJECT(ctree), "popup-menu",
521 G_CALLBACK(folderview_popup_menu), folderview);
522 g_signal_connect(G_OBJECT(ctree), "button_release_event",
523 G_CALLBACK(folderview_button_released),
525 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
526 G_CALLBACK(folderview_selected), folderview);
527 g_signal_connect(G_OBJECT(ctree), "start_drag",
528 G_CALLBACK(folderview_start_drag), folderview);
529 g_signal_connect(G_OBJECT(ctree), "drag_data_get",
530 G_CALLBACK(folderview_drag_data_get),
533 g_signal_connect_after(G_OBJECT(ctree), "tree_expand",
534 G_CALLBACK(folderview_tree_expanded),
536 g_signal_connect_after(G_OBJECT(ctree), "tree_collapse",
537 G_CALLBACK(folderview_tree_collapsed),
540 g_signal_connect(G_OBJECT(ctree), "resize_column",
541 G_CALLBACK(folderview_col_resized),
545 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
546 folderview_drag_types, 2,
547 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
548 g_signal_connect(G_OBJECT(ctree), "drag_motion",
549 G_CALLBACK(folderview_drag_motion_cb),
551 g_signal_connect(G_OBJECT(ctree), "drag_leave",
552 G_CALLBACK(folderview_drag_leave_cb),
554 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
555 G_CALLBACK(folderview_drag_received_cb),
557 g_signal_connect(G_OBJECT(ctree), "drag_end",
558 G_CALLBACK(folderview_drag_end_cb),
561 gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
566 void folderview_set_column_order(FolderView *folderview)
569 FolderItem *item = folderview_get_selected_item(folderview);
570 GtkWidget *scrolledwin = folderview->scrolledwin;
572 debug_print("recreating tree...\n");
573 gtk_widget_destroy(folderview->ctree);
575 folderview->ctree = ctree = folderview_ctree_create(folderview);
576 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
577 GTK_CLIST(ctree)->hadjustment);
578 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
579 GTK_CLIST(ctree)->vadjustment);
580 gtk_widget_show(ctree);
582 folderview_set(folderview);
583 folderview_column_set_titles(folderview);
585 folderview_select(folderview,item);
588 FolderView *folderview_create(void)
590 FolderView *folderview;
591 GtkWidget *scrolledwin;
594 debug_print("Creating folder view...\n");
595 folderview = g_new0(FolderView, 1);
597 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
598 gtk_scrolled_window_set_policy
599 (GTK_SCROLLED_WINDOW(scrolledwin),
600 GTK_POLICY_AUTOMATIC,
601 prefs_common.folderview_vscrollbar_policy);
602 gtk_widget_set_size_request(scrolledwin,
603 prefs_common.folderview_width,
604 prefs_common.folderview_height);
606 folderview->scrolledwin = scrolledwin;
607 ctree = folderview_ctree_create(folderview);
609 /* create popup factories */
610 folderview->popups = g_hash_table_new(g_str_hash, g_str_equal);
611 g_hash_table_foreach(folderview_popups, create_ifactories, folderview);
613 folderview->ctree = ctree;
615 folderview->folder_update_callback_id =
616 hooks_register_hook(FOLDER_UPDATE_HOOKLIST, folderview_update_folder, (gpointer) folderview);
617 folderview->folder_item_update_callback_id =
618 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item_claws, (gpointer) folderview);
620 gtk_widget_show_all(scrolledwin);
622 folderview->target_list = gtk_target_list_new(folderview_drag_types, 2);
623 folderview_list = g_list_append(folderview_list, folderview);
628 void folderview_init(FolderView *folderview)
630 GtkWidget *ctree = folderview->ctree;
633 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE, &inboxxpm, &inboxxpmmask);
634 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM, &inboxhrmxpm, &inboxhrmxpmmask);
635 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN, &inboxopenxpm, &inboxopenxpmmask);
636 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM, &inboxopenhrmxpm, &inboxopenhrmxpmmask);
637 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE, &outboxxpm, &outboxxpmmask);
638 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM, &outboxhrmxpm, &outboxhrmxpmmask);
639 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN, &outboxopenxpm, &outboxopenxpmmask);
640 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM, &outboxopenhrmxpm, &outboxopenhrmxpmmask);
641 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
642 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM, &folderhrmxpm, &folderhrmxpmmask);
643 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
644 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM, &folderopenhrmxpm, &folderopenhrmxpmmask);
645 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN, &trashopenxpm, &trashopenxpmmask);
646 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM, &trashopenhrmxpm, &trashopenhrmxpmmask);
647 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE, &trashxpm, &trashxpmmask);
648 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM, &trashhrmxpm, &trashhrmxpmmask);
649 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE, &queuexpm, &queuexpmmask);
650 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM, &queuehrmxpm, &queuehrmxpmmask);
651 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN, &queueopenxpm, &queueopenxpmmask);
652 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM, &queueopenhrmxpm, &queueopenhrmxpmmask);
653 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE, &draftsxpm, &draftsxpmmask);
654 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN, &draftsopenxpm, &draftsopenxpmmask);
655 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_NOSELECT, &noselectxpm, &noselectxpmmask);
657 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_MARK, &m_inboxxpm, &m_inboxxpmmask);
658 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK, &m_inboxhrmxpm, &m_inboxhrmxpmmask);
659 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_MARK, &m_inboxopenxpm, &m_inboxopenxpmmask);
660 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM_MARK, &m_inboxopenhrmxpm, &m_inboxopenhrmxpmmask);
661 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_MARK, &m_outboxxpm, &m_outboxxpmmask);
662 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK, &m_outboxhrmxpm, &m_outboxhrmxpmmask);
663 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_MARK, &m_outboxopenxpm, &m_outboxopenxpmmask);
664 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK, &m_outboxopenhrmxpm, &m_outboxopenhrmxpmmask);
665 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_MARK, &m_folderxpm, &m_folderxpmmask);
666 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM_MARK, &m_folderhrmxpm, &m_folderhrmxpmmask);
667 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_MARK, &m_folderopenxpm, &m_folderopenxpmmask);
668 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM_MARK, &m_folderopenhrmxpm, &m_folderopenhrmxpmmask);
669 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_MARK, &m_trashopenxpm, &m_trashopenxpmmask);
670 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM_MARK, &m_trashopenhrmxpm, &m_trashopenhrmxpmmask);
671 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_MARK, &m_trashxpm, &m_trashxpmmask);
672 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK, &m_trashhrmxpm, &m_trashhrmxpmmask);
673 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_MARK, &m_queuexpm, &m_queuexpmmask);
674 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK, &m_queuehrmxpm, &m_queuehrmxpmmask);
675 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_MARK, &m_queueopenxpm, &m_queueopenxpmmask);
676 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK, &m_queueopenhrmxpm, &m_queueopenhrmxpmmask);
677 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE_MARK, &m_draftsxpm, &m_draftsxpmmask);
678 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN_MARK, &m_draftsopenxpm, &m_draftsopenxpmmask);
681 PangoFontDescription *font_desc;
682 normal_style = gtk_style_copy(gtk_widget_get_style(ctree));
683 font_desc = pango_font_description_from_string(NORMAL_FONT);
685 if (normal_style->font_desc)
686 pango_font_description_free
687 (normal_style->font_desc);
688 normal_style->font_desc = font_desc;
690 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
691 normal_color_style = gtk_style_copy(normal_style);
692 normal_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
694 gtk_widget_set_style(ctree, normal_style);
698 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
699 bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
700 pango_font_description_set_weight
701 (bold_style->font_desc, PANGO_WEIGHT_BOLD);
702 bold_color_style = gtk_style_copy(bold_style);
703 bold_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
705 bold_tgtfold_style = gtk_style_copy(bold_style);
706 bold_tgtfold_style->fg[GTK_STATE_NORMAL] = folderview->color_op;
710 void folderview_set(FolderView *folderview)
712 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
713 MainWindow *mainwin = folderview->mainwin;
718 debug_print("Setting folder info...\n");
719 STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
721 main_window_cursor_wait(mainwin);
723 folderview->selected = NULL;
724 folderview->opened = NULL;
726 gtk_clist_freeze(GTK_CLIST(ctree));
727 gtk_clist_clear(GTK_CLIST(ctree));
728 gtk_clist_thaw(GTK_CLIST(ctree));
729 gtk_clist_freeze(GTK_CLIST(ctree));
731 folderview_set_folders(folderview);
733 gtk_clist_thaw(GTK_CLIST(ctree));
734 main_window_cursor_normal(mainwin);
735 STATUSBAR_POP(mainwin);
738 void folderview_set_all(void)
742 for (list = folderview_list; list != NULL; list = list->next)
743 folderview_set((FolderView *)list->data);
746 void folderview_select(FolderView *folderview, FolderItem *item)
748 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
750 GtkCTreeNode *old_selected = folderview->selected;
754 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
755 if (node) folderview_select_node(folderview, node);
757 if (old_selected != node)
758 folder_update_op_count();
761 static void mark_all_read_cb(FolderView *folderview, guint action,
767 item = folderview_get_selected_item(folderview);
771 if (folderview->summaryview->folder_item != item
772 && prefs_common.ask_mark_all_read) {
773 val = alertpanel_full(_("Mark all as read"),
774 _("Do you really want to mark all mails in this "
775 "folder as read ?"), GTK_STOCK_NO, GTK_STOCK_YES, NULL,
776 TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT);
778 if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
780 else if (val & G_ALERTDISABLE)
781 prefs_common.ask_mark_all_read = FALSE;
784 summary_lock(folderview->summaryview);
785 folder_item_update_freeze();
786 if (folderview->summaryview->folder_item == item)
787 summary_freeze(folderview->summaryview);
788 folderutils_mark_all_read(item);
789 if (folderview->summaryview->folder_item == item)
790 summary_thaw(folderview->summaryview);
791 folder_item_update_thaw();
792 summary_unlock(folderview->summaryview);
795 static void folderview_select_node(FolderView *folderview, GtkCTreeNode *node)
797 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
799 g_return_if_fail(node != NULL);
801 if (folderview->open_folder) {
805 folderview->open_folder = TRUE;
806 gtkut_ctree_set_focus_row(ctree, node);
807 gtk_ctree_select(ctree, node);
808 if (folderview->summaryview->folder_item &&
809 folderview->summaryview->folder_item->total_msgs > 0)
810 summary_grab_focus(folderview->summaryview);
812 gtk_widget_grab_focus(folderview->ctree);
814 gtkut_ctree_expand_parent_all(ctree, node);
817 void folderview_unselect(FolderView *folderview)
819 if (folderview->opened && !GTK_CTREE_ROW(folderview->opened)->children)
821 (GTK_CTREE(folderview->ctree), folderview->opened);
823 folderview->selected = folderview->opened = NULL;
826 static GtkCTreeNode *folderview_find_next_marked(GtkCTree *ctree,
832 node = gtkut_ctree_node_next(ctree, node);
834 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
836 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
837 item = gtk_ctree_node_get_row_data(ctree, node);
838 if (item && item->marked_msgs > 0 && item->stype != F_TRASH)
845 void folderview_select_next_marked(FolderView *folderview)
847 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
848 GtkCTreeNode *node = NULL;
849 SelectOnEntry last_sel = prefs_common.select_on_entry;
850 gboolean last_open = prefs_common.always_show_msg;
852 prefs_common.select_on_entry = SELECTONENTRY_MNU;
853 prefs_common.always_show_msg = TRUE;
855 if ((node = folderview_find_next_marked(ctree, folderview->opened))
857 folderview_select_node(folderview, node);
861 if (!folderview->opened ||
862 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
865 /* search again from the first node */
866 if ((node = folderview_find_next_marked(ctree, NULL)) != NULL)
867 folderview_select_node(folderview, node);
870 prefs_common.select_on_entry = last_sel;
871 prefs_common.always_show_msg = last_open;
874 static GtkCTreeNode *folderview_find_next_unread(GtkCTree *ctree,
880 node = gtkut_ctree_node_next(ctree, node);
882 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
884 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
885 item = gtk_ctree_node_get_row_data(ctree, node);
886 if (item && item->unread_msgs > 0 && item->stype != F_TRASH)
893 void folderview_select_next_unread(FolderView *folderview, gboolean force_open)
895 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
896 GtkCTreeNode *node = NULL;
897 SelectOnEntry last_sel = prefs_common.select_on_entry;
898 gboolean last_open = prefs_common.always_show_msg;
900 prefs_common.select_on_entry = SELECTONENTRY_UNM;
901 prefs_common.always_show_msg = force_open ? TRUE : last_open;
903 if ((node = folderview_find_next_unread(ctree, folderview->opened))
905 folderview_select_node(folderview, node);
909 if (!folderview->opened ||
910 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
913 /* search again from the first node */
914 if ((node = folderview_find_next_unread(ctree, NULL)) != NULL)
915 folderview_select_node(folderview, node);
918 prefs_common.select_on_entry = last_sel;
919 prefs_common.always_show_msg = last_open;
922 static GtkCTreeNode *folderview_find_next_new(GtkCTree *ctree,
928 node = gtkut_ctree_node_next(ctree, node);
930 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
932 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
933 item = gtk_ctree_node_get_row_data(ctree, node);
934 if (item && item->new_msgs > 0 && item->stype != F_TRASH)
941 void folderview_select_next_new(FolderView *folderview)
943 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
944 GtkCTreeNode *node = NULL;
945 SelectOnEntry last_sel = prefs_common.select_on_entry;
946 gboolean last_open = prefs_common.always_show_msg;
948 prefs_common.select_on_entry = SELECTONENTRY_NUM;
949 prefs_common.always_show_msg = TRUE;
951 if ((node = folderview_find_next_new(ctree, folderview->opened))
953 folderview_select_node(folderview, node);
957 if (!folderview->opened ||
958 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
961 /* search again from the first node */
962 if ((node = folderview_find_next_new(ctree, NULL)) != NULL)
963 folderview_select_node(folderview, node);
966 prefs_common.select_on_entry = last_sel;
967 prefs_common.always_show_msg = last_open;
970 FolderItem *folderview_get_selected_item(FolderView *folderview)
972 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
974 if (!folderview->selected) return NULL;
975 return gtk_ctree_node_get_row_data(ctree, folderview->selected);
978 void folderview_update_msg_num(FolderView *folderview, GtkCTreeNode *row)
980 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
981 static GtkCTreeNode *prev_row = NULL;
983 gint new, unread, total;
984 gchar *new_str, *unread_str, *total_str;
985 gint *col_pos = folderview->col_pos;
989 item = gtk_ctree_node_get_row_data(ctree, row);
992 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_NEW], &new_str);
993 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_UNREAD], &unread_str);
994 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_TOTAL], &total_str);
996 unread = atoi(unread_str);
997 total = atoi(total_str);
1001 folderview_update_node(folderview, row);
1004 void folderview_append_item(FolderItem *item)
1008 g_return_if_fail(item != NULL);
1009 g_return_if_fail(item->folder != NULL);
1010 if (folder_item_parent(item)) return;
1012 for (list = folderview_list; list != NULL; list = list->next) {
1013 FolderView *folderview = (FolderView *)list->data;
1014 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1015 GtkCTreeNode *node, *child;
1016 gint *col_pos = folderview->col_pos;
1018 node = gtk_ctree_find_by_row_data(ctree, NULL,
1019 folder_item_parent(item));
1021 child = gtk_ctree_find_by_row_data(ctree, node, item);
1023 gchar *text[N_FOLDER_COLS] =
1024 {NULL, "0", "0", "0"};
1026 gtk_clist_freeze(GTK_CLIST(ctree));
1028 text[col_pos[F_COL_FOLDER]] = item->name;
1029 child = gtk_sctree_insert_node
1030 (ctree, node, NULL, text,
1032 folderxpm, folderxpmmask,
1033 folderopenxpm, folderopenxpmmask,
1035 gtk_ctree_node_set_row_data(ctree, child, item);
1036 gtk_ctree_expand(ctree, node);
1037 folderview_update_node(folderview, child);
1038 folderview_sort_folders(folderview, node,
1041 gtk_clist_thaw(GTK_CLIST(ctree));
1047 static void folderview_set_folders(FolderView *folderview)
1050 list = folder_get_list();
1052 for (; list != NULL; list = list->next) {
1053 folderview_append_folder(folderview, FOLDER(list->data));
1057 static gchar *get_scan_str(FolderItem *item)
1060 return g_strdup_printf(_("Scanning folder %s%c%s ..."),
1061 item->folder->name, G_DIR_SEPARATOR,
1064 return g_strdup_printf(_("Scanning folder %s ..."),
1065 item->folder->name);
1067 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
1071 for (list = folderview_list; list != NULL; list = list->next) {
1072 FolderView *folderview = (FolderView *)list->data;
1073 MainWindow *mainwin = folderview->mainwin;
1074 gchar *str = get_scan_str(item);
1076 STATUSBAR_PUSH(mainwin, str);
1077 STATUSBAR_POP(mainwin);
1082 void folderview_rescan_tree(Folder *folder, gboolean rebuild)
1086 g_return_if_fail(folder != NULL);
1088 if (!folder->klass->scan_tree) return;
1091 alertpanel_full(_("Rebuild folder tree"),
1092 _("Rebuilding the folder tree will remove "
1093 "local caches. Do you want to continue?"),
1094 GTK_STOCK_NO, GTK_STOCK_YES, NULL, FALSE,
1095 NULL, ALERT_WARNING, G_ALERTDEFAULT)
1096 != G_ALERTALTERNATE) {
1102 window = label_window_create(_("Rebuilding folder tree..."));
1104 window = label_window_create(_("Scanning folder tree..."));
1106 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1107 folder_scan_tree(folder, rebuild);
1108 folder_set_ui_func(folder, NULL, NULL);
1110 folderview_set_all();
1112 gtk_widget_destroy(window);
1116 /** folderview_check_new()
1117 * Scan and update the folder and return the
1118 * count the number of new messages since last check.
1119 * \param folder the folder to check for new messages
1120 * \return the number of new messages since last check
1122 gint folderview_check_new(Folder *folder)
1126 FolderView *folderview;
1130 gint former_new_msgs = 0;
1131 gint former_new = 0, former_unread = 0, former_total;
1133 for (list = folderview_list; list != NULL; list = list->next) {
1134 folderview = (FolderView *)list->data;
1135 ctree = GTK_CTREE(folderview->ctree);
1138 main_window_lock(folderview->mainwin);
1140 for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1141 node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
1143 item = gtk_ctree_node_get_row_data(ctree, node);
1144 if (!item || !item->path || !item->folder) continue;
1145 if (item->no_select) continue;
1146 if (folder && folder != item->folder) continue;
1147 if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
1148 if (!item->prefs->newmailcheck) continue;
1149 if (item->processing_pending == TRUE) {
1150 debug_print("skipping %s, processing pending\n",
1151 item->path ? item->path : item->name);
1155 str = get_scan_str(item);
1157 STATUSBAR_PUSH(folderview->mainwin, str);
1161 folderview_scan_tree_func(item->folder, item, NULL);
1162 former_new = item->new_msgs;
1163 former_unread = item->unread_msgs;
1164 former_total = item->total_msgs;
1166 if (item->folder->klass->scan_required &&
1167 (item->folder->klass->scan_required(item->folder, item) ||
1168 item->folder->inbox == item ||
1169 item->opened == TRUE ||
1170 item->processing_pending == TRUE)) {
1171 if (folder_item_scan(item) < 0) {
1173 summaryview_unlock(folderview->summaryview, item);
1174 if (FOLDER_TYPE(item->folder) == F_NEWS || FOLDER_IS_LOCAL(folder)) {
1175 log_error(_("Couldn't scan folder %s\n"),
1176 item->path ? item->path:item->name);
1178 } else if (!FOLDER_IS_LOCAL(folder)) {
1179 STATUSBAR_POP(folderview->mainwin);
1184 } else if (!item->folder->klass->scan_required) {
1185 if (folder_item_scan(item) < 0) {
1186 summaryview_unlock(folderview->summaryview, item);
1187 if (folder && !FOLDER_IS_LOCAL(folder)) {
1188 STATUSBAR_POP(folderview->mainwin);
1193 if (former_new != item->new_msgs ||
1194 former_unread != item->unread_msgs ||
1195 former_total != item->total_msgs)
1196 folderview_update_node(folderview, node);
1198 new_msgs += item->new_msgs;
1199 former_new_msgs += former_new;
1200 STATUSBAR_POP(folderview->mainwin);
1203 main_window_unlock(folderview->mainwin);
1207 folder_write_list();
1208 /* Number of new messages since last check is the just the difference
1209 * between former_new_msgs and new_msgs. If new_msgs is less than
1210 * former_new_msgs, that would mean another session accessed the folder
1211 * and the result is not well defined.
1213 new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
1217 void folderview_check_new_all(void)
1221 FolderView *folderview;
1223 folderview = (FolderView *)folderview_list->data;
1226 main_window_lock(folderview->mainwin);
1227 window = label_window_create
1228 (_("Checking for new messages in all folders..."));
1230 list = folder_get_list();
1231 for (; list != NULL; list = list->next) {
1232 Folder *folder = list->data;
1234 folderview_check_new(folder);
1237 folder_write_list();
1238 folderview_set_all();
1240 gtk_widget_destroy(window);
1241 main_window_unlock(folderview->mainwin);
1245 static gboolean folderview_have_new_children_sub(FolderView *folderview,
1251 if (!item || !item->folder || !item->folder->node)
1254 node = item->folder->node;
1256 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1257 node = node->children;
1260 (item->new_msgs > 0 ||
1261 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1265 while (node != NULL) {
1266 if (node && node->data) {
1267 FolderItem *next_item = (FolderItem*) node->data;
1269 if (folderview_have_new_children_sub(folderview,
1278 static gboolean folderview_have_new_children(FolderView *folderview,
1281 return folderview_have_new_children_sub(folderview, item, FALSE);
1284 static gboolean folderview_have_unread_children_sub(FolderView *folderview,
1290 if (!item || !item->folder || !item->folder->node)
1293 node = item->folder->node;
1295 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1296 node = node->children;
1299 (item->unread_msgs > 0 ||
1300 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1304 while (node != NULL) {
1305 if (node && node->data) {
1306 FolderItem *next_item = (FolderItem*) node->data;
1308 if (folderview_have_unread_children_sub(folderview,
1318 static gboolean folderview_have_unread_children(FolderView *folderview,
1321 return folderview_have_unread_children_sub(folderview, item, FALSE);
1324 static gboolean folderview_have_matching_children_sub(FolderView *folderview,
1330 if (!item || !item->folder || !item->folder->node)
1333 node = item->folder->node;
1335 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1336 node = node->children;
1338 if (in_sub && item->search_match){
1342 while (node != NULL) {
1343 if (node && node->data) {
1344 FolderItem *next_item = (FolderItem*) node->data;
1346 if (folderview_have_matching_children_sub(folderview,
1356 static gboolean folderview_have_matching_children(FolderView *folderview,
1359 return folderview_have_matching_children_sub(folderview, item, FALSE);
1362 static gboolean folderview_have_marked_children_sub(FolderView *folderview,
1368 if (!item || !item->folder || !item->folder->node)
1371 node = item->folder->node;
1373 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1374 node = node->children;
1376 if (item->marked_msgs != 0) {
1380 while (node != NULL) {
1381 if (node && node->data) {
1382 FolderItem *next_item = (FolderItem*) node->data;
1384 if (folderview_have_marked_children_sub(folderview,
1393 static gboolean folderview_have_marked_children(FolderView *folderview,
1396 return folderview_have_marked_children_sub(folderview, item, FALSE);
1399 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
1401 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1402 GtkStyle *style = NULL;
1403 GtkStyle *color_style = NULL;
1405 GdkPixmap *xpm, *openxpm;
1406 GdkBitmap *mask, *openmask;
1407 static GdkPixmap *searchicon;
1408 static GdkBitmap *searchmask;
1409 gboolean mark = FALSE;
1412 gboolean add_unread_mark;
1413 gboolean add_sub_match_mark;
1414 gboolean use_bold, use_color;
1415 gint *col_pos = folderview->col_pos;
1416 SpecialFolderItemType stype;
1418 item = gtk_ctree_node_get_row_data(ctree, node);
1419 g_return_if_fail(item != NULL);
1421 if (!GTK_CTREE_ROW(node)->expanded)
1422 mark = folderview_have_marked_children(folderview, item);
1424 mark = (item->marked_msgs != 0);
1426 stype = item->stype;
1427 if (stype == F_NORMAL) {
1428 if (folder_has_parent_of_type(item, F_TRASH))
1430 else if (folder_has_parent_of_type(item, F_DRAFT))
1432 else if (folder_has_parent_of_type(item, F_OUTBOX))
1434 else if (folder_has_parent_of_type(item, F_QUEUE))
1439 if (item->hide_read_msgs) {
1440 xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
1441 mask = mark?m_inboxhrmxpmmask:inboxhrmxpmmask;
1442 openxpm = mark?m_inboxopenhrmxpm:inboxopenhrmxpm;
1443 openmask = mark?m_inboxopenhrmxpmmask:inboxopenhrmxpmmask;
1445 xpm = mark?m_inboxxpm:inboxxpm;
1446 mask = mark?m_inboxxpmmask:inboxxpmmask;
1447 openxpm = mark?m_inboxopenxpm:inboxopenxpm;
1448 openmask = mark?m_inboxopenxpmmask:inboxopenxpmmask;
1452 if (item->hide_read_msgs) {
1453 xpm = mark?m_outboxhrmxpm:outboxhrmxpm;
1454 mask = mark?m_outboxhrmxpmmask:outboxhrmxpmmask;
1455 openxpm = mark?m_outboxopenhrmxpm:outboxopenhrmxpm;
1456 openmask = mark?m_outboxopenhrmxpmmask:outboxopenhrmxpmmask;
1458 xpm = mark?m_outboxxpm:outboxxpm;
1459 mask = mark?m_outboxxpmmask:outboxxpmmask;
1460 openxpm = mark?m_outboxopenxpm:outboxopenxpm;
1461 openmask = mark?m_outboxopenxpmmask:outboxopenxpmmask;
1465 if (item->hide_read_msgs) {
1466 xpm = mark?m_queuehrmxpm:queuehrmxpm;
1467 mask = mark?m_queuehrmxpmmask:queuehrmxpmmask;
1468 openxpm = mark?m_queueopenhrmxpm:queueopenhrmxpm;
1469 openmask = mark?m_queueopenhrmxpmmask:queueopenhrmxpmmask;
1471 xpm = mark?m_queuexpm:queuexpm;
1472 mask = mark?m_queuexpmmask:queuexpmmask;
1473 openxpm = mark?m_queueopenxpm:queueopenxpm;
1474 openmask = mark?m_queueopenxpmmask:queueopenxpmmask;
1478 if (item->hide_read_msgs) {
1479 xpm = mark?m_trashhrmxpm:trashhrmxpm;
1480 mask = mark?m_trashhrmxpmmask:trashhrmxpmmask;
1481 openxpm = mark?m_trashopenhrmxpm:trashopenhrmxpm;
1482 openmask = mark?m_trashopenhrmxpmmask:trashopenhrmxpmmask;
1484 xpm = mark?m_trashxpm:trashxpm;
1485 mask = mark?m_trashxpmmask:trashxpmmask;
1486 openxpm = mark?m_trashopenxpm:trashopenxpm;
1487 openmask = mark?m_trashopenxpmmask:trashopenxpmmask;
1491 xpm = mark?m_draftsxpm:draftsxpm;
1492 mask = mark?m_draftsxpmmask:draftsxpmmask;
1493 openxpm = mark?m_draftsopenxpm:draftsopenxpm;
1494 openmask = mark?m_draftsopenxpmmask:draftsopenxpmmask;
1497 if (item->hide_read_msgs) {
1498 xpm = mark?m_folderhrmxpm:folderhrmxpm;
1499 mask = mark?m_folderhrmxpmmask:folderhrmxpmmask;
1500 openxpm = mark?m_folderopenhrmxpm:folderopenhrmxpm;
1501 openmask = mark?m_folderopenhrmxpmmask:folderopenhrmxpmmask;
1503 xpm = mark?m_folderxpm:folderxpm;
1504 mask = mark?m_folderxpmmask:folderxpmmask;
1505 openxpm = mark?m_folderopenxpm:folderopenxpm;
1506 openmask = mark?m_folderopenxpmmask:folderopenxpmmask;
1510 if (item->no_select) {
1511 xpm = openxpm = noselectxpm;
1512 mask = openmask = noselectxpmmask;
1515 name = folder_item_get_name(item);
1517 if (!GTK_CTREE_ROW(node)->expanded) {
1518 add_unread_mark = folderview_have_unread_children(
1520 add_sub_match_mark = folderview_have_matching_children(
1523 add_unread_mark = FALSE;
1524 add_sub_match_mark = FALSE;
1527 if (item->search_match) {
1529 stock_pixmap_gdk(folderview->ctree, STOCK_PIXMAP_QUICKSEARCH,
1530 &searchicon, &searchmask);
1532 xpm = openxpm = searchicon;
1533 mask = openmask = searchmask;
1536 if (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0 &&
1537 prefs_common.display_folder_unread) {
1538 str = g_strdup_printf("%s (%d%s)", name, item->total_msgs,
1539 add_unread_mark ? "+" : "");
1540 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1541 xpm, mask, openxpm, openmask,
1542 FALSE, GTK_CTREE_ROW(node)->expanded);
1544 } else if (((item->unread_msgs > 0 || add_unread_mark) &&
1545 prefs_common.display_folder_unread)
1546 || add_sub_match_mark) {
1548 if (item->unread_msgs > 0)
1549 str = g_strdup_printf("%s (%d%s%s)", name, item->unread_msgs,
1550 add_unread_mark || add_sub_match_mark ? "+" : "",
1551 item->unreadmarked_msgs > 0 ? "!":"");
1553 str = g_strdup_printf("%s (+)", name);
1554 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1555 xpm, mask, openxpm, openmask,
1556 FALSE, GTK_CTREE_ROW(node)->expanded);
1559 str = g_strdup_printf("%s%s", name,
1560 item->unreadmarked_msgs > 0 ? " (!)":"");
1562 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1563 xpm, mask, openxpm, openmask,
1564 FALSE, GTK_CTREE_ROW(node)->expanded);
1569 if (!folder_item_parent(item)) {
1570 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], "-");
1571 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
1572 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], "-");
1574 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], itos(item->new_msgs));
1575 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], itos(item->unread_msgs));
1576 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], itos(item->total_msgs));
1579 if (folder_has_parent_of_type(item, F_OUTBOX) ||
1580 folder_has_parent_of_type(item, F_DRAFT) ||
1581 folder_has_parent_of_type(item, F_TRASH)) {
1582 use_bold = use_color = FALSE;
1583 } else if (folder_has_parent_of_type(item, F_QUEUE)) {
1584 /* highlight queue folder if there are any messages */
1585 use_bold = use_color = (item->total_msgs > 0);
1587 /* if unread messages exist, print with bold font */
1588 use_bold = (item->unread_msgs > 0|| item->new_msgs > 0)
1590 /* if new messages exist, print with colored letter */
1592 (item->new_msgs > 0) ||
1594 folderview_have_new_children(folderview, item));
1597 gtk_ctree_node_set_foreground(ctree, node, NULL);
1602 if (item->prefs->color > 0 && !use_color) {
1603 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1604 color_style = gtk_style_copy(bold_style);
1605 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1606 style = color_style;
1607 } else if (use_color) {
1608 style = bold_color_style;
1611 if (item->op_count > 0) {
1612 style = bold_tgtfold_style;
1614 } else if (use_color) {
1615 style = normal_color_style;
1616 gtk_ctree_node_set_foreground(ctree, node,
1617 &folderview->color_new);
1618 } else if (item->op_count > 0) {
1619 style = bold_tgtfold_style;
1620 } else if (item->prefs->color > 0) {
1622 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1623 color_style = gtk_style_copy(normal_style);
1624 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1625 style = color_style;
1627 style = normal_style;
1630 gtk_ctree_node_set_row_style(ctree, node, style);
1632 if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1633 folderview_update_node(folderview, node);
1636 #if !CLAWS /* keep it here for syncs */
1637 void folderview_update_item(FolderItem *item, gboolean update_summary)
1640 FolderView *folderview;
1644 g_return_if_fail(item != NULL);
1646 for (list = folderview_list; list != NULL; list = list->next) {
1647 folderview = (FolderView *)list->data;
1648 ctree = GTK_CTREE(folderview->ctree);
1650 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1652 folderview_update_node(folderview, node);
1653 if (update_summary && folderview->opened == node)
1654 summary_show(folderview->summaryview,
1661 void folderview_update_search_icon(FolderItem *item, gboolean matches)
1664 FolderView *folderview;
1668 g_return_if_fail(item != NULL);
1670 for (list = folderview_list; list != NULL; list = list->next) {
1671 folderview = (FolderView *)list->data;
1672 ctree = GTK_CTREE(folderview->ctree);
1674 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1676 item->search_match = matches;
1677 folderview_update_node(folderview, node);
1682 gboolean folderview_update_item_claws(gpointer source, gpointer data)
1684 FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1685 FolderView *folderview = (FolderView *)data;
1688 g_return_val_if_fail(update_info != NULL, TRUE);
1689 g_return_val_if_fail(update_info->item != NULL, TRUE);
1690 g_return_val_if_fail(folderview != NULL, FALSE);
1692 ctree = GTK_CTREE(folderview->ctree);
1694 node = gtk_ctree_find_by_row_data(ctree, NULL, update_info->item);
1697 if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
1698 folderview_update_node(folderview, node);
1699 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) && (folderview->opened == node))
1700 if (!quicksearch_is_active(folderview->summaryview->quicksearch))
1701 summary_show(folderview->summaryview, update_info->item);
1707 static void folderview_update_item_foreach_func(gpointer key, gpointer val,
1710 /* CLAWS: share this joy with other hook functions ... */
1711 folder_item_update((FolderItem *)key,
1712 (FolderItemUpdateFlags)GPOINTER_TO_INT(data));
1715 void folderview_update_item_foreach(GHashTable *table, gboolean update_summary)
1718 FolderItemUpdateFlags flags;
1720 flags = update_summary ? F_ITEM_UPDATE_CONTENT | F_ITEM_UPDATE_MSGCNT
1722 for (list = folderview_list; list != NULL; list = list->next)
1723 g_hash_table_foreach(table, folderview_update_item_foreach_func,
1724 GINT_TO_POINTER(flags));
1727 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1728 GNode *gnode, GtkCTreeNode *cnode,
1731 FolderView *folderview = (FolderView *)data;
1732 FolderItem *item = FOLDER_ITEM(gnode->data);
1734 g_return_val_if_fail(item != NULL, FALSE);
1736 gtk_ctree_node_set_row_data(ctree, cnode, item);
1737 folderview_update_node(folderview, cnode);
1742 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1745 FolderView *folderview = (FolderView *)data;
1748 if (GTK_CTREE_ROW(node)->children) {
1749 item = gtk_ctree_node_get_row_data(ctree, node);
1750 g_return_if_fail(item != NULL);
1752 if (!item->collapsed)
1753 gtk_ctree_expand(ctree, node);
1755 folderview_update_node(folderview, node);
1759 static void set_special_folder(GtkCTree *ctree, FolderItem *item,
1760 GtkCTreeNode *root, GtkCTreeNode **prev)
1763 GtkCTreeNode *node, *parent, *sibling;
1765 node = gtk_ctree_find_by_row_data(ctree, root, item);
1767 g_warning("%s not found.\n", item->path);
1769 parent = GTK_CTREE_ROW(node)->parent;
1770 if (*prev && parent == GTK_CTREE_ROW(*prev)->parent)
1771 sibling = GTK_CTREE_ROW(*prev)->sibling;
1773 sibling = GTK_CTREE_ROW(parent)->children;
1777 tmp = gtk_ctree_node_get_row_data
1779 if (tmp->stype != F_NORMAL)
1780 sibling = GTK_CTREE_ROW(sibling)->sibling;
1784 if (node != sibling)
1785 gtk_ctree_move(ctree, node, parent, sibling);
1792 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1795 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1796 GtkCTreeNode *prev = NULL;
1798 gtk_clist_freeze(GTK_CLIST(ctree));
1799 gtk_sctree_sort_recursive(ctree, root);
1800 if (root && GTK_CTREE_ROW(root)->parent) {
1801 gtk_clist_thaw(GTK_CLIST(ctree));
1804 set_special_folder(ctree, folder->inbox, root, &prev);
1805 set_special_folder(ctree, folder->outbox, root, &prev);
1806 set_special_folder(ctree, folder->draft, root, &prev);
1807 set_special_folder(ctree, folder->queue, root, &prev);
1808 set_special_folder(ctree, folder->trash, root, &prev);
1809 gtk_clist_thaw(GTK_CLIST(ctree));
1812 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1814 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1817 g_return_if_fail(folder != NULL);
1819 root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
1820 folderview_gnode_func, folderview);
1821 gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1823 folderview_sort_folders(folderview, root, folder);
1826 /* callback functions */
1827 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
1828 GdkEventButton *event)
1830 GtkCList *clist = GTK_CLIST(folderview->ctree);
1833 FolderViewPopup *fpopup;
1834 GtkItemFactory *fpopup_factory;
1836 FolderItem *special_trash = NULL, *special_queue = NULL;
1840 item = gtk_clist_get_row_data(clist, row);
1842 item = folderview_get_selected_item(folderview);
1844 g_return_if_fail(item != NULL);
1845 g_return_if_fail(item->folder != NULL);
1846 folder = item->folder;
1848 fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1850 fpopup_factory = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1852 fpopup = g_hash_table_lookup(folderview_popups, "common");
1853 fpopup_factory = g_hash_table_lookup(folderview->popups, "common");
1856 if (fpopup->set_sensitivity != NULL)
1857 fpopup->set_sensitivity(fpopup_factory, item);
1859 if (NULL != (ac = account_find_from_item(item))) {
1860 special_trash = account_get_special_folder(ac, F_TRASH);
1861 special_queue = account_get_special_folder(ac, F_QUEUE);
1864 if ((item == folder->trash || item == special_trash
1865 || folder_has_parent_of_type(item, F_TRASH)) &&
1866 gtk_item_factory_get_item(fpopup_factory, "/Empty trash...") == NULL) {
1867 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[0], folderview, 1);
1868 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[1], folderview, 1);
1869 } else if (item != folder->trash && (special_trash == NULL || item != special_trash)
1870 && !folder_has_parent_of_type(item, F_TRASH)) {
1871 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[0]);
1872 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[1]);
1875 if ((item == folder->queue || item == special_queue
1876 || folder_has_parent_of_type(item, F_QUEUE)) &&
1877 gtk_item_factory_get_item(fpopup_factory, "/Send queue...") == NULL) {
1878 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[0], folderview, 1);
1879 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[1], folderview, 1);
1880 } else if (item != folder->queue && (special_queue == NULL || item != special_queue)
1881 && !folder_has_parent_of_type(item, F_QUEUE)) {
1882 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[0]);
1883 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[1]);
1886 #define SET_SENS(name, sens) \
1887 menu_set_sensitive(fpopup_factory, name, sens)
1889 SET_SENS("/Mark all read", item->unread_msgs >= 1);
1890 SET_SENS("/Search folder...", item->total_msgs >= 1 &&
1891 folderview->selected == folderview->opened);
1892 SET_SENS("/Properties...", TRUE);
1893 SET_SENS("/Processing...", item->node->parent != NULL);
1894 if (item == folder->trash || item == special_trash
1895 || folder_has_parent_of_type(item, F_TRASH)) {
1896 GSList *msglist = folder_item_get_msg_list(item);
1897 SET_SENS("/Empty trash...", msglist != NULL);
1898 procmsg_msg_list_free(msglist);
1900 if (item == folder->queue || item == special_queue
1901 || folder_has_parent_of_type(item, F_QUEUE)) {
1902 GSList *msglist = folder_item_get_msg_list(item);
1903 SET_SENS("/Send queue...", msglist != NULL);
1904 procmsg_msg_list_free(msglist);
1908 popup = gtk_item_factory_get_widget(fpopup_factory, fpopup->path);
1909 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1910 event->button, event->time);
1915 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1916 FolderView *folderview)
1918 GtkCList *clist = GTK_CLIST(ctree);
1919 gint prev_row = -1, row = -1, column = -1;
1921 if (!event) return FALSE;
1923 if (event->button == 1 || event->button == 2) {
1924 if (!gtk_ctree_is_hot_spot (GTK_CTREE(clist), event->x, event->y))
1925 folderview->open_folder = TRUE;
1927 if (event->type == GDK_2BUTTON_PRESS) {
1928 if (clist->selection) {
1931 node = GTK_CTREE_NODE(clist->selection->data);
1933 gtk_ctree_toggle_expansion(
1936 folderview->open_folder = FALSE;
1943 if (event->button == 2 || event->button == 3) {
1945 if (clist->selection) {
1948 node = GTK_CTREE_NODE(clist->selection->data);
1950 prev_row = gtkut_ctree_get_nth_from_node
1951 (GTK_CTREE(ctree), node);
1954 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1957 if (prev_row != row) {
1958 gtk_clist_unselect_all(clist);
1959 if (event->button == 2)
1960 folderview_select_node
1962 gtk_ctree_node_nth(GTK_CTREE(ctree),
1965 gtk_clist_select_row(clist, row, column);
1969 if (event->button != 3) return FALSE;
1971 folderview_set_sens_and_popup_menu(folderview, row, event);
1975 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1976 FolderView *folderview)
1978 if (!event) return FALSE;
1980 if (event->button == 1 && folderview->open_folder == FALSE &&
1981 folderview->opened != NULL) {
1982 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1983 folderview->opened);
1984 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1990 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1991 FolderView *folderview)
1993 if (!event) return FALSE;
1995 if (quicksearch_has_focus(folderview->summaryview->quicksearch))
1998 switch (event->keyval) {
2000 if (folderview->selected) {
2001 folderview_select_node(folderview,
2002 folderview->selected);
2006 if (folderview->selected) {
2007 if (folderview->opened == folderview->selected &&
2008 (!folderview->summaryview->folder_item ||
2009 folderview->summaryview->folder_item->total_msgs == 0))
2010 folderview_select_next_unread(folderview, TRUE);
2012 folderview_select_node(folderview,
2013 folderview->selected);
2023 typedef struct _PostponedSelectData
2028 FolderView *folderview;
2029 } PostponedSelectData;
2031 static gboolean postpone_select(void *data)
2033 PostponedSelectData *psdata = (PostponedSelectData *)data;
2034 debug_print("trying again\n");
2035 psdata->folderview->open_folder = TRUE;
2036 main_window_cursor_normal(psdata->folderview->mainwin);
2037 STATUSBAR_POP(psdata->folderview->mainwin);
2038 folderview_selected(psdata->ctree, psdata->row,
2039 psdata->column, psdata->folderview);
2044 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
2045 gint column, FolderView *folderview)
2047 static gboolean can_select = TRUE; /* exclusive lock */
2053 folderview->selected = row;
2055 if (folderview->opened == row) {
2056 folderview->open_folder = FALSE;
2061 if (!can_select || summary_is_locked(folderview->summaryview)) {
2062 if (folderview->opened) {
2063 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2064 gtk_ctree_select(ctree, folderview->opened);
2070 if (!folderview->open_folder) {
2074 item = gtk_ctree_node_get_row_data(ctree, row);
2075 if (!item || item->no_select) {
2077 folderview->open_folder = FALSE;
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, gboolean copy)
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(copy ? _("Do you really want to copy folder '%s' in '%s' ?"):
2442 _("Do you really want to make folder '%s' a sub-folder of '%s' ?"),
2443 from_folder->name, to_folder->name);
2444 status = alertpanel_full(copy ? _("Copy folder"):_("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(copy ? _("Copying %s to %s..."):_("Moving %s to %s..."),
2456 from_folder->name, to_folder->name);
2457 STATUSBAR_PUSH(folderview->mainwin, buf);
2459 summary_clear_all(folderview->summaryview);
2460 folderview->opened = NULL;
2461 folderview->selected = NULL;
2462 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2464 main_window_cursor_wait(folderview->mainwin);
2465 statusbar_verbosity_set(TRUE);
2466 folder_item_update_freeze();
2467 if ((status = folder_item_move_to(from_folder, to_folder, &new_folder, copy)) == F_MOVE_OK) {
2468 statusbar_verbosity_set(FALSE);
2469 main_window_cursor_normal(folderview->mainwin);
2470 STATUSBAR_POP(folderview->mainwin);
2471 folder_item_update_thaw();
2472 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2474 folderview_sort_folders(folderview,
2475 gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree),
2476 NULL, to_folder), new_folder->folder);
2477 folderview_select(folderview, new_folder);
2479 statusbar_verbosity_set(FALSE);
2480 main_window_cursor_normal(folderview->mainwin);
2481 STATUSBAR_POP(folderview->mainwin);
2482 folder_item_update_thaw();
2484 case F_MOVE_FAILED_DEST_IS_PARENT:
2485 alertpanel_error(_("Source and destination are the same."));
2487 case F_MOVE_FAILED_DEST_IS_CHILD:
2488 alertpanel_error(copy ? _("Can't copy a folder to one of its children."):
2489 _("Can't move a folder to one of its children."));
2491 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2492 alertpanel_error(_("Folder moving cannot be done between different mailboxes."));
2495 alertpanel_error(copy ? _("Copy failed!"):_("Move failed!"));
2500 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2503 static gint folderview_clist_compare(GtkCList *clist,
2504 gconstpointer ptr1, gconstpointer ptr2)
2506 FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
2507 FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
2510 return (item2->name != NULL);
2514 return g_utf8_collate(item1->name, item2->name);
2517 static void folderview_processing_cb(FolderView *folderview, guint action,
2520 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2524 if (!folderview->selected) return;
2526 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2527 g_return_if_fail(item != NULL);
2528 g_return_if_fail(item->folder != NULL);
2530 id = folder_item_get_identifier(item);
2531 title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2534 prefs_filtering_open(&item->prefs->processing, title,
2535 MANUAL_ANCHOR_PROCESSING, NULL, NULL, FALSE);
2539 void folderview_set_target_folder_color(gint color_op)
2543 FolderView *folderview;
2545 for (list = folderview_list; list != NULL; list = list->next) {
2546 folderview = (FolderView *)list->data;
2547 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2549 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2550 folderview->color_op;
2556 static gchar *last_font = NULL;
2557 void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
2565 void folderview_reflect_prefs(void)
2567 gboolean update_font = TRUE;
2568 FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2569 FolderItem *item = folderview_get_selected_item(folderview);
2570 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2571 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2572 gint height = pos->value;
2574 if (last_font && !strcmp(last_font, NORMAL_FONT))
2575 update_font = FALSE;
2578 last_font = g_strdup(NORMAL_FONT);
2581 normal_style = normal_color_style = bold_style =
2582 bold_color_style = bold_tgtfold_style = NULL;
2584 folderview_init(folderview);
2586 gtk_clist_freeze(GTK_CLIST(folderview->ctree));
2587 folderview_column_set_titles(folderview);
2588 folderview_set_all();
2590 g_signal_handlers_block_by_func
2591 (G_OBJECT(folderview->ctree),
2592 G_CALLBACK(folderview_selected), folderview);
2595 GtkCTreeNode *node = gtk_ctree_find_by_row_data(
2596 GTK_CTREE(folderview->ctree), NULL, item);
2598 folderview_select(folderview, item);
2599 folderview->open_folder = FALSE;
2600 folderview->selected = node;
2603 g_signal_handlers_unblock_by_func
2604 (G_OBJECT(folderview->ctree),
2605 G_CALLBACK(folderview_selected), folderview);
2607 pos = gtk_scrolled_window_get_vadjustment(
2608 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2609 gtk_adjustment_set_value(pos, height);
2610 gtk_clist_thaw(GTK_CLIST(folderview->ctree));
2613 static void drag_state_stop(FolderView *folderview)
2615 if (folderview->drag_timer)
2616 g_source_remove(folderview->drag_timer);
2617 folderview->drag_timer = 0;
2618 folderview->drag_node = NULL;
2621 static gint folderview_defer_expand(FolderView *folderview)
2623 if (folderview->drag_node) {
2624 folderview_recollapse_nodes(folderview, folderview->drag_node);
2625 if (folderview->drag_item->collapsed) {
2626 gtk_ctree_expand(GTK_CTREE(folderview->ctree), folderview->drag_node);
2627 folderview->nodes_to_recollapse = g_slist_append
2628 (folderview->nodes_to_recollapse, folderview->drag_node);
2631 folderview->drag_item = NULL;
2632 folderview->drag_timer = 0;
2636 static void drag_state_start(FolderView *folderview, GtkCTreeNode *node, FolderItem *item)
2638 /* the idea is that we call drag_state_start() whenever we want expansion to
2639 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2640 * we need to call drag_state_stop() */
2641 drag_state_stop(folderview);
2642 /* request expansion */
2643 if (0 != (folderview->drag_timer = g_timeout_add
2644 (prefs_common.hover_timeout,
2645 (GtkFunction)folderview_defer_expand,
2647 folderview->drag_node = node;
2648 folderview->drag_item = item;
2652 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2653 FolderView *folderview)
2655 GdkDragContext *context;
2657 g_return_if_fail(folderview != NULL);
2658 if (folderview->selected == NULL) return;
2659 if (folderview->nodes_to_recollapse)
2660 g_slist_free(folderview->nodes_to_recollapse);
2661 folderview->nodes_to_recollapse = NULL;
2662 context = gtk_drag_begin(widget, folderview->target_list,
2663 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2664 gtk_drag_set_icon_default(context);
2667 static void folderview_drag_data_get(GtkWidget *widget,
2668 GdkDragContext *drag_context,
2669 GtkSelectionData *selection_data,
2672 FolderView *folderview)
2676 gchar *source = NULL;
2677 if (info == TARGET_DUMMY) {
2678 for (cur = GTK_CLIST(folderview->ctree)->selection;
2679 cur != NULL; cur = cur->next) {
2680 item = gtk_ctree_node_get_row_data
2681 (GTK_CTREE(folderview->ctree),
2682 GTK_CTREE_NODE(cur->data));
2684 source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2685 gtk_selection_data_set(selection_data,
2686 selection_data->target, 8,
2687 source, strlen(source));
2693 g_warning("unknown info %d\n", info);
2697 gboolean folderview_update_folder(gpointer source, gpointer userdata)
2699 FolderUpdateData *hookdata;
2700 FolderView *folderview;
2704 folderview = (FolderView *) userdata;
2705 g_return_val_if_fail(hookdata != NULL, FALSE);
2706 g_return_val_if_fail(folderview != NULL, FALSE);
2708 ctree = folderview->ctree;
2709 g_return_val_if_fail(ctree != NULL, FALSE);
2711 if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2712 folderview_create_folder_node(folderview, hookdata->item);
2713 else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2714 GtkCTreeNode *node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree),
2715 NULL, folder_item_parent(hookdata->item));
2716 folderview_sort_folders(folderview, node, hookdata->folder);
2717 } else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2720 node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree), NULL, hookdata->item);
2722 gtk_ctree_remove_node(GTK_CTREE(ctree), node);
2723 } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
2724 folderview_set(folderview);
2729 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2730 GdkDragContext *context,
2734 FolderView *folderview)
2737 FolderItem *item = NULL, *src_item = NULL;
2738 GtkCTreeNode *node = NULL;
2739 gboolean acceptable = FALSE;
2740 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2741 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2742 int height = (int)pos->page_size;
2743 int total_height = (int)pos->upper;
2744 int vpos = (int) pos->value;
2746 if (gtk_clist_get_selection_info
2747 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
2748 GtkWidget *srcwidget;
2750 if (y > height - 24 && height + vpos < total_height)
2751 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
2753 if (y < 48 && y > 0)
2754 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
2756 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2757 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2758 src_item = folderview->summaryview->folder_item;
2760 srcwidget = gtk_drag_get_source_widget(context);
2761 if (srcwidget == summary_get_main_widget(folderview->summaryview)) {
2762 /* comes from summaryview */
2763 /* we are copying messages, so only accept folder items that are not
2764 the source item, are no root items and can copy messages */
2765 if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
2766 src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2767 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2769 } else if (srcwidget == folderview->ctree) {
2770 /* comes from folderview */
2771 /* we are moving folder items, only accept folders that are not
2772 the source items and can copy messages and create folder items */
2773 if (item && item->folder && src_item && src_item != item &&
2774 FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2775 FOLDER_CLASS(item->folder)->create_folder != NULL &&
2776 ((FOLDER_TYPE(item->folder) != F_UNKNOWN && FOLDER_TYPE(src_item->folder) != F_UNKNOWN)
2777 || item->folder == src_item->folder))
2780 /* comes from another app */
2781 /* we are adding messages, so only accept folder items that are
2782 no root items and can copy messages */
2783 if (item && item->folder && folder_item_parent(item) != NULL
2784 && FOLDER_CLASS(item->folder)->add_msg != NULL &&
2785 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2790 if (acceptable || (src_item && src_item == item))
2791 drag_state_start(folderview, node, item);
2794 g_signal_handlers_block_by_func
2796 G_CALLBACK(folderview_selected), folderview);
2797 gtk_ctree_select(GTK_CTREE(widget), node);
2798 g_signal_handlers_unblock_by_func
2800 G_CALLBACK(folderview_selected), folderview);
2801 gdk_drag_status(context,
2802 (context->actions == GDK_ACTION_COPY ?
2803 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2805 if (folderview->opened)
2806 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2807 gdk_drag_status(context, 0, time);
2813 static void folderview_drag_leave_cb(GtkWidget *widget,
2814 GdkDragContext *context,
2816 FolderView *folderview)
2818 drag_state_stop(folderview);
2819 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2822 static void free_info (gpointer stuff, gpointer data)
2827 void folderview_finish_dnd(const gchar *data, GdkDragContext *drag_context,
2828 guint time, FolderItem *item)
2831 GSList *msglist = NULL;
2832 list = uri_list_extract_filenames(data);
2833 if (!(item && item->folder && folder_item_parent(item) != NULL
2834 && FOLDER_CLASS(item->folder)->add_msg != NULL))
2836 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2840 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2843 for (tmp = list; tmp != NULL; tmp = tmp->next) {
2844 MsgFileInfo *info = NULL;
2846 if (file_is_email((gchar *)tmp->data)) {
2847 info = g_new0(MsgFileInfo, 1);
2848 info->msginfo = NULL;
2849 info->file = (gchar *)tmp->data;
2850 msglist = g_slist_prepend(msglist, info);
2854 msglist = g_slist_reverse(msglist);
2855 folder_item_add_msgs(item, msglist, FALSE);
2856 g_slist_foreach(msglist, free_info, NULL);
2857 g_slist_free(msglist);
2858 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2860 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2862 list_free_strings(list);
2866 static void folderview_drag_received_cb(GtkWidget *widget,
2867 GdkDragContext *drag_context,
2870 GtkSelectionData *data,
2873 FolderView *folderview)
2876 FolderItem *item = NULL, *src_item;
2879 if (info == TARGET_DUMMY) {
2880 drag_state_stop(folderview);
2881 if ((void *)strstr(data->data, "FROM_OTHER_FOLDER") != (void *)data->data) {
2882 /* comes from summaryview */
2883 if (gtk_clist_get_selection_info
2884 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2887 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2888 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2889 src_item = folderview->summaryview->folder_item;
2891 /* re-check (due to acceptable possibly set for folder moves */
2892 if (!(item && item->folder && item->path && !item->no_select &&
2893 src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) {
2896 if (item && src_item) {
2897 switch (drag_context->action) {
2898 case GDK_ACTION_COPY:
2899 summary_copy_selected_to(folderview->summaryview, item);
2900 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2902 case GDK_ACTION_MOVE:
2903 case GDK_ACTION_DEFAULT:
2905 if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL)
2906 summary_copy_selected_to(folderview->summaryview, item);
2908 summary_move_selected_to(folderview->summaryview, item);
2909 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2912 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2914 /* comes from folderview */
2916 gboolean folder_is_normal = TRUE;
2917 gboolean copy = (drag_context->action == GDK_ACTION_COPY);
2919 source = data->data + 17;
2920 if (gtk_clist_get_selection_info
2921 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0
2923 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2926 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2927 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2928 src_item = folder_find_item_from_identifier(source);
2932 src_item->stype == F_NORMAL &&
2933 !folder_has_parent_of_type(src_item, F_OUTBOX) &&
2934 !folder_has_parent_of_type(src_item, F_DRAFT) &&
2935 !folder_has_parent_of_type(src_item, F_QUEUE) &&
2936 !folder_has_parent_of_type(src_item, F_TRASH);
2937 if (!item || item->no_select || !src_item
2938 || !folder_is_normal) {
2939 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2943 folderview_move_folder(folderview, src_item, item, copy);
2944 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2946 folderview->nodes_to_recollapse = NULL;
2947 } else if (info == TARGET_MAIL_URI_LIST) {
2948 if (gtk_clist_get_selection_info
2949 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2952 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2954 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2957 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2959 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2962 folderview_finish_dnd(data->data, drag_context, time, item);
2966 static void folderview_drag_end_cb(GtkWidget *widget,
2967 GdkDragContext *drag_context,
2968 FolderView *folderview)
2970 drag_state_stop(folderview);
2971 g_slist_free(folderview->nodes_to_recollapse);
2972 folderview->nodes_to_recollapse = NULL;
2975 void folderview_register_popup(FolderViewPopup *fpopup)
2979 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2980 FolderView *folderview = folderviews->data;
2981 GtkItemFactory *factory;
2983 factory = create_ifactory(folderview, fpopup);
2984 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
2986 g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
2989 void folderview_unregister_popup(FolderViewPopup *fpopup)
2993 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2994 FolderView *folderview = folderviews->data;
2996 g_hash_table_remove(folderview->popups, fpopup->klass);
2998 g_hash_table_remove(folderview_popups, fpopup->klass);