2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2007 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)
1085 MainWindow *mainwin = mainwindow_get_mainwindow();
1086 FolderView *folderview = NULL;
1087 GtkAdjustment *pos = NULL;
1090 g_return_if_fail(folder != NULL);
1092 if (!folder->klass->scan_tree) return;
1095 alertpanel_full(_("Rebuild folder tree"),
1096 _("Rebuilding the folder tree will remove "
1097 "local caches. Do you want to continue?"),
1098 GTK_STOCK_NO, GTK_STOCK_YES, NULL, FALSE,
1099 NULL, ALERT_WARNING, G_ALERTDEFAULT)
1100 != G_ALERTALTERNATE) {
1106 window = label_window_create(_("Rebuilding folder tree..."));
1108 window = label_window_create(_("Scanning folder tree..."));
1111 folderview = mainwin->folderview;
1114 pos = gtk_scrolled_window_get_vadjustment(
1115 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1116 height = pos->value;
1119 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1120 folder_scan_tree(folder, rebuild);
1121 folder_set_ui_func(folder, NULL, NULL);
1123 folderview_set_all();
1126 pos = gtk_scrolled_window_get_vadjustment(
1127 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1128 gtk_adjustment_set_value(pos, height);
1130 gtk_widget_destroy(window);
1134 /** folderview_check_new()
1135 * Scan and update the folder and return the
1136 * count the number of new messages since last check.
1137 * \param folder the folder to check for new messages
1138 * \return the number of new messages since last check
1140 gint folderview_check_new(Folder *folder)
1144 FolderView *folderview;
1148 gint former_new_msgs = 0;
1149 gint former_new = 0, former_unread = 0, former_total;
1151 for (list = folderview_list; list != NULL; list = list->next) {
1152 folderview = (FolderView *)list->data;
1153 ctree = GTK_CTREE(folderview->ctree);
1156 main_window_lock(folderview->mainwin);
1158 for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1159 node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
1161 item = gtk_ctree_node_get_row_data(ctree, node);
1162 if (!item || !item->path || !item->folder) continue;
1163 if (item->no_select) continue;
1164 if (folder && folder != item->folder) continue;
1165 if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
1166 if (!item->prefs->newmailcheck) continue;
1167 if (item->processing_pending == TRUE) {
1168 debug_print("skipping %s, processing pending\n",
1169 item->path ? item->path : item->name);
1173 str = get_scan_str(item);
1175 STATUSBAR_PUSH(folderview->mainwin, str);
1179 folderview_scan_tree_func(item->folder, item, NULL);
1180 former_new = item->new_msgs;
1181 former_unread = item->unread_msgs;
1182 former_total = item->total_msgs;
1184 if (item->folder->klass->scan_required &&
1185 (item->folder->klass->scan_required(item->folder, item) ||
1186 item->folder->inbox == item ||
1187 item->opened == TRUE ||
1188 item->processing_pending == TRUE)) {
1189 if (folder_item_scan(item) < 0) {
1191 summaryview_unlock(folderview->summaryview, item);
1192 if (FOLDER_TYPE(item->folder) == F_NEWS || FOLDER_IS_LOCAL(folder)) {
1193 log_error(_("Couldn't scan folder %s\n"),
1194 item->path ? item->path:item->name);
1196 } else if (!FOLDER_IS_LOCAL(folder)) {
1197 STATUSBAR_POP(folderview->mainwin);
1202 } else if (!item->folder->klass->scan_required) {
1203 if (folder_item_scan(item) < 0) {
1204 summaryview_unlock(folderview->summaryview, item);
1205 if (folder && !FOLDER_IS_LOCAL(folder)) {
1206 STATUSBAR_POP(folderview->mainwin);
1211 if (former_new != item->new_msgs ||
1212 former_unread != item->unread_msgs ||
1213 former_total != item->total_msgs)
1214 folderview_update_node(folderview, node);
1216 new_msgs += item->new_msgs;
1217 former_new_msgs += former_new;
1218 STATUSBAR_POP(folderview->mainwin);
1221 main_window_unlock(folderview->mainwin);
1225 folder_write_list();
1226 /* Number of new messages since last check is the just the difference
1227 * between former_new_msgs and new_msgs. If new_msgs is less than
1228 * former_new_msgs, that would mean another session accessed the folder
1229 * and the result is not well defined.
1231 new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
1235 void folderview_check_new_all(void)
1239 FolderView *folderview;
1241 folderview = (FolderView *)folderview_list->data;
1244 main_window_lock(folderview->mainwin);
1245 window = label_window_create
1246 (_("Checking for new messages in all folders..."));
1248 list = folder_get_list();
1249 for (; list != NULL; list = list->next) {
1250 Folder *folder = list->data;
1252 folderview_check_new(folder);
1255 folder_write_list();
1256 folderview_set_all();
1258 gtk_widget_destroy(window);
1259 main_window_unlock(folderview->mainwin);
1263 static gboolean folderview_have_new_children_sub(FolderView *folderview,
1269 if (!item || !item->folder || !item->folder->node)
1272 node = item->folder->node;
1274 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1275 node = node->children;
1278 (item->new_msgs > 0 ||
1279 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1283 while (node != NULL) {
1284 if (node && node->data) {
1285 FolderItem *next_item = (FolderItem*) node->data;
1287 if (folderview_have_new_children_sub(folderview,
1296 static gboolean folderview_have_new_children(FolderView *folderview,
1299 return folderview_have_new_children_sub(folderview, item, FALSE);
1302 static gboolean folderview_have_unread_children_sub(FolderView *folderview,
1308 if (!item || !item->folder || !item->folder->node)
1311 node = item->folder->node;
1313 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1314 node = node->children;
1317 (item->unread_msgs > 0 ||
1318 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1322 while (node != NULL) {
1323 if (node && node->data) {
1324 FolderItem *next_item = (FolderItem*) node->data;
1326 if (folderview_have_unread_children_sub(folderview,
1336 static gboolean folderview_have_unread_children(FolderView *folderview,
1339 return folderview_have_unread_children_sub(folderview, item, FALSE);
1342 static gboolean folderview_have_matching_children_sub(FolderView *folderview,
1348 if (!item || !item->folder || !item->folder->node)
1351 node = item->folder->node;
1353 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1354 node = node->children;
1356 if (in_sub && item->search_match){
1360 while (node != NULL) {
1361 if (node && node->data) {
1362 FolderItem *next_item = (FolderItem*) node->data;
1364 if (folderview_have_matching_children_sub(folderview,
1374 static gboolean folderview_have_matching_children(FolderView *folderview,
1377 return folderview_have_matching_children_sub(folderview, item, FALSE);
1380 static gboolean folderview_have_marked_children_sub(FolderView *folderview,
1386 if (!item || !item->folder || !item->folder->node)
1389 node = item->folder->node;
1391 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1392 node = node->children;
1394 if (item->marked_msgs != 0) {
1398 while (node != NULL) {
1399 if (node && node->data) {
1400 FolderItem *next_item = (FolderItem*) node->data;
1402 if (folderview_have_marked_children_sub(folderview,
1411 static gboolean folderview_have_marked_children(FolderView *folderview,
1414 return folderview_have_marked_children_sub(folderview, item, FALSE);
1417 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
1419 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1420 GtkStyle *style = NULL;
1421 GtkStyle *color_style = NULL;
1423 GdkPixmap *xpm, *openxpm;
1424 GdkBitmap *mask, *openmask;
1425 static GdkPixmap *searchicon;
1426 static GdkBitmap *searchmask;
1427 gboolean mark = FALSE;
1430 gboolean add_unread_mark;
1431 gboolean add_sub_match_mark;
1432 gboolean use_bold, use_color;
1433 gint *col_pos = folderview->col_pos;
1434 SpecialFolderItemType stype;
1436 item = gtk_ctree_node_get_row_data(ctree, node);
1437 g_return_if_fail(item != NULL);
1439 if (!GTK_CTREE_ROW(node)->expanded)
1440 mark = folderview_have_marked_children(folderview, item);
1442 mark = (item->marked_msgs != 0);
1444 stype = item->stype;
1445 if (stype == F_NORMAL) {
1446 if (folder_has_parent_of_type(item, F_TRASH))
1448 else if (folder_has_parent_of_type(item, F_DRAFT))
1450 else if (folder_has_parent_of_type(item, F_OUTBOX))
1452 else if (folder_has_parent_of_type(item, F_QUEUE))
1457 if (item->hide_read_msgs) {
1458 xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
1459 mask = mark?m_inboxhrmxpmmask:inboxhrmxpmmask;
1460 openxpm = mark?m_inboxopenhrmxpm:inboxopenhrmxpm;
1461 openmask = mark?m_inboxopenhrmxpmmask:inboxopenhrmxpmmask;
1463 xpm = mark?m_inboxxpm:inboxxpm;
1464 mask = mark?m_inboxxpmmask:inboxxpmmask;
1465 openxpm = mark?m_inboxopenxpm:inboxopenxpm;
1466 openmask = mark?m_inboxopenxpmmask:inboxopenxpmmask;
1470 if (item->hide_read_msgs) {
1471 xpm = mark?m_outboxhrmxpm:outboxhrmxpm;
1472 mask = mark?m_outboxhrmxpmmask:outboxhrmxpmmask;
1473 openxpm = mark?m_outboxopenhrmxpm:outboxopenhrmxpm;
1474 openmask = mark?m_outboxopenhrmxpmmask:outboxopenhrmxpmmask;
1476 xpm = mark?m_outboxxpm:outboxxpm;
1477 mask = mark?m_outboxxpmmask:outboxxpmmask;
1478 openxpm = mark?m_outboxopenxpm:outboxopenxpm;
1479 openmask = mark?m_outboxopenxpmmask:outboxopenxpmmask;
1483 if (item->hide_read_msgs) {
1484 xpm = mark?m_queuehrmxpm:queuehrmxpm;
1485 mask = mark?m_queuehrmxpmmask:queuehrmxpmmask;
1486 openxpm = mark?m_queueopenhrmxpm:queueopenhrmxpm;
1487 openmask = mark?m_queueopenhrmxpmmask:queueopenhrmxpmmask;
1489 xpm = mark?m_queuexpm:queuexpm;
1490 mask = mark?m_queuexpmmask:queuexpmmask;
1491 openxpm = mark?m_queueopenxpm:queueopenxpm;
1492 openmask = mark?m_queueopenxpmmask:queueopenxpmmask;
1496 if (item->hide_read_msgs) {
1497 xpm = mark?m_trashhrmxpm:trashhrmxpm;
1498 mask = mark?m_trashhrmxpmmask:trashhrmxpmmask;
1499 openxpm = mark?m_trashopenhrmxpm:trashopenhrmxpm;
1500 openmask = mark?m_trashopenhrmxpmmask:trashopenhrmxpmmask;
1502 xpm = mark?m_trashxpm:trashxpm;
1503 mask = mark?m_trashxpmmask:trashxpmmask;
1504 openxpm = mark?m_trashopenxpm:trashopenxpm;
1505 openmask = mark?m_trashopenxpmmask:trashopenxpmmask;
1509 xpm = mark?m_draftsxpm:draftsxpm;
1510 mask = mark?m_draftsxpmmask:draftsxpmmask;
1511 openxpm = mark?m_draftsopenxpm:draftsopenxpm;
1512 openmask = mark?m_draftsopenxpmmask:draftsopenxpmmask;
1515 if (item->hide_read_msgs) {
1516 xpm = mark?m_folderhrmxpm:folderhrmxpm;
1517 mask = mark?m_folderhrmxpmmask:folderhrmxpmmask;
1518 openxpm = mark?m_folderopenhrmxpm:folderopenhrmxpm;
1519 openmask = mark?m_folderopenhrmxpmmask:folderopenhrmxpmmask;
1521 xpm = mark?m_folderxpm:folderxpm;
1522 mask = mark?m_folderxpmmask:folderxpmmask;
1523 openxpm = mark?m_folderopenxpm:folderopenxpm;
1524 openmask = mark?m_folderopenxpmmask:folderopenxpmmask;
1528 if (item->no_select) {
1529 xpm = openxpm = noselectxpm;
1530 mask = openmask = noselectxpmmask;
1533 name = folder_item_get_name(item);
1535 if (!GTK_CTREE_ROW(node)->expanded) {
1536 add_unread_mark = folderview_have_unread_children(
1538 add_sub_match_mark = folderview_have_matching_children(
1541 add_unread_mark = FALSE;
1542 add_sub_match_mark = FALSE;
1545 if (item->search_match) {
1547 stock_pixmap_gdk(folderview->ctree, STOCK_PIXMAP_QUICKSEARCH,
1548 &searchicon, &searchmask);
1550 xpm = openxpm = searchicon;
1551 mask = openmask = searchmask;
1554 if (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0 &&
1555 prefs_common.display_folder_unread) {
1556 str = g_strdup_printf("%s (%d%s)", name, item->total_msgs,
1557 add_unread_mark ? "+" : "");
1558 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1559 xpm, mask, openxpm, openmask,
1560 FALSE, GTK_CTREE_ROW(node)->expanded);
1562 } else if (((item->unread_msgs > 0 || add_unread_mark) &&
1563 prefs_common.display_folder_unread)
1564 || add_sub_match_mark) {
1566 if (item->unread_msgs > 0)
1567 str = g_strdup_printf("%s (%d%s%s)", name, item->unread_msgs,
1568 add_unread_mark || add_sub_match_mark ? "+" : "",
1569 item->unreadmarked_msgs > 0 ? "!":"");
1571 str = g_strdup_printf("%s (+)", name);
1572 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1573 xpm, mask, openxpm, openmask,
1574 FALSE, GTK_CTREE_ROW(node)->expanded);
1577 str = g_strdup_printf("%s%s", name,
1578 item->unreadmarked_msgs > 0 ? " (!)":"");
1580 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1581 xpm, mask, openxpm, openmask,
1582 FALSE, GTK_CTREE_ROW(node)->expanded);
1587 if (!folder_item_parent(item)) {
1588 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], "-");
1589 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
1590 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], "-");
1592 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], itos(item->new_msgs));
1593 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], itos(item->unread_msgs));
1594 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], itos(item->total_msgs));
1597 if (folder_has_parent_of_type(item, F_OUTBOX) ||
1598 folder_has_parent_of_type(item, F_DRAFT) ||
1599 folder_has_parent_of_type(item, F_TRASH)) {
1600 use_bold = use_color = FALSE;
1601 } else if (folder_has_parent_of_type(item, F_QUEUE)) {
1602 /* highlight queue folder if there are any messages */
1603 use_bold = use_color = (item->total_msgs > 0);
1605 /* if unread messages exist, print with bold font */
1606 use_bold = (item->unread_msgs > 0|| item->new_msgs > 0)
1608 /* if new messages exist, print with colored letter */
1610 (item->new_msgs > 0) ||
1612 folderview_have_new_children(folderview, item));
1615 gtk_ctree_node_set_foreground(ctree, node, NULL);
1620 if (item->prefs->color > 0 && !use_color) {
1621 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1622 color_style = gtk_style_copy(bold_style);
1623 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1624 style = color_style;
1625 } else if (use_color) {
1626 style = bold_color_style;
1629 if (item->op_count > 0) {
1630 style = bold_tgtfold_style;
1632 } else if (use_color) {
1633 style = normal_color_style;
1634 gtk_ctree_node_set_foreground(ctree, node,
1635 &folderview->color_new);
1636 } else if (item->op_count > 0) {
1637 style = bold_tgtfold_style;
1638 } else if (item->prefs->color > 0) {
1640 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1641 color_style = gtk_style_copy(normal_style);
1642 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1643 style = color_style;
1645 style = normal_style;
1648 gtk_ctree_node_set_row_style(ctree, node, style);
1650 if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1651 folderview_update_node(folderview, node);
1654 void folderview_update_search_icon(FolderItem *item, gboolean matches)
1657 FolderView *folderview;
1661 g_return_if_fail(item != NULL);
1663 for (list = folderview_list; list != NULL; list = list->next) {
1664 folderview = (FolderView *)list->data;
1665 ctree = GTK_CTREE(folderview->ctree);
1667 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1669 item->search_match = matches;
1670 folderview_update_node(folderview, node);
1675 gboolean folderview_update_item_claws(gpointer source, gpointer data)
1677 FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1678 FolderView *folderview = (FolderView *)data;
1681 g_return_val_if_fail(update_info != NULL, TRUE);
1682 g_return_val_if_fail(update_info->item != NULL, TRUE);
1683 g_return_val_if_fail(folderview != NULL, FALSE);
1685 ctree = GTK_CTREE(folderview->ctree);
1687 node = gtk_ctree_find_by_row_data(ctree, NULL, update_info->item);
1690 if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
1691 folderview_update_node(folderview, node);
1692 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) && (folderview->opened == node))
1693 if (!quicksearch_is_active(folderview->summaryview->quicksearch))
1694 summary_show(folderview->summaryview, update_info->item);
1700 static void folderview_update_item_foreach_func(gpointer key, gpointer val,
1703 /* CLAWS: share this joy with other hook functions ... */
1704 folder_item_update((FolderItem *)key,
1705 (FolderItemUpdateFlags)GPOINTER_TO_INT(data));
1708 void folderview_update_item_foreach(GHashTable *table, gboolean update_summary)
1711 FolderItemUpdateFlags flags;
1713 flags = update_summary ? F_ITEM_UPDATE_CONTENT | F_ITEM_UPDATE_MSGCNT
1715 for (list = folderview_list; list != NULL; list = list->next)
1716 g_hash_table_foreach(table, folderview_update_item_foreach_func,
1717 GINT_TO_POINTER(flags));
1720 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1721 GNode *gnode, GtkCTreeNode *cnode,
1724 FolderView *folderview = (FolderView *)data;
1725 FolderItem *item = FOLDER_ITEM(gnode->data);
1727 g_return_val_if_fail(item != NULL, FALSE);
1729 gtk_ctree_node_set_row_data(ctree, cnode, item);
1730 folderview_update_node(folderview, cnode);
1735 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1738 FolderView *folderview = (FolderView *)data;
1741 if (GTK_CTREE_ROW(node)->children) {
1742 item = gtk_ctree_node_get_row_data(ctree, node);
1743 g_return_if_fail(item != NULL);
1745 if (!item->collapsed)
1746 gtk_ctree_expand(ctree, node);
1748 folderview_update_node(folderview, node);
1752 static void set_special_folder(GtkCTree *ctree, FolderItem *item,
1753 GtkCTreeNode *root, GtkCTreeNode **prev)
1756 GtkCTreeNode *node, *parent, *sibling;
1758 node = gtk_ctree_find_by_row_data(ctree, root, item);
1760 g_warning("%s not found.\n", item->path);
1762 parent = GTK_CTREE_ROW(node)->parent;
1763 if (*prev && parent == GTK_CTREE_ROW(*prev)->parent)
1764 sibling = GTK_CTREE_ROW(*prev)->sibling;
1766 sibling = GTK_CTREE_ROW(parent)->children;
1770 tmp = gtk_ctree_node_get_row_data
1772 if (tmp->stype != F_NORMAL)
1773 sibling = GTK_CTREE_ROW(sibling)->sibling;
1777 if (node != sibling)
1778 gtk_ctree_move(ctree, node, parent, sibling);
1785 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1788 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1789 GtkCTreeNode *prev = NULL;
1791 gtk_clist_freeze(GTK_CLIST(ctree));
1792 gtk_sctree_sort_recursive(ctree, root);
1793 if (root && GTK_CTREE_ROW(root)->parent) {
1794 gtk_clist_thaw(GTK_CLIST(ctree));
1797 set_special_folder(ctree, folder->inbox, root, &prev);
1798 set_special_folder(ctree, folder->outbox, root, &prev);
1799 set_special_folder(ctree, folder->draft, root, &prev);
1800 set_special_folder(ctree, folder->queue, root, &prev);
1801 set_special_folder(ctree, folder->trash, root, &prev);
1802 gtk_clist_thaw(GTK_CLIST(ctree));
1805 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1807 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1810 g_return_if_fail(folder != NULL);
1812 root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
1813 folderview_gnode_func, folderview);
1814 gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1816 folderview_sort_folders(folderview, root, folder);
1819 /* callback functions */
1820 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
1821 GdkEventButton *event)
1823 GtkCList *clist = GTK_CLIST(folderview->ctree);
1826 FolderViewPopup *fpopup;
1827 GtkItemFactory *fpopup_factory;
1829 FolderItem *special_trash = NULL, *special_queue = NULL;
1833 item = gtk_clist_get_row_data(clist, row);
1835 item = folderview_get_selected_item(folderview);
1837 g_return_if_fail(item != NULL);
1838 g_return_if_fail(item->folder != NULL);
1839 folder = item->folder;
1841 fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1843 fpopup_factory = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1845 fpopup = g_hash_table_lookup(folderview_popups, "common");
1846 fpopup_factory = g_hash_table_lookup(folderview->popups, "common");
1849 if (fpopup->set_sensitivity != NULL)
1850 fpopup->set_sensitivity(fpopup_factory, item);
1852 if (NULL != (ac = account_find_from_item(item))) {
1853 special_trash = account_get_special_folder(ac, F_TRASH);
1854 special_queue = account_get_special_folder(ac, F_QUEUE);
1857 if ((item == folder->trash || item == special_trash
1858 || folder_has_parent_of_type(item, F_TRASH)) &&
1859 gtk_item_factory_get_item(fpopup_factory, "/Empty trash...") == NULL) {
1860 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[0], folderview, 1);
1861 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[1], folderview, 1);
1862 } else if (item != folder->trash && (special_trash == NULL || item != special_trash)
1863 && !folder_has_parent_of_type(item, F_TRASH)) {
1864 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[0]);
1865 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[1]);
1868 if ((item == folder->queue || item == special_queue
1869 || folder_has_parent_of_type(item, F_QUEUE)) &&
1870 gtk_item_factory_get_item(fpopup_factory, "/Send queue...") == NULL) {
1871 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[0], folderview, 1);
1872 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[1], folderview, 1);
1873 } else if (item != folder->queue && (special_queue == NULL || item != special_queue)
1874 && !folder_has_parent_of_type(item, F_QUEUE)) {
1875 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[0]);
1876 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[1]);
1879 #define SET_SENS(name, sens) \
1880 menu_set_sensitive(fpopup_factory, name, sens)
1882 SET_SENS("/Mark all read", item->unread_msgs >= 1);
1883 SET_SENS("/Search folder...", item->total_msgs >= 1 &&
1884 folderview->selected == folderview->opened);
1885 SET_SENS("/Properties...", TRUE);
1886 SET_SENS("/Processing...", item->node->parent != NULL);
1887 if (item == folder->trash || item == special_trash
1888 || folder_has_parent_of_type(item, F_TRASH)) {
1889 GSList *msglist = folder_item_get_msg_list(item);
1890 SET_SENS("/Empty trash...", msglist != NULL);
1891 procmsg_msg_list_free(msglist);
1893 if (item == folder->queue || item == special_queue
1894 || folder_has_parent_of_type(item, F_QUEUE)) {
1895 GSList *msglist = folder_item_get_msg_list(item);
1896 SET_SENS("/Send queue...", msglist != NULL);
1897 procmsg_msg_list_free(msglist);
1901 popup = gtk_item_factory_get_widget(fpopup_factory, fpopup->path);
1902 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1903 event->button, event->time);
1908 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1909 FolderView *folderview)
1911 GtkCList *clist = GTK_CLIST(ctree);
1912 gint prev_row = -1, row = -1, column = -1;
1914 if (!event) return FALSE;
1916 if (event->button == 1 || event->button == 2) {
1917 if (!gtk_ctree_is_hot_spot (GTK_CTREE(clist), event->x, event->y))
1918 folderview->open_folder = TRUE;
1920 if (event->type == GDK_2BUTTON_PRESS) {
1921 if (clist->selection) {
1924 node = GTK_CTREE_NODE(clist->selection->data);
1926 gtk_ctree_toggle_expansion(
1929 folderview->open_folder = FALSE;
1936 if (event->button == 2 || event->button == 3) {
1938 if (clist->selection) {
1941 node = GTK_CTREE_NODE(clist->selection->data);
1943 prev_row = gtkut_ctree_get_nth_from_node
1944 (GTK_CTREE(ctree), node);
1947 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1950 if (prev_row != row) {
1951 gtk_clist_unselect_all(clist);
1952 if (event->button == 2)
1953 folderview_select_node
1955 gtk_ctree_node_nth(GTK_CTREE(ctree),
1958 gtk_clist_select_row(clist, row, column);
1962 if (event->button != 3) return FALSE;
1964 folderview_set_sens_and_popup_menu(folderview, row, event);
1968 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1969 FolderView *folderview)
1971 if (!event) return FALSE;
1973 if (event->button == 1 && folderview->open_folder == FALSE &&
1974 folderview->opened != NULL) {
1975 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1976 folderview->opened);
1977 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1983 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1984 FolderView *folderview)
1986 if (!event) return FALSE;
1988 if (quicksearch_has_focus(folderview->summaryview->quicksearch))
1991 switch (event->keyval) {
1993 if (folderview->selected) {
1994 folderview_select_node(folderview,
1995 folderview->selected);
1999 if (folderview->selected) {
2000 if (folderview->opened == folderview->selected &&
2001 (!folderview->summaryview->folder_item ||
2002 folderview->summaryview->folder_item->total_msgs == 0))
2003 folderview_select_next_unread(folderview, TRUE);
2005 folderview_select_node(folderview,
2006 folderview->selected);
2016 typedef struct _PostponedSelectData
2021 FolderView *folderview;
2022 } PostponedSelectData;
2024 static gboolean postpone_select(void *data)
2026 PostponedSelectData *psdata = (PostponedSelectData *)data;
2027 debug_print("trying again\n");
2028 psdata->folderview->open_folder = TRUE;
2029 main_window_cursor_normal(psdata->folderview->mainwin);
2030 STATUSBAR_POP(psdata->folderview->mainwin);
2031 folderview_selected(psdata->ctree, psdata->row,
2032 psdata->column, psdata->folderview);
2037 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
2038 gint column, FolderView *folderview)
2040 static gboolean can_select = TRUE; /* exclusive lock */
2046 folderview->selected = row;
2048 if (folderview->opened == row) {
2049 folderview->open_folder = FALSE;
2054 if (!can_select || summary_is_locked(folderview->summaryview)) {
2055 if (folderview->opened) {
2056 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2057 gtk_ctree_select(ctree, folderview->opened);
2063 if (!folderview->open_folder) {
2067 item = gtk_ctree_node_get_row_data(ctree, row);
2068 if (!item || item->no_select) {
2070 folderview->open_folder = FALSE;
2076 /* Save cache for old folder */
2077 /* We don't want to lose all caches if sylpheed crashed */
2078 if (folderview->opened) {
2079 FolderItem *olditem;
2081 olditem = gtk_ctree_node_get_row_data(ctree, folderview->opened);
2083 buf = g_strdup_printf(_("Closing Folder %s..."),
2084 olditem->path ? olditem->path:olditem->name);
2085 /* will be null if we just moved the previously opened folder */
2086 STATUSBAR_PUSH(folderview->mainwin, buf);
2087 main_window_cursor_wait(folderview->mainwin);
2089 summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
2090 summary_show(folderview->summaryview, NULL);
2091 folder_item_close(olditem);
2092 main_window_cursor_normal(folderview->mainwin);
2093 STATUSBAR_POP(folderview->mainwin);
2097 /* CLAWS: set compose button type: news folder items
2098 * always have a news folder as parent */
2100 toolbar_set_compose_button
2101 (folderview->mainwin->toolbar,
2102 FOLDER_TYPE(item->folder) == F_NEWS ?
2103 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
2106 debug_print("Folder %s is selected\n", item->path);
2108 if (!GTK_CTREE_ROW(row)->children)
2109 gtk_ctree_expand(ctree, row);
2110 if (folderview->opened &&
2111 !GTK_CTREE_ROW(folderview->opened)->children)
2112 gtk_ctree_collapse(ctree, folderview->opened);
2114 /* ungrab the mouse event */
2115 if (GTK_WIDGET_HAS_GRAB(ctree)) {
2116 gtk_grab_remove(GTK_WIDGET(ctree));
2117 if (gdk_pointer_is_grabbed())
2118 gdk_pointer_ungrab(GDK_CURRENT_TIME);
2122 buf = g_strdup_printf(_("Opening Folder %s..."), item->path ?
2123 item->path : "(null)");
2124 debug_print("%s\n", buf);
2125 STATUSBAR_PUSH(folderview->mainwin, buf);
2128 main_window_cursor_wait(folderview->mainwin);
2130 res = folder_item_open(item);
2132 main_window_cursor_normal(folderview->mainwin);
2133 STATUSBAR_POP(folderview->mainwin);
2135 alertpanel_error(_("Folder could not be opened."));
2137 folderview->open_folder = FALSE;
2141 } else if (res == -2) {
2142 PostponedSelectData *data = g_new0(PostponedSelectData, 1);
2143 data->ctree = ctree;
2145 data->column = column;
2146 data->folderview = folderview;
2147 debug_print("postponing open of %s till end of scan\n",
2148 item->path ? item->path:item->name);
2149 folderview->open_folder = FALSE;
2151 g_timeout_add(500, postpone_select, data);
2156 main_window_cursor_normal(folderview->mainwin);
2159 summary_set_prefs_from_folderitem(folderview->summaryview, item);
2160 opened = summary_show(folderview->summaryview, item);
2162 folder_clean_cache_memory(item);
2165 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2166 gtk_ctree_select(ctree, folderview->opened);
2168 folderview->opened = row;
2169 if (gtk_ctree_node_is_visible(ctree, row)
2170 != GTK_VISIBILITY_FULL)
2171 gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0);
2174 STATUSBAR_POP(folderview->mainwin);
2176 folderview->open_folder = FALSE;
2181 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
2182 FolderView *folderview)
2186 item = gtk_ctree_node_get_row_data(ctree, node);
2187 g_return_if_fail(item != NULL);
2188 item->collapsed = FALSE;
2189 folderview_update_node(folderview, node);
2192 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
2193 FolderView *folderview)
2197 item = gtk_ctree_node_get_row_data(ctree, node);
2198 g_return_if_fail(item != NULL);
2199 item->collapsed = TRUE;
2200 folderview_update_node(folderview, node);
2203 static void folderview_popup_close(GtkMenuShell *menu_shell,
2204 FolderView *folderview)
2206 if (!folderview->opened) return;
2208 gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
2211 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
2212 FolderView *folderview)
2214 FolderColumnType type = folderview->col_state[column].type;
2216 prefs_common.folder_col_size[type] = width;
2219 void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item)
2223 folderview_create_folder_node(folderview, item);
2225 if (!item || !item->folder || !item->folder->node)
2228 srcnode = item->folder->node;
2229 srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item);
2230 srcnode = srcnode->children;
2231 while (srcnode != NULL) {
2232 if (srcnode && srcnode->data) {
2233 FolderItem *next_item = (FolderItem*) srcnode->data;
2234 folderview_create_folder_node_recursive(folderview, next_item);
2236 srcnode = srcnode->next;
2240 void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
2242 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2243 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2244 GtkCTreeNode *node, *parent_node;
2245 gint *col_pos = folderview->col_pos;
2246 FolderItemUpdateData hookdata;
2248 parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
2249 if (parent_node == NULL)
2252 gtk_clist_freeze(GTK_CLIST(ctree));
2254 text[col_pos[F_COL_FOLDER]] = item->name;
2255 node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
2257 folderxpm, folderxpmmask,
2258 folderopenxpm, folderopenxpmmask,
2260 gtk_ctree_expand(ctree, parent_node);
2261 gtk_ctree_node_set_row_data(ctree, node, item);
2263 gtk_ctree_node_set_row_style(ctree, node, normal_style);
2264 folderview_sort_folders(folderview, parent_node, item->folder);
2266 hookdata.item = item;
2267 hookdata.update_flags = F_ITEM_UPDATE_NAME;
2268 hookdata.msg = NULL;
2269 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
2271 gtk_clist_thaw(GTK_CLIST(ctree));
2274 static void folderview_empty_trash_cb(FolderView *folderview, guint action,
2277 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2279 GSList *mlist = NULL;
2281 FolderItem *special_trash = NULL;
2284 if (!folderview->selected) return;
2285 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2286 g_return_if_fail(item != NULL);
2287 g_return_if_fail(item->folder != NULL);
2289 if (NULL != (ac = account_find_from_item(item)))
2290 special_trash = account_get_special_folder(ac, F_TRASH);
2292 if (item != item->folder->trash && item != special_trash
2293 && !folder_has_parent_of_type(item, F_TRASH)) return;
2295 if (prefs_common.ask_on_clean) {
2296 if (alertpanel(_("Empty trash"),
2297 _("Delete all messages in trash?"),
2298 GTK_STOCK_CANCEL, _("+_Empty trash"), NULL) != G_ALERTALTERNATE)
2302 mlist = folder_item_get_msg_list(item);
2304 for (cur = mlist ; cur != NULL ; cur = cur->next) {
2305 MsgInfo * msginfo = (MsgInfo *) cur->data;
2306 if (MSG_IS_LOCKED(msginfo->flags))
2308 /* is it partially received? (partial_recv isn't cached) */
2309 if (msginfo->total_size != 0 &&
2310 msginfo->size != (off_t)msginfo->total_size)
2311 partial_mark_for_delete(msginfo);
2313 procmsg_msg_list_free(mlist);
2315 folder_item_remove_all_msg(item);
2318 static void folderview_send_queue_cb(FolderView *folderview, guint action,
2321 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2323 FolderItem *special_queue = NULL;
2325 gchar *errstr = NULL;
2327 if (!folderview->selected) return;
2328 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2329 g_return_if_fail(item != NULL);
2330 g_return_if_fail(item->folder != NULL);
2332 if (NULL != (ac = account_find_from_item(item)))
2333 special_queue = account_get_special_folder(ac, F_QUEUE);
2335 if (item != item->folder->queue && item != special_queue
2336 && !folder_has_parent_of_type(item, F_QUEUE)) return;
2338 if (procmsg_queue_is_empty(item))
2341 if (prefs_common.work_offline)
2342 if (alertpanel(_("Offline warning"),
2343 _("You're working offline. Override?"),
2344 GTK_STOCK_NO, GTK_STOCK_YES,
2345 NULL) != G_ALERTALTERNATE)
2348 /* ask for confirmation before sending queued messages only
2349 in online mode and if there is at least one message queued
2350 in any of the folder queue
2352 if (prefs_common.confirm_send_queued_messages) {
2353 if (!prefs_common.work_offline) {
2354 if (alertpanel(_("Send queued messages"),
2355 _("Send all queued messages?"),
2356 GTK_STOCK_CANCEL, _("_Send"),
2357 NULL) != G_ALERTALTERNATE)
2362 if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
2364 alertpanel_error_log(_("Some errors occurred while "
2365 "sending queued messages."));
2367 gchar *tmp = g_strdup_printf(_("Some errors occurred "
2368 "while sending queued messages:\n%s"), errstr);
2370 alertpanel_error_log(tmp);
2376 static void folderview_search_cb(FolderView *folderview, guint action,
2379 summary_search(folderview->summaryview);
2382 static void folderview_property_cb(FolderView *folderview, guint action,
2385 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2388 if (!folderview->selected) return;
2390 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2391 g_return_if_fail(item != NULL);
2392 g_return_if_fail(item->folder != NULL);
2394 prefs_folder_item_open(item);
2397 static void folderview_recollapse_nodes(FolderView *folderview, GtkCTreeNode *node)
2399 GSList *list = NULL;
2400 GSList *done = NULL;
2401 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2403 for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2404 if (!gtkut_ctree_node_is_parent(GTK_CTREE_NODE(list->data), node)
2405 && list->data != node) {
2406 gtk_ctree_collapse(ctree, GTK_CTREE_NODE(list->data));
2407 done = g_slist_append(done, GTK_CTREE_NODE(list->data));
2410 for (list = done; list != NULL; list = g_slist_next(list)) {
2411 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse,
2417 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
2418 FolderItem *to_folder, gboolean copy)
2420 FolderItem *from_parent = NULL;
2421 FolderItem *new_folder = NULL;
2422 GtkCTreeNode *src_node = NULL;
2426 g_return_if_fail(folderview != NULL);
2427 g_return_if_fail(from_folder != NULL);
2428 g_return_if_fail(to_folder != NULL);
2430 src_node = gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), NULL, from_folder);
2431 from_parent = folder_item_parent(from_folder);
2433 if (prefs_common.warn_dnd) {
2434 buf = g_strdup_printf(copy ? _("Do you really want to copy folder '%s' in '%s' ?"):
2435 _("Do you really want to make folder '%s' a sub-folder of '%s' ?"),
2436 from_folder->name, to_folder->name);
2437 status = alertpanel_full(copy ? _("Copy folder"):_("Move folder"), buf,
2438 GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE,
2439 NULL, ALERT_QUESTION, G_ALERTDEFAULT);
2442 if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
2444 else if (status & G_ALERTDISABLE)
2445 prefs_common.warn_dnd = FALSE;
2448 buf = g_strdup_printf(copy ? _("Copying %s to %s..."):_("Moving %s to %s..."),
2449 from_folder->name, to_folder->name);
2450 STATUSBAR_PUSH(folderview->mainwin, buf);
2452 summary_clear_all(folderview->summaryview);
2453 folderview->opened = NULL;
2454 folderview->selected = NULL;
2455 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2457 main_window_cursor_wait(folderview->mainwin);
2459 statusbar_verbosity_set(FALSE);
2460 folder_item_update_freeze();
2461 if ((status = folder_item_move_to(from_folder, to_folder, &new_folder, copy)) == F_MOVE_OK) {
2462 statusbar_verbosity_set(FALSE);
2463 main_window_cursor_normal(folderview->mainwin);
2464 STATUSBAR_POP(folderview->mainwin);
2465 folder_item_update_thaw();
2466 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2468 folderview_sort_folders(folderview,
2469 gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree),
2470 NULL, to_folder), new_folder->folder);
2471 folderview_select(folderview, new_folder);
2473 statusbar_verbosity_set(FALSE);
2474 main_window_cursor_normal(folderview->mainwin);
2475 STATUSBAR_POP(folderview->mainwin);
2476 folder_item_update_thaw();
2478 case F_MOVE_FAILED_DEST_IS_PARENT:
2479 alertpanel_error(_("Source and destination are the same."));
2481 case F_MOVE_FAILED_DEST_IS_CHILD:
2482 alertpanel_error(copy ? _("Can't copy a folder to one of its children."):
2483 _("Can't move a folder to one of its children."));
2485 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2486 alertpanel_error(_("Folder moving cannot be done between different mailboxes."));
2489 alertpanel_error(copy ? _("Copy failed!"):_("Move failed!"));
2494 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2497 static gint folderview_clist_compare(GtkCList *clist,
2498 gconstpointer ptr1, gconstpointer ptr2)
2500 FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
2501 FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
2504 return (item2->name != NULL);
2508 return g_utf8_collate(item1->name, item2->name);
2511 static void folderview_processing_cb(FolderView *folderview, guint action,
2514 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2518 if (!folderview->selected) return;
2520 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2521 g_return_if_fail(item != NULL);
2522 g_return_if_fail(item->folder != NULL);
2524 id = folder_item_get_identifier(item);
2525 title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2528 prefs_filtering_open(&item->prefs->processing, title,
2529 MANUAL_ANCHOR_PROCESSING, NULL, NULL, FALSE);
2533 void folderview_set_target_folder_color(gint color_op)
2537 FolderView *folderview;
2539 for (list = folderview_list; list != NULL; list = list->next) {
2540 folderview = (FolderView *)list->data;
2541 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2543 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2544 folderview->color_op;
2550 static gchar *last_font = NULL;
2551 void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
2559 void folderview_reflect_prefs(void)
2561 gboolean update_font = TRUE;
2562 FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2563 FolderItem *item = folderview_get_selected_item(folderview);
2564 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2565 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2566 gint height = pos->value;
2568 if (last_font && !strcmp(last_font, NORMAL_FONT))
2569 update_font = FALSE;
2572 last_font = g_strdup(NORMAL_FONT);
2575 normal_style = normal_color_style = bold_style =
2576 bold_color_style = bold_tgtfold_style = NULL;
2578 folderview_init(folderview);
2580 gtk_clist_freeze(GTK_CLIST(folderview->ctree));
2581 folderview_column_set_titles(folderview);
2582 folderview_set_all();
2584 g_signal_handlers_block_by_func
2585 (G_OBJECT(folderview->ctree),
2586 G_CALLBACK(folderview_selected), folderview);
2589 GtkCTreeNode *node = gtk_ctree_find_by_row_data(
2590 GTK_CTREE(folderview->ctree), NULL, item);
2592 folderview_select(folderview, item);
2593 folderview->open_folder = FALSE;
2594 folderview->selected = node;
2597 g_signal_handlers_unblock_by_func
2598 (G_OBJECT(folderview->ctree),
2599 G_CALLBACK(folderview_selected), folderview);
2601 pos = gtk_scrolled_window_get_vadjustment(
2602 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2603 gtk_adjustment_set_value(pos, height);
2604 gtk_clist_thaw(GTK_CLIST(folderview->ctree));
2607 static void drag_state_stop(FolderView *folderview)
2609 if (folderview->drag_timer)
2610 g_source_remove(folderview->drag_timer);
2611 folderview->drag_timer = 0;
2612 folderview->drag_node = NULL;
2615 static gint folderview_defer_expand(FolderView *folderview)
2617 if (folderview->drag_node) {
2618 folderview_recollapse_nodes(folderview, folderview->drag_node);
2619 if (folderview->drag_item->collapsed) {
2620 gtk_ctree_expand(GTK_CTREE(folderview->ctree), folderview->drag_node);
2621 folderview->nodes_to_recollapse = g_slist_append
2622 (folderview->nodes_to_recollapse, folderview->drag_node);
2625 folderview->drag_item = NULL;
2626 folderview->drag_timer = 0;
2630 static void drag_state_start(FolderView *folderview, GtkCTreeNode *node, FolderItem *item)
2632 /* the idea is that we call drag_state_start() whenever we want expansion to
2633 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2634 * we need to call drag_state_stop() */
2635 drag_state_stop(folderview);
2636 /* request expansion */
2637 if (0 != (folderview->drag_timer = g_timeout_add
2638 (prefs_common.hover_timeout,
2639 (GtkFunction)folderview_defer_expand,
2641 folderview->drag_node = node;
2642 folderview->drag_item = item;
2646 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2647 FolderView *folderview)
2649 GdkDragContext *context;
2651 g_return_if_fail(folderview != NULL);
2652 if (folderview->selected == NULL) return;
2653 if (folderview->nodes_to_recollapse)
2654 g_slist_free(folderview->nodes_to_recollapse);
2655 folderview->nodes_to_recollapse = NULL;
2656 context = gtk_drag_begin(widget, folderview->target_list,
2657 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2658 gtk_drag_set_icon_default(context);
2661 static void folderview_drag_data_get(GtkWidget *widget,
2662 GdkDragContext *drag_context,
2663 GtkSelectionData *selection_data,
2666 FolderView *folderview)
2670 gchar *source = NULL;
2671 if (info == TARGET_DUMMY) {
2672 for (cur = GTK_CLIST(folderview->ctree)->selection;
2673 cur != NULL; cur = cur->next) {
2674 item = gtk_ctree_node_get_row_data
2675 (GTK_CTREE(folderview->ctree),
2676 GTK_CTREE_NODE(cur->data));
2678 source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2679 gtk_selection_data_set(selection_data,
2680 selection_data->target, 8,
2681 source, strlen(source));
2687 g_warning("unknown info %d\n", info);
2691 gboolean folderview_update_folder(gpointer source, gpointer userdata)
2693 FolderUpdateData *hookdata;
2694 FolderView *folderview;
2698 folderview = (FolderView *) userdata;
2699 g_return_val_if_fail(hookdata != NULL, FALSE);
2700 g_return_val_if_fail(folderview != NULL, FALSE);
2702 ctree = folderview->ctree;
2703 g_return_val_if_fail(ctree != NULL, FALSE);
2705 if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2706 folderview_create_folder_node(folderview, hookdata->item);
2707 else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2708 GtkCTreeNode *node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree),
2709 NULL, folder_item_parent(hookdata->item));
2710 folderview_sort_folders(folderview, node, hookdata->folder);
2711 } else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2714 node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree), NULL, hookdata->item);
2716 gtk_ctree_remove_node(GTK_CTREE(ctree), node);
2717 } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
2718 folderview_set(folderview);
2723 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2724 GdkDragContext *context,
2728 FolderView *folderview)
2731 FolderItem *item = NULL, *src_item = NULL;
2732 GtkCTreeNode *node = NULL;
2733 gboolean acceptable = FALSE;
2734 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2735 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2736 int height = (int)pos->page_size;
2737 int total_height = (int)pos->upper;
2738 int vpos = (int) pos->value;
2740 if (gtk_clist_get_selection_info
2741 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
2742 GtkWidget *srcwidget;
2744 if (y > height - 24 && height + vpos < total_height)
2745 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
2747 if (y < 48 && y > 0)
2748 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
2750 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2751 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2752 src_item = folderview->summaryview->folder_item;
2754 srcwidget = gtk_drag_get_source_widget(context);
2755 if (srcwidget == summary_get_main_widget(folderview->summaryview)) {
2756 /* comes from summaryview */
2757 /* we are copying messages, so only accept folder items that are not
2758 the source item, are no root items and can copy messages */
2759 if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
2760 src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2761 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2763 } else if (srcwidget == folderview->ctree) {
2764 /* comes from folderview */
2765 /* we are moving folder items, only accept folders that are not
2766 the source items and can copy messages and create folder items */
2767 if (item && item->folder && src_item && src_item != item &&
2768 FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2769 FOLDER_CLASS(item->folder)->create_folder != NULL &&
2770 ((FOLDER_TYPE(item->folder) != F_UNKNOWN && FOLDER_TYPE(src_item->folder) != F_UNKNOWN)
2771 || item->folder == src_item->folder))
2774 /* comes from another app */
2775 /* we are adding messages, so only accept folder items that are
2776 no root items and can copy messages */
2777 if (item && item->folder && folder_item_parent(item) != NULL
2778 && FOLDER_CLASS(item->folder)->add_msg != NULL &&
2779 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2784 if (acceptable || (src_item && src_item == item))
2785 drag_state_start(folderview, node, item);
2788 g_signal_handlers_block_by_func
2790 G_CALLBACK(folderview_selected), folderview);
2791 gtk_ctree_select(GTK_CTREE(widget), node);
2792 g_signal_handlers_unblock_by_func
2794 G_CALLBACK(folderview_selected), folderview);
2795 gdk_drag_status(context,
2796 (context->actions == GDK_ACTION_COPY ?
2797 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2799 if (folderview->opened)
2800 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2801 gdk_drag_status(context, 0, time);
2807 static void folderview_drag_leave_cb(GtkWidget *widget,
2808 GdkDragContext *context,
2810 FolderView *folderview)
2812 drag_state_stop(folderview);
2813 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2816 static void free_info (gpointer stuff, gpointer data)
2821 void folderview_finish_dnd(const gchar *data, GdkDragContext *drag_context,
2822 guint time, FolderItem *item)
2825 GSList *msglist = NULL;
2826 list = uri_list_extract_filenames(data);
2827 if (!(item && item->folder && folder_item_parent(item) != NULL
2828 && FOLDER_CLASS(item->folder)->add_msg != NULL))
2830 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2834 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2837 for (tmp = list; tmp != NULL; tmp = tmp->next) {
2838 MsgFileInfo *info = NULL;
2840 if (file_is_email((gchar *)tmp->data)) {
2841 info = g_new0(MsgFileInfo, 1);
2842 info->msginfo = NULL;
2843 info->file = (gchar *)tmp->data;
2844 msglist = g_slist_prepend(msglist, info);
2848 msglist = g_slist_reverse(msglist);
2849 folder_item_add_msgs(item, msglist, FALSE);
2850 g_slist_foreach(msglist, free_info, NULL);
2851 g_slist_free(msglist);
2852 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2854 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2856 list_free_strings(list);
2860 static void folderview_drag_received_cb(GtkWidget *widget,
2861 GdkDragContext *drag_context,
2864 GtkSelectionData *data,
2867 FolderView *folderview)
2870 FolderItem *item = NULL, *src_item;
2873 if (info == TARGET_DUMMY) {
2874 drag_state_stop(folderview);
2875 if ((void *)strstr(data->data, "FROM_OTHER_FOLDER") != (void *)data->data) {
2876 /* comes from summaryview */
2877 if (gtk_clist_get_selection_info
2878 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2881 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2882 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2883 src_item = folderview->summaryview->folder_item;
2885 /* re-check (due to acceptable possibly set for folder moves */
2886 if (!(item && item->folder && item->path && !item->no_select &&
2887 src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) {
2890 if (item && src_item) {
2891 switch (drag_context->action) {
2892 case GDK_ACTION_COPY:
2893 summary_copy_selected_to(folderview->summaryview, item);
2894 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2896 case GDK_ACTION_MOVE:
2897 case GDK_ACTION_DEFAULT:
2899 if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL)
2900 summary_copy_selected_to(folderview->summaryview, item);
2902 summary_move_selected_to(folderview->summaryview, item);
2903 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2906 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2908 /* comes from folderview */
2910 gboolean folder_is_normal = TRUE;
2911 gboolean copy = (drag_context->action == GDK_ACTION_COPY);
2913 source = data->data + 17;
2914 if (gtk_clist_get_selection_info
2915 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0
2917 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2920 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2921 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2922 src_item = folder_find_item_from_identifier(source);
2926 src_item->stype == F_NORMAL &&
2927 !folder_has_parent_of_type(src_item, F_OUTBOX) &&
2928 !folder_has_parent_of_type(src_item, F_DRAFT) &&
2929 !folder_has_parent_of_type(src_item, F_QUEUE) &&
2930 !folder_has_parent_of_type(src_item, F_TRASH);
2931 if (!item || item->no_select || !src_item
2932 || !folder_is_normal) {
2933 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2937 folderview_move_folder(folderview, src_item, item, copy);
2938 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2940 folderview->nodes_to_recollapse = NULL;
2941 } else if (info == TARGET_MAIL_URI_LIST) {
2942 if (gtk_clist_get_selection_info
2943 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2946 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2948 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2951 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2953 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2956 folderview_finish_dnd(data->data, drag_context, time, item);
2960 static void folderview_drag_end_cb(GtkWidget *widget,
2961 GdkDragContext *drag_context,
2962 FolderView *folderview)
2964 drag_state_stop(folderview);
2965 g_slist_free(folderview->nodes_to_recollapse);
2966 folderview->nodes_to_recollapse = NULL;
2969 void folderview_register_popup(FolderViewPopup *fpopup)
2973 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2974 FolderView *folderview = folderviews->data;
2975 GtkItemFactory *factory;
2977 factory = create_ifactory(folderview, fpopup);
2978 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
2980 g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
2983 void folderview_unregister_popup(FolderViewPopup *fpopup)
2987 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2988 FolderView *folderview = folderviews->data;
2990 g_hash_table_remove(folderview->popups, fpopup->klass);
2992 g_hash_table_remove(folderview_popups, fpopup->klass);