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 3 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, see <http://www.gnu.org/licenses/>.
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;
183 static void folderview_select_node (FolderView *folderview,
185 static void folderview_set_folders (FolderView *folderview);
186 static void folderview_sort_folders (FolderView *folderview,
189 static void folderview_append_folder (FolderView *folderview,
191 static void folderview_update_node (FolderView *folderview,
194 static gint folderview_clist_compare (GtkCList *clist,
198 /* callback functions */
199 static gboolean folderview_button_pressed (GtkWidget *ctree,
200 GdkEventButton *event,
201 FolderView *folderview);
202 static gboolean folderview_button_released (GtkWidget *ctree,
203 GdkEventButton *event,
204 FolderView *folderview);
205 static gboolean folderview_key_pressed (GtkWidget *widget,
207 FolderView *folderview);
208 static void folderview_selected (GtkCTree *ctree,
211 FolderView *folderview);
212 static void folderview_tree_expanded (GtkCTree *ctree,
214 FolderView *folderview);
215 static void folderview_tree_collapsed (GtkCTree *ctree,
217 FolderView *folderview);
218 static void folderview_popup_close (GtkMenuShell *menu_shell,
219 FolderView *folderview);
220 static void folderview_col_resized (GtkCList *clist,
223 FolderView *folderview);
225 static void mark_all_read_cb (FolderView *folderview,
229 static void folderview_empty_trash_cb (FolderView *folderview,
233 static void folderview_send_queue_cb (FolderView *folderview,
237 static void folderview_search_cb (FolderView *folderview,
241 static void folderview_property_cb (FolderView *folderview,
245 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
246 GdkDragContext *context,
250 FolderView *folderview);
251 static void folderview_drag_leave_cb (GtkWidget *widget,
252 GdkDragContext *context,
254 FolderView *folderview);
255 static void folderview_drag_received_cb (GtkWidget *widget,
256 GdkDragContext *drag_context,
259 GtkSelectionData *data,
262 FolderView *folderview);
263 static void folderview_start_drag (GtkWidget *widget, gint button, GdkEvent *event,
264 FolderView *folderview);
265 static void folderview_drag_data_get (GtkWidget *widget,
266 GdkDragContext *drag_context,
267 GtkSelectionData *selection_data,
270 FolderView *folderview);
271 static void folderview_drag_end_cb (GtkWidget *widget,
272 GdkDragContext *drag_context,
273 FolderView *folderview);
275 static void folderview_create_folder_node (FolderView *folderview,
277 static gboolean folderview_update_folder (gpointer source,
279 static gboolean folderview_update_item_claws (gpointer source,
281 static void folderview_processing_cb(FolderView *folderview, guint action,
283 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
284 GdkEventButton *event);
286 GHashTable *folderview_popups;
288 static GtkItemFactoryEntry folderview_common_popup_entries[] =
290 {N_("/Mark all re_ad"), NULL, mark_all_read_cb, 0, NULL},
291 {"/---", NULL, NULL, 0, "<Separator>"},
292 {N_("/_Search folder..."), NULL, folderview_search_cb, 0, NULL},
293 {N_("/_Properties..."), NULL, folderview_property_cb, 0, NULL},
294 {N_("/Process_ing..."), NULL, folderview_processing_cb, 0, NULL},
297 static GtkItemFactoryEntry folder_view_trash_popup_entries[] = {
298 {"/------trashsep", NULL, NULL, 0, "<Separator>"},
299 {N_("/Empty _trash..."), NULL, folderview_empty_trash_cb, 0, NULL},
302 static GtkItemFactoryEntry folder_view_queue_popup_entries[] = {
303 {"/------queuesep", NULL, NULL, 0, "<Separator>"},
304 {N_("/Send _queue..."), NULL, folderview_send_queue_cb, 0, NULL},
308 GtkTargetEntry folderview_drag_types[] =
310 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY},
311 {"text/uri-list", 0, TARGET_MAIL_URI_LIST}
314 void folderview_initialize(void)
316 FolderViewPopup *fpopup;
318 GSList *entries = NULL;
320 fpopup = g_new0(FolderViewPopup, 1);
322 n_entries = sizeof(folderview_common_popup_entries) /
323 sizeof(folderview_common_popup_entries[0]);
324 for (i = 0; i < n_entries; i++)
325 entries = g_slist_append(entries, &folderview_common_popup_entries[i]);
327 fpopup->klass = "common";
328 fpopup->path = "<CommonFolder>";
329 fpopup->entries = entries;
330 fpopup->set_sensitivity = NULL;
332 folderview_popups = g_hash_table_new(g_str_hash, g_str_equal);
333 g_hash_table_insert(folderview_popups, "common", fpopup);
336 static GtkItemFactory *create_ifactory(FolderView *folderview, FolderViewPopup *fpopup)
339 GtkItemFactory *factory;
340 FolderViewPopup *fpopup_common;
343 factory = gtk_item_factory_new(GTK_TYPE_MENU, fpopup->path, NULL);
344 gtk_item_factory_set_translate_func(factory, menu_translate,
347 for (entries = fpopup->entries; entries != NULL; entries = g_slist_next(entries))
348 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
350 fpopup_common = g_hash_table_lookup(folderview_popups, "common");
351 if (fpopup_common != fpopup)
352 for (entries = fpopup_common->entries; entries != NULL; entries = g_slist_next(entries))
353 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
355 popup = gtk_item_factory_get_widget(factory, fpopup->path);
356 g_signal_connect(G_OBJECT(popup), "selection_done",
357 G_CALLBACK(folderview_popup_close),
363 static void create_ifactories(gpointer key, gpointer value, gpointer data)
365 FolderView *folderview = data;
366 FolderViewPopup *fpopup = value;
367 GtkItemFactory *factory;
369 factory = create_ifactory(folderview, fpopup);
370 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
373 static void folderview_column_set_titles(FolderView *folderview)
375 GtkWidget *ctree = folderview->ctree;
376 GtkWidget *label_new;
377 GtkWidget *label_unread;
378 GtkWidget *label_total;
380 GtkWidget *hbox_unread;
381 GtkWidget *hbox_total;
382 gint *col_pos = folderview->col_pos;
384 debug_print("setting titles...\n");
385 gtk_widget_realize(folderview->ctree);
386 gtk_widget_show_all(folderview->scrolledwin);
388 /* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
389 * instead text (text overflows making them unreadable and ugly) */
390 stock_pixmap_gdk(ctree, STOCK_PIXMAP_NEW,
391 &newxpm, &newxpmmask);
392 stock_pixmap_gdk(ctree, STOCK_PIXMAP_UNREAD,
393 &unreadxpm, &unreadxpmmask);
394 stock_pixmap_gdk(ctree, STOCK_PIXMAP_READ,
395 &readxpm, &readxpmmask);
397 label_new = gtk_image_new_from_pixmap(newxpm, newxpmmask);
398 label_unread = gtk_image_new_from_pixmap(unreadxpm, unreadxpmmask);
399 label_total = gtk_image_new_from_pixmap(readxpm, readxpmmask);
401 gtk_clist_column_titles_active(GTK_CLIST(ctree));
403 hbox_new = gtk_hbox_new(FALSE, 4);
404 hbox_unread = gtk_hbox_new(FALSE, 4);
405 hbox_total = gtk_hbox_new(FALSE, 4);
408 gtk_box_pack_start(GTK_BOX(hbox_new), label_new, TRUE, TRUE, 0);
409 gtk_misc_set_alignment (GTK_MISC (label_new), 1, 0.5);
410 gtk_box_pack_start(GTK_BOX(hbox_unread), label_unread, TRUE, TRUE, 0);
411 gtk_misc_set_alignment (GTK_MISC (label_unread), 1, 0.5);
412 gtk_box_pack_start(GTK_BOX(hbox_total), label_total, TRUE, TRUE, 0);
413 gtk_misc_set_alignment (GTK_MISC (label_total), 1, 0.5);
415 gtk_widget_show_all(hbox_new);
416 gtk_widget_show_all(hbox_unread);
417 gtk_widget_show_all(hbox_total);
419 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_NEW],hbox_new);
420 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_UNREAD],hbox_unread);
421 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_TOTAL],hbox_total);
423 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_NEW], _("New"));
424 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_UNREAD], _("Unread"));
425 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_TOTAL], _("Total"));
428 static gboolean folderview_popup_menu(GtkWidget *widget, gpointer data)
430 FolderView *folderview = (FolderView *)data;
431 GdkEventButton event;
432 if (folderview_get_selected_item(folderview) == NULL)
436 event.time = gtk_get_current_event_time();
438 folderview_set_sens_and_popup_menu(folderview, -1,
445 static GtkWidget *folderview_ctree_create(FolderView *folderview)
449 FolderColumnState *col_state;
450 FolderColumnType type;
451 gchar *titles[N_FOLDER_COLS];
453 GtkWidget *scrolledwin = folderview->scrolledwin;
455 debug_print("creating tree...\n");
456 memset(titles, 0, sizeof(titles));
458 col_state = prefs_folder_column_get_config();
459 memset(titles, 0, sizeof(titles));
461 col_pos = folderview->col_pos;
463 for (i = 0; i < N_FOLDER_COLS; i++) {
464 folderview->col_state[i] = col_state[i];
465 type = col_state[i].type;
469 titles[col_pos[F_COL_FOLDER]] = _("Folder");
470 titles[col_pos[F_COL_NEW]] = _("New");
471 titles[col_pos[F_COL_UNREAD]] = _("Unread");
472 /* TRANSLATORS: This in Number sign in American style */
473 titles[col_pos[F_COL_TOTAL]] = _("#");
475 ctree = gtk_sctree_new_with_titles(N_FOLDER_COLS, col_pos[F_COL_FOLDER],
478 if (prefs_common.show_col_headers == FALSE)
479 gtk_clist_column_titles_hide(GTK_CLIST(ctree));
482 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
483 gtk_clist_set_column_justification(GTK_CLIST(ctree), col_pos[F_COL_NEW],
485 gtk_clist_set_column_justification(GTK_CLIST(ctree),
486 col_pos[F_COL_UNREAD],
488 gtk_clist_set_column_justification(GTK_CLIST(ctree),
489 col_pos[F_COL_TOTAL],
491 if (prefs_common.enable_dotted_lines) {
492 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
493 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
494 GTK_CTREE_EXPANDER_SQUARE);
496 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_NONE);
497 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
498 GTK_CTREE_EXPANDER_TRIANGLE);
501 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
502 gtk_sctree_set_recursive_expand(GTK_SCTREE(ctree), FALSE);
504 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
505 gtk_clist_set_compare_func(GTK_CLIST(ctree), folderview_clist_compare);
507 /* don't let title buttons take key focus */
508 for (i = 0; i < N_FOLDER_COLS; i++) {
509 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[i].button,
511 gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[i],
512 prefs_common.folder_col_size[i]);
513 gtk_clist_set_column_visibility
514 (GTK_CLIST(ctree), i, col_state[i].visible);
517 g_signal_connect(G_OBJECT(ctree), "key_press_event",
518 G_CALLBACK(folderview_key_pressed),
520 g_signal_connect(G_OBJECT(ctree), "button_press_event",
521 G_CALLBACK(folderview_button_pressed),
524 g_signal_connect(G_OBJECT(ctree), "popup-menu",
525 G_CALLBACK(folderview_popup_menu), folderview);
527 gtk_widget_tap_and_hold_setup(GTK_WIDGET(ctree), NULL, NULL,
528 GTK_TAP_AND_HOLD_NONE | GTK_TAP_AND_HOLD_NO_INTERNALS);
529 g_signal_connect(G_OBJECT(ctree), "tap-and-hold",
530 G_CALLBACK(folderview_popup_menu), folderview);
532 g_signal_connect(G_OBJECT(ctree), "button_release_event",
533 G_CALLBACK(folderview_button_released),
535 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
536 G_CALLBACK(folderview_selected), folderview);
538 /* drag-n-dropping folders on maemo is impractical as this
539 * opens the folder almost everytime */
540 g_signal_connect(G_OBJECT(ctree), "start_drag",
541 G_CALLBACK(folderview_start_drag), folderview);
543 g_signal_connect(G_OBJECT(ctree), "drag_data_get",
544 G_CALLBACK(folderview_drag_data_get),
547 g_signal_connect_after(G_OBJECT(ctree), "tree_expand",
548 G_CALLBACK(folderview_tree_expanded),
550 g_signal_connect_after(G_OBJECT(ctree), "tree_collapse",
551 G_CALLBACK(folderview_tree_collapsed),
554 g_signal_connect(G_OBJECT(ctree), "resize_column",
555 G_CALLBACK(folderview_col_resized),
559 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
560 folderview_drag_types, 2,
561 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
562 g_signal_connect(G_OBJECT(ctree), "drag_motion",
563 G_CALLBACK(folderview_drag_motion_cb),
565 g_signal_connect(G_OBJECT(ctree), "drag_leave",
566 G_CALLBACK(folderview_drag_leave_cb),
568 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
569 G_CALLBACK(folderview_drag_received_cb),
571 g_signal_connect(G_OBJECT(ctree), "drag_end",
572 G_CALLBACK(folderview_drag_end_cb),
575 gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
580 void folderview_set_column_order(FolderView *folderview)
583 FolderItem *item = folderview_get_selected_item(folderview);
584 GtkWidget *scrolledwin = folderview->scrolledwin;
586 debug_print("recreating tree...\n");
587 gtk_widget_destroy(folderview->ctree);
589 folderview->ctree = ctree = folderview_ctree_create(folderview);
590 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
591 GTK_CLIST(ctree)->hadjustment);
592 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
593 GTK_CLIST(ctree)->vadjustment);
594 gtk_widget_show(ctree);
596 folderview_set(folderview);
597 folderview_column_set_titles(folderview);
599 folderview_select(folderview,item);
602 FolderView *folderview_create(void)
604 FolderView *folderview;
605 GtkWidget *scrolledwin;
608 debug_print("Creating folder view...\n");
609 folderview = g_new0(FolderView, 1);
611 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
612 gtk_scrolled_window_set_policy
613 (GTK_SCROLLED_WINDOW(scrolledwin),
614 GTK_POLICY_AUTOMATIC,
615 prefs_common.folderview_vscrollbar_policy);
616 gtk_widget_set_size_request(scrolledwin,
617 prefs_common.folderview_width,
618 prefs_common.folderview_height);
620 folderview->scrolledwin = scrolledwin;
621 ctree = folderview_ctree_create(folderview);
623 /* create popup factories */
624 folderview->popups = g_hash_table_new(g_str_hash, g_str_equal);
625 g_hash_table_foreach(folderview_popups, create_ifactories, folderview);
627 folderview->ctree = ctree;
629 folderview->folder_update_callback_id =
630 hooks_register_hook(FOLDER_UPDATE_HOOKLIST, folderview_update_folder, (gpointer) folderview);
631 folderview->folder_item_update_callback_id =
632 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item_claws, (gpointer) folderview);
634 gtk_widget_show_all(scrolledwin);
636 folderview->target_list = gtk_target_list_new(folderview_drag_types, 2);
637 folderview_list = g_list_append(folderview_list, folderview);
638 folderview->deferred_refresh_id = -1;
643 void folderview_init(FolderView *folderview)
645 GtkWidget *ctree = folderview->ctree;
648 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE, &inboxxpm, &inboxxpmmask);
649 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM, &inboxhrmxpm, &inboxhrmxpmmask);
650 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN, &inboxopenxpm, &inboxopenxpmmask);
651 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM, &inboxopenhrmxpm, &inboxopenhrmxpmmask);
652 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE, &outboxxpm, &outboxxpmmask);
653 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM, &outboxhrmxpm, &outboxhrmxpmmask);
654 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN, &outboxopenxpm, &outboxopenxpmmask);
655 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM, &outboxopenhrmxpm, &outboxopenhrmxpmmask);
656 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
657 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM, &folderhrmxpm, &folderhrmxpmmask);
658 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
659 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM, &folderopenhrmxpm, &folderopenhrmxpmmask);
660 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN, &trashopenxpm, &trashopenxpmmask);
661 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM, &trashopenhrmxpm, &trashopenhrmxpmmask);
662 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE, &trashxpm, &trashxpmmask);
663 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM, &trashhrmxpm, &trashhrmxpmmask);
664 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE, &queuexpm, &queuexpmmask);
665 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM, &queuehrmxpm, &queuehrmxpmmask);
666 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN, &queueopenxpm, &queueopenxpmmask);
667 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM, &queueopenhrmxpm, &queueopenhrmxpmmask);
668 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE, &draftsxpm, &draftsxpmmask);
669 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN, &draftsopenxpm, &draftsopenxpmmask);
670 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_NOSELECT, &noselectxpm, &noselectxpmmask);
672 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_MARK, &m_inboxxpm, &m_inboxxpmmask);
673 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK, &m_inboxhrmxpm, &m_inboxhrmxpmmask);
674 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_MARK, &m_inboxopenxpm, &m_inboxopenxpmmask);
675 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM_MARK, &m_inboxopenhrmxpm, &m_inboxopenhrmxpmmask);
676 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_MARK, &m_outboxxpm, &m_outboxxpmmask);
677 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK, &m_outboxhrmxpm, &m_outboxhrmxpmmask);
678 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_MARK, &m_outboxopenxpm, &m_outboxopenxpmmask);
679 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK, &m_outboxopenhrmxpm, &m_outboxopenhrmxpmmask);
680 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_MARK, &m_folderxpm, &m_folderxpmmask);
681 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM_MARK, &m_folderhrmxpm, &m_folderhrmxpmmask);
682 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_MARK, &m_folderopenxpm, &m_folderopenxpmmask);
683 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM_MARK, &m_folderopenhrmxpm, &m_folderopenhrmxpmmask);
684 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_MARK, &m_trashopenxpm, &m_trashopenxpmmask);
685 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM_MARK, &m_trashopenhrmxpm, &m_trashopenhrmxpmmask);
686 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_MARK, &m_trashxpm, &m_trashxpmmask);
687 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK, &m_trashhrmxpm, &m_trashhrmxpmmask);
688 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_MARK, &m_queuexpm, &m_queuexpmmask);
689 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK, &m_queuehrmxpm, &m_queuehrmxpmmask);
690 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_MARK, &m_queueopenxpm, &m_queueopenxpmmask);
691 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK, &m_queueopenhrmxpm, &m_queueopenhrmxpmmask);
692 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE_MARK, &m_draftsxpm, &m_draftsxpmmask);
693 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN_MARK, &m_draftsopenxpm, &m_draftsopenxpmmask);
696 PangoFontDescription *font_desc;
697 normal_style = gtk_style_copy(gtk_widget_get_style(ctree));
698 font_desc = pango_font_description_from_string(NORMAL_FONT);
700 if (normal_style->font_desc)
701 pango_font_description_free
702 (normal_style->font_desc);
703 normal_style->font_desc = font_desc;
705 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
706 normal_color_style = gtk_style_copy(normal_style);
707 normal_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
709 gtk_widget_set_style(ctree, normal_style);
713 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
714 bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
715 pango_font_description_set_weight
716 (bold_style->font_desc, PANGO_WEIGHT_BOLD);
717 bold_color_style = gtk_style_copy(bold_style);
718 bold_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
720 bold_tgtfold_style = gtk_style_copy(bold_style);
721 bold_tgtfold_style->fg[GTK_STATE_NORMAL] = folderview->color_op;
725 static gboolean folderview_defer_set(gpointer data)
727 FolderView *folderview = (FolderView *)data;
728 MainWindow *mainwin = folderview->mainwin;
732 if (mainwin->lock_count)
735 printf("doing deferred folderview_set now\n");
736 folderview_set(folderview);
738 folderview->deferred_refresh_id = -1;
742 void folderview_set(FolderView *folderview)
744 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
745 MainWindow *mainwin = folderview->mainwin;
746 FolderItem *sel_item = NULL, *op_item = NULL;
751 if (mainwin->lock_count) {
752 if (folderview->deferred_refresh_id == -1)
753 folderview->deferred_refresh_id =
754 g_timeout_add(500, folderview_defer_set, folderview);
755 printf("deferred folderview_set\n");
760 debug_print("Setting folder info...\n");
761 STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
763 main_window_cursor_wait(mainwin);
765 if (folderview->selected)
766 sel_item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
767 if (folderview->opened)
768 op_item = gtk_ctree_node_get_row_data(ctree, folderview->opened);
770 folderview->selected = NULL;
771 folderview->opened = NULL;
773 gtk_clist_freeze(GTK_CLIST(ctree));
774 gtk_clist_clear(GTK_CLIST(ctree));
776 folderview_set_folders(folderview);
779 folderview->selected = gtk_ctree_find_by_row_data(ctree, NULL, sel_item);
781 folderview->opened = gtk_ctree_find_by_row_data(ctree, NULL, op_item);
783 gtk_clist_thaw(GTK_CLIST(ctree));
784 main_window_cursor_normal(mainwin);
785 STATUSBAR_POP(mainwin);
789 void folderview_set_all(void)
793 for (list = folderview_list; list != NULL; list = list->next)
794 folderview_set((FolderView *)list->data);
797 void folderview_select(FolderView *folderview, FolderItem *item)
799 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
801 GtkCTreeNode *old_selected = folderview->selected;
805 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
806 if (node) folderview_select_node(folderview, node);
808 if (old_selected != node)
809 folder_update_op_count();
812 static void mark_all_read_cb(FolderView *folderview, guint action,
818 item = folderview_get_selected_item(folderview);
822 if (folderview->summaryview->folder_item != item
823 && prefs_common.ask_mark_all_read) {
824 val = alertpanel_full(_("Mark all as read"),
825 _("Do you really want to mark all mails in this "
826 "folder as read ?"), GTK_STOCK_NO, GTK_STOCK_YES, NULL,
827 TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT);
829 if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
831 else if (val & G_ALERTDISABLE)
832 prefs_common.ask_mark_all_read = FALSE;
835 summary_lock(folderview->summaryview);
836 folder_item_update_freeze();
837 if (folderview->summaryview->folder_item == item)
838 summary_freeze(folderview->summaryview);
839 folderutils_mark_all_read(item);
840 if (folderview->summaryview->folder_item == item)
841 summary_thaw(folderview->summaryview);
842 folder_item_update_thaw();
843 summary_unlock(folderview->summaryview);
846 static void folderview_select_node(FolderView *folderview, GtkCTreeNode *node)
848 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
850 g_return_if_fail(node != NULL);
852 if (folderview->open_folder) {
856 folderview->open_folder = TRUE;
857 gtkut_ctree_set_focus_row(ctree, node);
858 gtk_ctree_select(ctree, node);
859 if (folderview->summaryview->folder_item &&
860 folderview->summaryview->folder_item->total_msgs > 0)
861 summary_grab_focus(folderview->summaryview);
863 gtk_widget_grab_focus(folderview->ctree);
865 gtkut_ctree_expand_parent_all(ctree, node);
868 void folderview_unselect(FolderView *folderview)
870 if (folderview->opened && !GTK_CTREE_ROW(folderview->opened)->children)
872 (GTK_CTREE(folderview->ctree), folderview->opened);
874 folderview->selected = folderview->opened = NULL;
877 static GtkCTreeNode *folderview_find_next_marked(GtkCTree *ctree,
883 node = gtkut_ctree_node_next(ctree, node);
885 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
887 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
888 item = gtk_ctree_node_get_row_data(ctree, node);
889 if (item && item->marked_msgs > 0 && item->stype != F_TRASH)
896 void folderview_select_next_marked(FolderView *folderview)
898 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
899 GtkCTreeNode *node = NULL;
900 EntryAction last_summary_select_prio = prefs_common.summary_select_prio[0];
901 gboolean last_open = prefs_common.always_show_msg;
903 prefs_common.summary_select_prio[0] = ACTION_MARKED;
904 prefs_common.always_show_msg = TRUE;
906 if ((node = folderview_find_next_marked(ctree, folderview->opened))
908 folderview_select_node(folderview, node);
912 if (!folderview->opened ||
913 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
916 /* search again from the first node */
917 if ((node = folderview_find_next_marked(ctree, NULL)) != NULL)
918 folderview_select_node(folderview, node);
921 prefs_common.summary_select_prio[0] = last_summary_select_prio;
922 prefs_common.always_show_msg = last_open;
925 static GtkCTreeNode *folderview_find_next_unread(GtkCTree *ctree,
931 node = gtkut_ctree_node_next(ctree, node);
933 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
935 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
936 item = gtk_ctree_node_get_row_data(ctree, node);
937 if (item && item->unread_msgs > 0 && item->stype != F_TRASH)
944 void folderview_select_next_unread(FolderView *folderview, gboolean force_open)
946 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
947 GtkCTreeNode *node = NULL;
948 EntryAction last_summary_select_prio = prefs_common.summary_select_prio[0];
949 gboolean last_open = prefs_common.always_show_msg;
951 prefs_common.summary_select_prio[0] = ACTION_UNREAD;
952 prefs_common.always_show_msg = force_open ? TRUE : last_open;
954 if ((node = folderview_find_next_unread(ctree, folderview->opened))
956 folderview_select_node(folderview, node);
960 if (!folderview->opened ||
961 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
964 /* search again from the first node */
965 if ((node = folderview_find_next_unread(ctree, NULL)) != NULL)
966 folderview_select_node(folderview, node);
969 prefs_common.summary_select_prio[0] = last_summary_select_prio;
970 prefs_common.always_show_msg = last_open;
973 static GtkCTreeNode *folderview_find_next_new(GtkCTree *ctree,
979 node = gtkut_ctree_node_next(ctree, node);
981 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
983 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
984 item = gtk_ctree_node_get_row_data(ctree, node);
985 if (item && item->new_msgs > 0 && item->stype != F_TRASH)
992 void folderview_select_next_new(FolderView *folderview)
994 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
995 GtkCTreeNode *node = NULL;
996 EntryAction last_summary_select_prio = prefs_common.summary_select_prio[0];
997 gboolean last_open = prefs_common.always_show_msg;
999 prefs_common.summary_select_prio[0] = ACTION_NEW;
1000 prefs_common.always_show_msg = TRUE;
1002 if ((node = folderview_find_next_new(ctree, folderview->opened))
1004 folderview_select_node(folderview, node);
1008 if (!folderview->opened ||
1009 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
1012 /* search again from the first node */
1013 if ((node = folderview_find_next_new(ctree, NULL)) != NULL)
1014 folderview_select_node(folderview, node);
1017 prefs_common.summary_select_prio[0] = last_summary_select_prio;
1018 prefs_common.always_show_msg = last_open;
1021 FolderItem *folderview_get_selected_item(FolderView *folderview)
1023 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1025 if (!folderview->selected) return NULL;
1026 return gtk_ctree_node_get_row_data(ctree, folderview->selected);
1029 static void folderview_set_folders(FolderView *folderview)
1032 list = folder_get_list();
1034 for (; list != NULL; list = list->next) {
1035 folderview_append_folder(folderview, FOLDER(list->data));
1039 static gchar *get_scan_str(FolderItem *item)
1042 return g_strdup_printf(_("Scanning folder %s%c%s ..."),
1043 item->folder->name, G_DIR_SEPARATOR,
1046 return g_strdup_printf(_("Scanning folder %s ..."),
1047 item->folder->name);
1049 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
1053 for (list = folderview_list; list != NULL; list = list->next) {
1054 FolderView *folderview = (FolderView *)list->data;
1055 MainWindow *mainwin = folderview->mainwin;
1056 gchar *str = get_scan_str(item);
1058 STATUSBAR_PUSH(mainwin, str);
1059 STATUSBAR_POP(mainwin);
1064 void folderview_rescan_tree(Folder *folder, gboolean rebuild)
1067 MainWindow *mainwin = mainwindow_get_mainwindow();
1068 FolderView *folderview = NULL;
1069 GtkAdjustment *pos = NULL;
1072 g_return_if_fail(folder != NULL);
1074 if (!folder->klass->scan_tree) return;
1077 alertpanel_full(_("Rebuild folder tree"),
1078 _("Rebuilding the folder tree will remove "
1079 "local caches. Do you want to continue?"),
1080 GTK_STOCK_NO, GTK_STOCK_YES, NULL, FALSE,
1081 NULL, ALERT_WARNING, G_ALERTDEFAULT)
1082 != G_ALERTALTERNATE) {
1088 window = label_window_create(_("Rebuilding folder tree..."));
1090 window = label_window_create(_("Scanning folder tree..."));
1093 folderview = mainwin->folderview;
1096 pos = gtk_scrolled_window_get_vadjustment(
1097 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1098 height = pos->value;
1101 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1102 folder_scan_tree(folder, rebuild);
1103 folder_set_ui_func(folder, NULL, NULL);
1105 folderview_set_all();
1108 pos = gtk_scrolled_window_get_vadjustment(
1109 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1110 gtk_adjustment_set_value(pos, height);
1112 label_window_destroy(window);
1116 void folderview_fast_rescan_tree(Folder *folder)
1119 MainWindow *mainwin = mainwindow_get_mainwindow();
1120 FolderView *folderview = NULL;
1121 GtkAdjustment *pos = NULL;
1124 g_return_if_fail(folder != NULL);
1126 if (!folder->klass->scan_tree) return;
1130 window = label_window_create(_("Scanning folder tree..."));
1133 folderview = mainwin->folderview;
1136 pos = gtk_scrolled_window_get_vadjustment(
1137 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1138 height = pos->value;
1141 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1142 folder_fast_scan_tree(folder);
1143 folder_set_ui_func(folder, NULL, NULL);
1145 folderview_set_all();
1148 pos = gtk_scrolled_window_get_vadjustment(
1149 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1150 gtk_adjustment_set_value(pos, height);
1152 label_window_destroy(window);
1156 /** folderview_check_new()
1157 * Scan and update the folder and return the
1158 * count the number of new messages since last check.
1159 * \param folder the folder to check for new messages
1160 * \return the number of new messages since last check
1162 gint folderview_check_new(Folder *folder)
1166 FolderView *folderview;
1170 gint former_new_msgs = 0;
1171 gint former_new = 0, former_unread = 0, former_total;
1173 for (list = folderview_list; list != NULL; list = list->next) {
1174 folderview = (FolderView *)list->data;
1175 ctree = GTK_CTREE(folderview->ctree);
1178 main_window_lock(folderview->mainwin);
1180 for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1181 node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
1183 item = gtk_ctree_node_get_row_data(ctree, node);
1184 if (!item || !item->path || !item->folder) continue;
1185 if (item->no_select) continue;
1186 if (folder && folder != item->folder) continue;
1187 if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
1188 if (!item->prefs->newmailcheck) continue;
1189 if (item->processing_pending == TRUE) {
1190 debug_print("skipping %s, processing pending\n",
1191 item->path ? item->path : item->name);
1195 str = get_scan_str(item);
1197 STATUSBAR_PUSH(folderview->mainwin, str);
1201 folderview_scan_tree_func(item->folder, item, NULL);
1202 former_new = item->new_msgs;
1203 former_unread = item->unread_msgs;
1204 former_total = item->total_msgs;
1206 if (item->folder->klass->scan_required &&
1207 (item->folder->klass->scan_required(item->folder, item) ||
1208 item->folder->inbox == item ||
1209 item->opened == TRUE ||
1210 item->processing_pending == TRUE)) {
1211 if (folder_item_scan(item) < 0) {
1213 summaryview_unlock(folderview->summaryview, item);
1214 if (FOLDER_TYPE(item->folder) == F_NEWS || FOLDER_IS_LOCAL(folder)) {
1215 log_error(LOG_PROTOCOL, _("Couldn't scan folder %s\n"),
1216 item->path ? item->path:item->name);
1217 STATUSBAR_POP(folderview->mainwin);
1219 } else if (!FOLDER_IS_LOCAL(folder)) {
1220 STATUSBAR_POP(folderview->mainwin);
1225 } else if (!item->folder->klass->scan_required) {
1226 if (folder_item_scan(item) < 0) {
1227 summaryview_unlock(folderview->summaryview, item);
1228 if (folder && !FOLDER_IS_LOCAL(folder)) {
1229 STATUSBAR_POP(folderview->mainwin);
1234 if (former_new != item->new_msgs ||
1235 former_unread != item->unread_msgs ||
1236 former_total != item->total_msgs)
1237 folderview_update_node(folderview, node);
1239 new_msgs += item->new_msgs;
1240 former_new_msgs += former_new;
1241 STATUSBAR_POP(folderview->mainwin);
1244 main_window_unlock(folderview->mainwin);
1248 folder_write_list();
1249 /* Number of new messages since last check is the just the difference
1250 * between former_new_msgs and new_msgs. If new_msgs is less than
1251 * former_new_msgs, that would mean another session accessed the folder
1252 * and the result is not well defined.
1254 new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
1258 void folderview_check_new_all(void)
1262 FolderView *folderview;
1264 folderview = (FolderView *)folderview_list->data;
1267 main_window_lock(folderview->mainwin);
1268 window = label_window_create
1269 (_("Checking for new messages in all folders..."));
1271 list = folder_get_list();
1272 for (; list != NULL; list = list->next) {
1273 Folder *folder = list->data;
1275 folderview_check_new(folder);
1278 folder_write_list();
1279 folderview_set_all();
1281 label_window_destroy(window);
1282 main_window_unlock(folderview->mainwin);
1286 static gboolean folderview_have_new_children_sub(FolderView *folderview,
1292 if (!item || !item->folder || !item->folder->node)
1295 node = item->folder->node;
1297 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1298 node = node->children;
1301 (item->new_msgs > 0 ||
1302 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1306 while (node != NULL) {
1307 if (node && node->data) {
1308 FolderItem *next_item = (FolderItem*) node->data;
1310 if (folderview_have_new_children_sub(folderview,
1319 static gboolean folderview_have_new_children(FolderView *folderview,
1322 return folderview_have_new_children_sub(folderview, item, FALSE);
1325 static gboolean folderview_have_unread_children_sub(FolderView *folderview,
1331 if (!item || !item->folder || !item->folder->node)
1334 node = item->folder->node;
1336 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1337 node = node->children;
1340 (item->unread_msgs > 0 ||
1341 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1345 while (node != NULL) {
1346 if (node && node->data) {
1347 FolderItem *next_item = (FolderItem*) node->data;
1349 if (folderview_have_unread_children_sub(folderview,
1359 static gboolean folderview_have_unread_children(FolderView *folderview,
1362 return folderview_have_unread_children_sub(folderview, item, FALSE);
1365 static gboolean folderview_have_matching_children_sub(FolderView *folderview,
1371 if (!item || !item->folder || !item->folder->node)
1374 node = item->folder->node;
1376 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1377 node = node->children;
1379 if (in_sub && item->search_match){
1383 while (node != NULL) {
1384 if (node && node->data) {
1385 FolderItem *next_item = (FolderItem*) node->data;
1387 if (folderview_have_matching_children_sub(folderview,
1397 static gboolean folderview_have_matching_children(FolderView *folderview,
1400 return folderview_have_matching_children_sub(folderview, item, FALSE);
1403 static gboolean folderview_have_marked_children_sub(FolderView *folderview,
1409 if (!item || !item->folder || !item->folder->node)
1412 node = item->folder->node;
1414 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1415 node = node->children;
1417 if (item->marked_msgs != 0) {
1421 while (node != NULL) {
1422 if (node && node->data) {
1423 FolderItem *next_item = (FolderItem*) node->data;
1425 if (folderview_have_marked_children_sub(folderview,
1434 static gboolean folderview_have_marked_children(FolderView *folderview,
1437 return folderview_have_marked_children_sub(folderview, item, FALSE);
1440 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
1442 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1443 GtkStyle *style = NULL;
1444 GtkStyle *color_style = NULL;
1446 GdkPixmap *xpm, *openxpm;
1447 GdkBitmap *mask, *openmask;
1448 static GdkPixmap *searchicon;
1449 static GdkBitmap *searchmask;
1450 gboolean mark = FALSE;
1453 gboolean add_unread_mark;
1454 gboolean add_sub_match_mark;
1455 gboolean use_bold, use_color;
1456 gint *col_pos = folderview->col_pos;
1457 SpecialFolderItemType stype;
1459 item = gtk_ctree_node_get_row_data(ctree, node);
1460 g_return_if_fail(item != NULL);
1462 if (!GTK_CTREE_ROW(node)->expanded)
1463 mark = folderview_have_marked_children(folderview, item);
1465 mark = (item->marked_msgs != 0);
1467 stype = item->stype;
1468 if (stype == F_NORMAL) {
1469 if (folder_has_parent_of_type(item, F_TRASH))
1471 else if (folder_has_parent_of_type(item, F_DRAFT))
1473 else if (folder_has_parent_of_type(item, F_OUTBOX))
1475 else if (folder_has_parent_of_type(item, F_QUEUE))
1480 if (item->hide_read_msgs) {
1481 xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
1482 mask = mark?m_inboxhrmxpmmask:inboxhrmxpmmask;
1483 openxpm = mark?m_inboxopenhrmxpm:inboxopenhrmxpm;
1484 openmask = mark?m_inboxopenhrmxpmmask:inboxopenhrmxpmmask;
1486 xpm = mark?m_inboxxpm:inboxxpm;
1487 mask = mark?m_inboxxpmmask:inboxxpmmask;
1488 openxpm = mark?m_inboxopenxpm:inboxopenxpm;
1489 openmask = mark?m_inboxopenxpmmask:inboxopenxpmmask;
1493 if (item->hide_read_msgs) {
1494 xpm = mark?m_outboxhrmxpm:outboxhrmxpm;
1495 mask = mark?m_outboxhrmxpmmask:outboxhrmxpmmask;
1496 openxpm = mark?m_outboxopenhrmxpm:outboxopenhrmxpm;
1497 openmask = mark?m_outboxopenhrmxpmmask:outboxopenhrmxpmmask;
1499 xpm = mark?m_outboxxpm:outboxxpm;
1500 mask = mark?m_outboxxpmmask:outboxxpmmask;
1501 openxpm = mark?m_outboxopenxpm:outboxopenxpm;
1502 openmask = mark?m_outboxopenxpmmask:outboxopenxpmmask;
1506 if (item->hide_read_msgs) {
1507 xpm = mark?m_queuehrmxpm:queuehrmxpm;
1508 mask = mark?m_queuehrmxpmmask:queuehrmxpmmask;
1509 openxpm = mark?m_queueopenhrmxpm:queueopenhrmxpm;
1510 openmask = mark?m_queueopenhrmxpmmask:queueopenhrmxpmmask;
1512 xpm = mark?m_queuexpm:queuexpm;
1513 mask = mark?m_queuexpmmask:queuexpmmask;
1514 openxpm = mark?m_queueopenxpm:queueopenxpm;
1515 openmask = mark?m_queueopenxpmmask:queueopenxpmmask;
1519 if (item->hide_read_msgs) {
1520 xpm = mark?m_trashhrmxpm:trashhrmxpm;
1521 mask = mark?m_trashhrmxpmmask:trashhrmxpmmask;
1522 openxpm = mark?m_trashopenhrmxpm:trashopenhrmxpm;
1523 openmask = mark?m_trashopenhrmxpmmask:trashopenhrmxpmmask;
1525 xpm = mark?m_trashxpm:trashxpm;
1526 mask = mark?m_trashxpmmask:trashxpmmask;
1527 openxpm = mark?m_trashopenxpm:trashopenxpm;
1528 openmask = mark?m_trashopenxpmmask:trashopenxpmmask;
1532 xpm = mark?m_draftsxpm:draftsxpm;
1533 mask = mark?m_draftsxpmmask:draftsxpmmask;
1534 openxpm = mark?m_draftsopenxpm:draftsopenxpm;
1535 openmask = mark?m_draftsopenxpmmask:draftsopenxpmmask;
1538 if (item->hide_read_msgs) {
1539 xpm = mark?m_folderhrmxpm:folderhrmxpm;
1540 mask = mark?m_folderhrmxpmmask:folderhrmxpmmask;
1541 openxpm = mark?m_folderopenhrmxpm:folderopenhrmxpm;
1542 openmask = mark?m_folderopenhrmxpmmask:folderopenhrmxpmmask;
1544 xpm = mark?m_folderxpm:folderxpm;
1545 mask = mark?m_folderxpmmask:folderxpmmask;
1546 openxpm = mark?m_folderopenxpm:folderopenxpm;
1547 openmask = mark?m_folderopenxpmmask:folderopenxpmmask;
1551 if (item->no_select) {
1552 xpm = openxpm = noselectxpm;
1553 mask = openmask = noselectxpmmask;
1556 name = folder_item_get_name(item);
1558 if (!GTK_CTREE_ROW(node)->expanded) {
1559 add_unread_mark = folderview_have_unread_children(
1561 add_sub_match_mark = folderview_have_matching_children(
1564 add_unread_mark = FALSE;
1565 add_sub_match_mark = FALSE;
1568 if (item->search_match) {
1570 stock_pixmap_gdk(folderview->ctree, STOCK_PIXMAP_QUICKSEARCH,
1571 &searchicon, &searchmask);
1573 xpm = openxpm = searchicon;
1574 mask = openmask = searchmask;
1578 if (prefs_common.display_folder_unread) {
1579 if (folder_has_parent_of_type(item, F_QUEUE)) {
1580 /* only total_msgs matters here */
1581 if (item->total_msgs > 0) {
1582 /* show total number (should be equal to the unread number)
1584 str = g_strdup_printf("%s (%d%s%s)",
1585 name, item->total_msgs,
1586 (add_unread_mark || add_sub_match_mark) ? "+" : "",
1587 (item->unreadmarked_msgs > 0) ? "!" : "");
1590 if (prefs_common.display_folder_unread == 1) {
1591 if (item->unread_msgs > 0) {
1592 /* show unread number and signs */
1593 str = g_strdup_printf("%s (%d%s%s)",
1594 name, item->unread_msgs,
1595 (add_unread_mark || add_sub_match_mark) ? "+" : "",
1596 (item->unreadmarked_msgs > 0) ? "!" : "");
1599 if (item->total_msgs > 0) {
1600 /* show unread number, total number and signs if any */
1601 str = g_strdup_printf("%s (%d/%d%s%s)",
1602 name, item->unread_msgs, item->total_msgs,
1603 (add_unread_mark || add_sub_match_mark) ? "+" : "",
1604 (item->unreadmarked_msgs > 0) ? "!" : "");
1608 if ((str == NULL) &&
1609 (add_unread_mark || add_sub_match_mark || (item->unreadmarked_msgs > 0))) {
1610 /* no unread/total numbers, but at least one sign */
1611 str = g_strdup_printf("%s (%s%s)",
1613 (add_unread_mark || add_sub_match_mark) ? "+" : "",
1614 (item->unreadmarked_msgs > 0) ? "!" : "");
1618 /* last fallback, folder name only or with ! sign */
1619 str = g_strdup_printf("%s%s",
1620 name, (item->unreadmarked_msgs > 0) ? " (!)" : "");
1622 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1623 xpm, mask, openxpm, openmask,
1624 FALSE, GTK_CTREE_ROW(node)->expanded);
1628 if (!folder_item_parent(item)) {
1629 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], "-");
1630 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
1631 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], "-");
1633 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], item->new_msgs > 0 ? itos(item->new_msgs) : prefs_common.zero_replacement);
1634 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], item->unread_msgs > 0 ? itos(item->unread_msgs) : prefs_common.zero_replacement);
1635 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], item->total_msgs > 0 ? itos(item->total_msgs) : prefs_common.zero_replacement);
1638 if (folder_has_parent_of_type(item, F_OUTBOX) ||
1639 folder_has_parent_of_type(item, F_DRAFT) ||
1640 folder_has_parent_of_type(item, F_TRASH)) {
1641 use_bold = use_color = FALSE;
1642 } else if (folder_has_parent_of_type(item, F_QUEUE)) {
1643 /* highlight queue folder if there are any messages */
1644 use_bold = use_color = (item->total_msgs > 0);
1646 /* if unread messages exist, print with bold font */
1647 use_bold = (item->unread_msgs > 0|| item->new_msgs > 0)
1649 /* if new messages exist, print with colored letter */
1651 (item->new_msgs > 0) ||
1653 folderview_have_new_children(folderview, item));
1656 gtk_ctree_node_set_foreground(ctree, node, NULL);
1661 if (item->prefs->color > 0 && !use_color) {
1662 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1663 color_style = gtk_style_copy(bold_style);
1664 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1665 style = color_style;
1666 } else if (use_color) {
1667 style = bold_color_style;
1670 if (item->op_count > 0) {
1671 style = bold_tgtfold_style;
1673 } else if (use_color) {
1674 style = normal_color_style;
1675 gtk_ctree_node_set_foreground(ctree, node,
1676 &folderview->color_new);
1677 } else if (item->op_count > 0) {
1678 style = bold_tgtfold_style;
1679 } else if (item->prefs->color > 0) {
1681 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1682 color_style = gtk_style_copy(normal_style);
1683 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1684 style = color_style;
1686 style = normal_style;
1689 gtk_ctree_node_set_row_style(ctree, node, style);
1691 if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1692 folderview_update_node(folderview, node);
1695 void folderview_update_search_icon(FolderItem *item, gboolean matches)
1698 FolderView *folderview;
1702 g_return_if_fail(item != NULL);
1704 for (list = folderview_list; list != NULL; list = list->next) {
1705 folderview = (FolderView *)list->data;
1706 ctree = GTK_CTREE(folderview->ctree);
1708 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1710 item->search_match = matches;
1711 folderview_update_node(folderview, node);
1716 static gboolean folderview_update_item_claws(gpointer source, gpointer data)
1718 FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1719 FolderView *folderview = (FolderView *)data;
1722 g_return_val_if_fail(update_info != NULL, TRUE);
1723 g_return_val_if_fail(update_info->item != NULL, TRUE);
1724 g_return_val_if_fail(folderview != NULL, FALSE);
1726 ctree = GTK_CTREE(folderview->ctree);
1728 node = gtk_ctree_find_by_row_data(ctree, NULL, update_info->item);
1731 if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
1732 folderview_update_node(folderview, node);
1734 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) &&
1735 update_info->item == folderview->summaryview->folder_item &&
1736 update_info->item != NULL)
1737 if (!quicksearch_is_active(folderview->summaryview->quicksearch))
1738 summary_show(folderview->summaryview, update_info->item);
1744 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1745 GNode *gnode, GtkCTreeNode *cnode,
1748 FolderView *folderview = (FolderView *)data;
1749 FolderItem *item = FOLDER_ITEM(gnode->data);
1751 g_return_val_if_fail(item != NULL, FALSE);
1753 gtk_ctree_node_set_row_data(ctree, cnode, item);
1754 folderview_update_node(folderview, cnode);
1759 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1762 FolderView *folderview = (FolderView *)data;
1765 if (GTK_CTREE_ROW(node)->children) {
1766 item = gtk_ctree_node_get_row_data(ctree, node);
1767 g_return_if_fail(item != NULL);
1769 if (!item->collapsed)
1770 gtk_ctree_expand(ctree, node);
1772 folderview_update_node(folderview, node);
1776 static void set_special_folder(GtkCTree *ctree, FolderItem *item,
1777 GtkCTreeNode *root, GtkCTreeNode **prev)
1780 GtkCTreeNode *node, *parent, *sibling;
1782 node = gtk_ctree_find_by_row_data(ctree, root, item);
1784 g_warning("%s not found.\n", item->path);
1786 parent = GTK_CTREE_ROW(node)->parent;
1787 if (*prev && parent == GTK_CTREE_ROW(*prev)->parent)
1788 sibling = GTK_CTREE_ROW(*prev)->sibling;
1790 sibling = GTK_CTREE_ROW(parent)->children;
1794 tmp = gtk_ctree_node_get_row_data
1796 if (tmp->stype != F_NORMAL)
1797 sibling = GTK_CTREE_ROW(sibling)->sibling;
1801 if (node != sibling)
1802 gtk_ctree_move(ctree, node, parent, sibling);
1809 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1812 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1813 GtkCTreeNode *prev = NULL;
1815 gtk_clist_freeze(GTK_CLIST(ctree));
1816 gtk_sctree_sort_recursive(ctree, root);
1817 if (root && GTK_CTREE_ROW(root)->parent) {
1818 gtk_clist_thaw(GTK_CLIST(ctree));
1821 set_special_folder(ctree, folder->inbox, root, &prev);
1822 set_special_folder(ctree, folder->outbox, root, &prev);
1823 set_special_folder(ctree, folder->draft, root, &prev);
1824 set_special_folder(ctree, folder->queue, root, &prev);
1825 set_special_folder(ctree, folder->trash, root, &prev);
1826 gtk_clist_thaw(GTK_CLIST(ctree));
1829 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1831 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1834 g_return_if_fail(folder != NULL);
1836 root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
1837 folderview_gnode_func, folderview);
1838 gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1840 folderview_sort_folders(folderview, root, folder);
1843 /* callback functions */
1844 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
1845 GdkEventButton *event)
1847 GtkCList *clist = GTK_CLIST(folderview->ctree);
1850 FolderViewPopup *fpopup;
1851 GtkItemFactory *fpopup_factory;
1853 FolderItem *special_trash = NULL, *special_queue = NULL;
1857 item = gtk_clist_get_row_data(clist, row);
1859 item = folderview_get_selected_item(folderview);
1861 g_return_if_fail(item != NULL);
1862 g_return_if_fail(item->folder != NULL);
1863 folder = item->folder;
1865 fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1867 fpopup_factory = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1869 fpopup = g_hash_table_lookup(folderview_popups, "common");
1870 fpopup_factory = g_hash_table_lookup(folderview->popups, "common");
1873 if (fpopup->set_sensitivity != NULL)
1874 fpopup->set_sensitivity(fpopup_factory, item);
1876 if (NULL != (ac = account_find_from_item(item))) {
1877 special_trash = account_get_special_folder(ac, F_TRASH);
1878 special_queue = account_get_special_folder(ac, F_QUEUE);
1881 if ((item == folder->trash || item == special_trash
1882 || folder_has_parent_of_type(item, F_TRASH)) &&
1883 gtk_item_factory_get_item(fpopup_factory, "/Empty trash...") == NULL) {
1884 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[0], folderview, 1);
1885 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[1], folderview, 1);
1886 } else if (item != folder->trash && (special_trash == NULL || item != special_trash)
1887 && !folder_has_parent_of_type(item, F_TRASH)) {
1888 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[0]);
1889 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[1]);
1892 if ((item == folder->queue || item == special_queue
1893 || folder_has_parent_of_type(item, F_QUEUE)) &&
1894 gtk_item_factory_get_item(fpopup_factory, "/Send queue...") == NULL) {
1895 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[0], folderview, 1);
1896 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[1], folderview, 1);
1897 } else if (item != folder->queue && (special_queue == NULL || item != special_queue)
1898 && !folder_has_parent_of_type(item, F_QUEUE)) {
1899 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[0]);
1900 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[1]);
1903 #define SET_SENS(name, sens) \
1904 menu_set_sensitive(fpopup_factory, name, sens)
1906 SET_SENS("/Mark all read", item->unread_msgs >= 1);
1907 SET_SENS("/Search folder...", item->total_msgs >= 1 &&
1908 folderview->selected == folderview->opened);
1909 SET_SENS("/Properties...", TRUE);
1910 SET_SENS("/Processing...", item->node->parent != NULL);
1911 if (item == folder->trash || item == special_trash
1912 || folder_has_parent_of_type(item, F_TRASH)) {
1913 GSList *msglist = folder_item_get_msg_list(item);
1914 SET_SENS("/Empty trash...", msglist != NULL);
1915 procmsg_msg_list_free(msglist);
1917 if (item == folder->queue || item == special_queue
1918 || folder_has_parent_of_type(item, F_QUEUE)) {
1919 GSList *msglist = folder_item_get_msg_list(item);
1920 SET_SENS("/Send queue...", msglist != NULL);
1921 procmsg_msg_list_free(msglist);
1925 popup = gtk_item_factory_get_widget(fpopup_factory, fpopup->path);
1926 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1927 event->button, event->time);
1932 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1933 FolderView *folderview)
1935 GtkCList *clist = GTK_CLIST(ctree);
1936 gint prev_row = -1, row = -1, column = -1;
1938 if (!event) return FALSE;
1940 if (event->button == 1 || event->button == 2) {
1941 if (!gtk_ctree_is_hot_spot (GTK_CTREE(clist), event->x, event->y))
1942 folderview->open_folder = TRUE;
1944 if (event->type == GDK_2BUTTON_PRESS) {
1945 if (clist->selection) {
1948 node = GTK_CTREE_NODE(clist->selection->data);
1950 gtk_ctree_toggle_expansion(
1953 folderview->open_folder = FALSE;
1960 if (event->button == 2 || event->button == 3) {
1962 if (clist->selection) {
1965 node = GTK_CTREE_NODE(clist->selection->data);
1967 prev_row = gtkut_ctree_get_nth_from_node
1968 (GTK_CTREE(ctree), node);
1971 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1974 if (prev_row != row) {
1975 gtk_clist_unselect_all(clist);
1976 if (event->button == 2)
1977 folderview_select_node
1979 gtk_ctree_node_nth(GTK_CTREE(ctree),
1982 gtk_clist_select_row(clist, row, column);
1986 if (event->button != 3) return FALSE;
1988 folderview_set_sens_and_popup_menu(folderview, row, event);
1992 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1993 FolderView *folderview)
1995 if (!event) return FALSE;
1997 if (event->button == 1 && folderview->open_folder == FALSE &&
1998 folderview->opened != NULL) {
1999 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
2000 folderview->opened);
2001 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
2007 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
2008 FolderView *folderview)
2010 if (!event) return FALSE;
2012 if (quicksearch_has_focus(folderview->summaryview->quicksearch))
2015 switch (event->keyval) {
2021 if (folderview->selected) {
2022 folderview_select_node(folderview,
2023 folderview->selected);
2028 if (folderview->selected && GTK_CTREE_ROW(folderview->selected)->children) {
2029 gtk_ctree_toggle_expansion(
2030 GTK_CTREE(folderview->ctree),
2031 folderview->selected);
2036 if (folderview->selected) {
2037 if (folderview->opened == folderview->selected &&
2038 (!folderview->summaryview->folder_item ||
2039 folderview->summaryview->folder_item->total_msgs == 0))
2040 folderview_select_next_unread(folderview, TRUE);
2042 folderview_select_node(folderview,
2043 folderview->selected);
2053 typedef struct _PostponedSelectData
2058 FolderView *folderview;
2059 } PostponedSelectData;
2061 static gboolean postpone_select(void *data)
2063 PostponedSelectData *psdata = (PostponedSelectData *)data;
2064 debug_print("trying again\n");
2065 psdata->folderview->open_folder = TRUE;
2066 main_window_cursor_normal(psdata->folderview->mainwin);
2067 STATUSBAR_POP(psdata->folderview->mainwin);
2068 folderview_selected(psdata->ctree, psdata->row,
2069 psdata->column, psdata->folderview);
2074 void folderview_close_opened(FolderView *folderview)
2076 if (folderview->opened) {
2077 FolderItem *olditem;
2079 olditem = gtk_ctree_node_get_row_data(GTK_CTREE(folderview->ctree),
2080 folderview->opened);
2082 gchar *buf = g_strdup_printf(_("Closing Folder %s..."),
2083 olditem->path ? olditem->path:olditem->name);
2084 /* will be null if we just moved the previously opened folder */
2085 STATUSBAR_PUSH(folderview->mainwin, buf);
2086 main_window_cursor_wait(folderview->mainwin);
2088 summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
2089 summary_show(folderview->summaryview, NULL);
2090 folder_item_close(olditem);
2091 main_window_cursor_normal(folderview->mainwin);
2092 STATUSBAR_POP(folderview->mainwin);
2096 if (folderview->opened &&
2097 !GTK_CTREE_ROW(folderview->opened)->children)
2098 gtk_ctree_collapse(GTK_CTREE(folderview->ctree), folderview->opened);
2100 folderview->opened = NULL;
2102 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
2103 gint column, FolderView *folderview)
2105 static gboolean can_select = TRUE; /* exclusive lock */
2110 GtkCTreeNode *old_opened = folderview->opened;
2112 folderview->selected = row;
2114 debug_print("newly selected %p, opened %p\n", folderview->selected,
2115 folderview->opened);
2116 if (folderview->opened == row) {
2117 folderview->open_folder = FALSE;
2122 if (!can_select || summary_is_locked(folderview->summaryview)) {
2123 if (folderview->opened) {
2124 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2125 gtk_ctree_select(ctree, folderview->opened);
2127 folderview->open_folder = FALSE;
2132 if (!folderview->open_folder) {
2136 item = gtk_ctree_node_get_row_data(ctree, row);
2137 if (!item || item->no_select) {
2139 folderview->open_folder = FALSE;
2145 /* Save cache for old folder */
2146 /* We don't want to lose all caches if sylpheed crashed */
2147 /* resets folderview->opened to NULL */
2148 folderview_close_opened(folderview);
2150 /* CLAWS: set compose button type: news folder items
2151 * always have a news folder as parent */
2153 toolbar_set_compose_button
2154 (folderview->mainwin->toolbar,
2155 FOLDER_TYPE(item->folder) == F_NEWS ?
2156 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
2159 debug_print("Folder %s is selected\n", item->path);
2161 if (!GTK_CTREE_ROW(row)->children)
2162 gtk_ctree_expand(ctree, row);
2164 /* ungrab the mouse event */
2165 if (GTK_WIDGET_HAS_GRAB(ctree)) {
2166 gtk_grab_remove(GTK_WIDGET(ctree));
2167 if (gdk_pointer_is_grabbed())
2168 gdk_pointer_ungrab(GDK_CURRENT_TIME);
2172 buf = g_strdup_printf(_("Opening Folder %s..."), item->path ?
2173 item->path : "(null)");
2174 debug_print("%s\n", buf);
2175 STATUSBAR_PUSH(folderview->mainwin, buf);
2178 main_window_cursor_wait(folderview->mainwin);
2180 res = folder_item_open(item);
2182 main_window_cursor_normal(folderview->mainwin);
2183 STATUSBAR_POP(folderview->mainwin);
2185 alertpanel_error(_("Folder could not be opened."));
2187 folderview->open_folder = FALSE;
2191 } else if (res == -2) {
2192 PostponedSelectData *data = g_new0(PostponedSelectData, 1);
2193 data->ctree = ctree;
2195 data->column = column;
2196 data->folderview = folderview;
2197 debug_print("postponing open of %s till end of scan\n",
2198 item->path ? item->path:item->name);
2199 folderview->open_folder = FALSE;
2201 g_timeout_add(500, postpone_select, data);
2206 main_window_cursor_normal(folderview->mainwin);
2209 summary_set_prefs_from_folderitem(folderview->summaryview, item);
2210 opened = summary_show(folderview->summaryview, item);
2212 folder_clean_cache_memory(item);
2215 gtkut_ctree_set_focus_row(ctree, old_opened);
2216 gtk_ctree_select(ctree, old_opened);
2217 folderview->opened = old_opened;
2219 folderview->opened = row;
2220 if (gtk_ctree_node_is_visible(ctree, row)
2221 != GTK_VISIBILITY_FULL)
2222 gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0);
2225 STATUSBAR_POP(folderview->mainwin);
2227 folderview->open_folder = FALSE;
2232 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
2233 FolderView *folderview)
2237 item = gtk_ctree_node_get_row_data(ctree, node);
2238 g_return_if_fail(item != NULL);
2239 item->collapsed = FALSE;
2240 folderview_update_node(folderview, node);
2243 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
2244 FolderView *folderview)
2248 item = gtk_ctree_node_get_row_data(ctree, node);
2249 g_return_if_fail(item != NULL);
2250 item->collapsed = TRUE;
2251 folderview_update_node(folderview, node);
2254 static void folderview_popup_close(GtkMenuShell *menu_shell,
2255 FolderView *folderview)
2257 if (!folderview->opened) return;
2259 gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
2262 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
2263 FolderView *folderview)
2265 FolderColumnType type = folderview->col_state[column].type;
2267 prefs_common.folder_col_size[type] = width;
2270 static void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item)
2274 folderview_create_folder_node(folderview, item);
2276 if (!item || !item->folder || !item->folder->node)
2279 srcnode = item->folder->node;
2280 srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item);
2281 srcnode = srcnode->children;
2282 while (srcnode != NULL) {
2283 if (srcnode && srcnode->data) {
2284 FolderItem *next_item = (FolderItem*) srcnode->data;
2285 folderview_create_folder_node_recursive(folderview, next_item);
2287 srcnode = srcnode->next;
2291 static void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
2293 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2294 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2295 GtkCTreeNode *node, *parent_node;
2296 gint *col_pos = folderview->col_pos;
2297 FolderItemUpdateData hookdata;
2299 parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
2300 if (parent_node == NULL)
2303 gtk_clist_freeze(GTK_CLIST(ctree));
2305 text[col_pos[F_COL_FOLDER]] = item->name;
2306 node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
2308 folderxpm, folderxpmmask,
2309 folderopenxpm, folderopenxpmmask,
2311 gtk_ctree_expand(ctree, parent_node);
2312 gtk_ctree_node_set_row_data(ctree, node, item);
2314 gtk_ctree_node_set_row_style(ctree, node, normal_style);
2315 folderview_sort_folders(folderview, parent_node, item->folder);
2317 hookdata.item = item;
2318 hookdata.update_flags = F_ITEM_UPDATE_NAME;
2319 hookdata.msg = NULL;
2320 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
2322 gtk_clist_thaw(GTK_CLIST(ctree));
2325 static void folderview_empty_trash_cb(FolderView *folderview, guint action,
2328 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2330 GSList *mlist = NULL;
2332 FolderItem *special_trash = NULL;
2335 if (!folderview->selected) return;
2336 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2337 g_return_if_fail(item != NULL);
2338 g_return_if_fail(item->folder != NULL);
2340 if (NULL != (ac = account_find_from_item(item)))
2341 special_trash = account_get_special_folder(ac, F_TRASH);
2343 if (item != item->folder->trash && item != special_trash
2344 && !folder_has_parent_of_type(item, F_TRASH)) return;
2346 if (prefs_common.ask_on_clean) {
2347 if (alertpanel(_("Empty trash"),
2348 _("Delete all messages in trash?"),
2349 GTK_STOCK_CANCEL, _("+_Empty trash"), NULL) != G_ALERTALTERNATE)
2353 mlist = folder_item_get_msg_list(item);
2355 for (cur = mlist ; cur != NULL ; cur = cur->next) {
2356 MsgInfo * msginfo = (MsgInfo *) cur->data;
2357 if (MSG_IS_LOCKED(msginfo->flags))
2359 /* is it partially received? (partial_recv isn't cached) */
2360 if (msginfo->total_size != 0 &&
2361 msginfo->size != (off_t)msginfo->total_size)
2362 partial_mark_for_delete(msginfo);
2364 procmsg_msg_list_free(mlist);
2366 folder_item_remove_all_msg(item);
2369 static void folderview_send_queue_cb(FolderView *folderview, guint action,
2372 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2374 FolderItem *special_queue = NULL;
2376 gchar *errstr = NULL;
2378 if (!folderview->selected) return;
2379 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2380 g_return_if_fail(item != NULL);
2381 g_return_if_fail(item->folder != NULL);
2383 if (NULL != (ac = account_find_from_item(item)))
2384 special_queue = account_get_special_folder(ac, F_QUEUE);
2386 if (item != item->folder->queue && item != special_queue
2387 && !folder_has_parent_of_type(item, F_QUEUE)) return;
2389 if (procmsg_queue_is_empty(item))
2392 if (prefs_common.work_offline)
2393 if (alertpanel(_("Offline warning"),
2394 _("You're working offline. Override?"),
2395 GTK_STOCK_NO, GTK_STOCK_YES,
2396 NULL) != G_ALERTALTERNATE)
2399 /* ask for confirmation before sending queued messages only
2400 in online mode and if there is at least one message queued
2401 in any of the folder queue
2403 if (prefs_common.confirm_send_queued_messages) {
2404 if (!prefs_common.work_offline) {
2405 if (alertpanel(_("Send queued messages"),
2406 _("Send all queued messages?"),
2407 GTK_STOCK_CANCEL, _("_Send"),
2408 NULL) != G_ALERTALTERNATE)
2413 if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
2415 alertpanel_error_log(_("Some errors occurred while "
2416 "sending queued messages."));
2418 gchar *tmp = g_strdup_printf(_("Some errors occurred "
2419 "while sending queued messages:\n%s"), errstr);
2421 alertpanel_error_log(tmp);
2427 static void folderview_search_cb(FolderView *folderview, guint action,
2430 summary_search(folderview->summaryview);
2433 static void folderview_property_cb(FolderView *folderview, guint action,
2436 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2439 if (!folderview->selected) return;
2441 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2442 g_return_if_fail(item != NULL);
2443 g_return_if_fail(item->folder != NULL);
2445 prefs_folder_item_open(item);
2448 static void folderview_recollapse_nodes(FolderView *folderview, GtkCTreeNode *node)
2450 GSList *list = NULL;
2451 GSList *done = NULL;
2452 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2454 for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2455 if (!gtkut_ctree_node_is_parent(GTK_CTREE_NODE(list->data), node)
2456 && list->data != node) {
2457 gtk_ctree_collapse(ctree, GTK_CTREE_NODE(list->data));
2458 done = g_slist_append(done, GTK_CTREE_NODE(list->data));
2461 for (list = done; list != NULL; list = g_slist_next(list)) {
2462 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse,
2468 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
2469 FolderItem *to_folder, gboolean copy)
2471 FolderItem *from_parent = NULL;
2472 FolderItem *new_folder = NULL;
2473 GtkCTreeNode *src_node = NULL;
2477 g_return_if_fail(folderview != NULL);
2478 g_return_if_fail(from_folder != NULL);
2479 g_return_if_fail(to_folder != NULL);
2481 src_node = gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), NULL, from_folder);
2482 from_parent = folder_item_parent(from_folder);
2484 if (prefs_common.warn_dnd) {
2485 buf = g_strdup_printf(copy ? _("Do you really want to copy folder '%s' in '%s' ?"):
2486 _("Do you really want to make folder '%s' a sub-folder of '%s' ?"),
2487 from_folder->name, to_folder->name);
2488 status = alertpanel_full(copy ? _("Copy folder"):_("Move folder"), buf,
2489 GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE,
2490 NULL, ALERT_QUESTION, G_ALERTDEFAULT);
2493 if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
2495 else if (status & G_ALERTDISABLE)
2496 prefs_common.warn_dnd = FALSE;
2499 buf = g_strdup_printf(copy ? _("Copying %s to %s..."):_("Moving %s to %s..."),
2500 from_folder->name, to_folder->name);
2501 STATUSBAR_PUSH(folderview->mainwin, buf);
2503 summary_clear_all(folderview->summaryview);
2504 folderview->opened = NULL;
2505 folderview->selected = NULL;
2506 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2508 main_window_cursor_wait(folderview->mainwin);
2510 statusbar_verbosity_set(FALSE);
2511 folder_item_update_freeze();
2512 if ((status = folder_item_move_to(from_folder, to_folder, &new_folder, copy)) == F_MOVE_OK) {
2513 statusbar_verbosity_set(FALSE);
2514 main_window_cursor_normal(folderview->mainwin);
2515 STATUSBAR_POP(folderview->mainwin);
2516 folder_item_update_thaw();
2517 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2519 folderview_sort_folders(folderview,
2520 gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree),
2521 NULL, to_folder), new_folder->folder);
2522 folderview_select(folderview, new_folder);
2524 statusbar_verbosity_set(FALSE);
2525 main_window_cursor_normal(folderview->mainwin);
2526 STATUSBAR_POP(folderview->mainwin);
2527 folder_item_update_thaw();
2529 case F_MOVE_FAILED_DEST_IS_PARENT:
2530 alertpanel_error(_("Source and destination are the same."));
2532 case F_MOVE_FAILED_DEST_IS_CHILD:
2533 alertpanel_error(copy ? _("Can't copy a folder to one of its children."):
2534 _("Can't move a folder to one of its children."));
2536 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2537 alertpanel_error(_("A folder cannot be moved between different mailboxes."));
2540 alertpanel_error(copy ? _("Copy failed!"):_("Move failed!"));
2545 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2548 static gint folderview_clist_compare(GtkCList *clist,
2549 gconstpointer ptr1, gconstpointer ptr2)
2551 FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
2552 FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
2554 if (item1->order > 0 && item2->order > 0) // if we have an order item, use it
2556 return item1->order - item2->order;
2559 // if only one folder has an order it comes first
2560 if (item1->order > 0)
2564 if (item2->order > 0)
2570 return (item2->name != NULL);
2574 return g_utf8_collate(item1->name, item2->name);
2577 static void folderview_processing_cb(FolderView *folderview, guint action,
2580 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2584 if (!folderview->selected) return;
2586 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2587 g_return_if_fail(item != NULL);
2588 g_return_if_fail(item->folder != NULL);
2590 id = folder_item_get_identifier(item);
2591 title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2594 prefs_filtering_open(&item->prefs->processing, title,
2595 MANUAL_ANCHOR_PROCESSING, NULL, NULL, FALSE);
2599 void folderview_set_target_folder_color(gint color_op)
2603 FolderView *folderview;
2605 for (list = folderview_list; list != NULL; list = list->next) {
2606 folderview = (FolderView *)list->data;
2607 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2609 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2610 folderview->color_op;
2616 static gchar *last_font = NULL;
2617 void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
2625 void folderview_reflect_prefs(void)
2627 gboolean update_font = TRUE;
2628 FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2629 FolderItem *item = folderview_get_selected_item(folderview);
2630 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2631 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2632 gint height = pos->value;
2634 if (last_font && !strcmp(last_font, NORMAL_FONT))
2635 update_font = FALSE;
2638 last_font = g_strdup(NORMAL_FONT);
2641 normal_style = normal_color_style = bold_style =
2642 bold_color_style = bold_tgtfold_style = NULL;
2644 folderview_init(folderview);
2646 gtk_clist_freeze(GTK_CLIST(folderview->ctree));
2647 folderview_column_set_titles(folderview);
2648 folderview_set_all();
2650 g_signal_handlers_block_by_func
2651 (G_OBJECT(folderview->ctree),
2652 G_CALLBACK(folderview_selected), folderview);
2655 GtkCTreeNode *node = gtk_ctree_find_by_row_data(
2656 GTK_CTREE(folderview->ctree), NULL, item);
2658 folderview_select(folderview, item);
2659 folderview->open_folder = FALSE;
2660 folderview->selected = node;
2663 g_signal_handlers_unblock_by_func
2664 (G_OBJECT(folderview->ctree),
2665 G_CALLBACK(folderview_selected), folderview);
2667 pos = gtk_scrolled_window_get_vadjustment(
2668 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2669 gtk_adjustment_set_value(pos, height);
2670 gtk_clist_thaw(GTK_CLIST(folderview->ctree));
2673 static void drag_state_stop(FolderView *folderview)
2675 if (folderview->drag_timer)
2676 g_source_remove(folderview->drag_timer);
2677 folderview->drag_timer = 0;
2678 folderview->drag_node = NULL;
2681 static gint folderview_defer_expand(FolderView *folderview)
2683 if (folderview->drag_node) {
2684 folderview_recollapse_nodes(folderview, folderview->drag_node);
2685 if (folderview->drag_item->collapsed) {
2686 gtk_ctree_expand(GTK_CTREE(folderview->ctree), folderview->drag_node);
2687 folderview->nodes_to_recollapse = g_slist_append
2688 (folderview->nodes_to_recollapse, folderview->drag_node);
2691 folderview->drag_item = NULL;
2692 folderview->drag_timer = 0;
2696 static void drag_state_start(FolderView *folderview, GtkCTreeNode *node, FolderItem *item)
2698 /* the idea is that we call drag_state_start() whenever we want expansion to
2699 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2700 * we need to call drag_state_stop() */
2701 drag_state_stop(folderview);
2702 /* request expansion */
2703 if (0 != (folderview->drag_timer = g_timeout_add
2704 (prefs_common.hover_timeout,
2705 (GtkFunction)folderview_defer_expand,
2707 folderview->drag_node = node;
2708 folderview->drag_item = item;
2712 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2713 FolderView *folderview)
2715 GdkDragContext *context;
2717 g_return_if_fail(folderview != NULL);
2718 if (folderview->selected == NULL) return;
2719 if (folderview->nodes_to_recollapse)
2720 g_slist_free(folderview->nodes_to_recollapse);
2721 folderview->nodes_to_recollapse = NULL;
2722 context = gtk_drag_begin(widget, folderview->target_list,
2723 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2724 gtk_drag_set_icon_default(context);
2727 static void folderview_drag_data_get(GtkWidget *widget,
2728 GdkDragContext *drag_context,
2729 GtkSelectionData *selection_data,
2732 FolderView *folderview)
2736 gchar *source = NULL;
2737 if (info == TARGET_DUMMY) {
2738 for (cur = GTK_CLIST(folderview->ctree)->selection;
2739 cur != NULL; cur = cur->next) {
2740 item = gtk_ctree_node_get_row_data
2741 (GTK_CTREE(folderview->ctree),
2742 GTK_CTREE_NODE(cur->data));
2744 source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2745 gtk_selection_data_set(selection_data,
2746 selection_data->target, 8,
2747 source, strlen(source));
2753 g_warning("unknown info %d\n", info);
2757 static gboolean folderview_update_folder(gpointer source, gpointer userdata)
2759 FolderUpdateData *hookdata;
2760 FolderView *folderview;
2764 folderview = (FolderView *) userdata;
2765 g_return_val_if_fail(hookdata != NULL, FALSE);
2766 g_return_val_if_fail(folderview != NULL, FALSE);
2768 ctree = folderview->ctree;
2769 g_return_val_if_fail(ctree != NULL, FALSE);
2771 if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2772 folderview_create_folder_node(folderview, hookdata->item);
2773 else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2774 GtkCTreeNode *node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree),
2775 NULL, folder_item_parent(hookdata->item));
2776 folderview_sort_folders(folderview, node, hookdata->folder);
2777 } else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2780 node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree), NULL, hookdata->item);
2782 gtk_ctree_remove_node(GTK_CTREE(ctree), node);
2783 if (folderview->selected == node)
2784 folderview->selected = NULL;
2785 if (folderview->opened == node)
2786 folderview->opened = NULL;
2788 } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
2789 folderview_set(folderview);
2794 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2795 GdkDragContext *context,
2799 FolderView *folderview)
2802 FolderItem *item = NULL, *src_item = NULL;
2803 GtkCTreeNode *node = NULL;
2804 gboolean acceptable = FALSE;
2805 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2806 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2807 int height = (int)pos->page_size;
2808 int total_height = (int)pos->upper;
2809 int vpos = (int) pos->value;
2811 if (gtk_clist_get_selection_info
2812 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
2813 GtkWidget *srcwidget;
2815 if (y > height - 24 && height + vpos < total_height)
2816 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
2818 if (y < 48 && y > 0)
2819 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
2821 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2822 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2823 src_item = folderview->summaryview->folder_item;
2825 srcwidget = gtk_drag_get_source_widget(context);
2826 if (srcwidget == summary_get_main_widget(folderview->summaryview)) {
2827 /* comes from summaryview */
2828 /* we are copying messages, so only accept folder items that are not
2829 the source item, are no root items and can copy messages */
2830 if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
2831 src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2832 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2834 } else if (srcwidget == folderview->ctree) {
2835 /* comes from folderview */
2836 /* we are moving folder items, only accept folders that are not
2837 the source items and can copy messages and create folder items */
2838 if (item && item->folder && src_item && src_item != item &&
2839 FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2840 FOLDER_CLASS(item->folder)->create_folder != NULL &&
2841 ((FOLDER_TYPE(item->folder) != F_UNKNOWN && FOLDER_TYPE(src_item->folder) != F_UNKNOWN)
2842 || item->folder == src_item->folder))
2845 /* comes from another app */
2846 /* we are adding messages, so only accept folder items that are
2847 no root items and can copy messages */
2848 if (item && item->folder && folder_item_parent(item) != NULL
2849 && FOLDER_CLASS(item->folder)->add_msg != NULL &&
2850 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2855 if (acceptable || (src_item && src_item == item))
2856 drag_state_start(folderview, node, item);
2859 g_signal_handlers_block_by_func
2861 G_CALLBACK(folderview_selected), folderview);
2862 gtk_ctree_select(GTK_CTREE(widget), node);
2863 g_signal_handlers_unblock_by_func
2865 G_CALLBACK(folderview_selected), folderview);
2866 gdk_drag_status(context,
2867 (context->actions == GDK_ACTION_COPY ?
2868 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2870 if (folderview->opened)
2871 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2872 gdk_drag_status(context, 0, time);
2878 static void folderview_drag_leave_cb(GtkWidget *widget,
2879 GdkDragContext *context,
2881 FolderView *folderview)
2883 drag_state_stop(folderview);
2884 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2887 static void free_info (gpointer stuff, gpointer data)
2892 void folderview_finish_dnd(const gchar *data, GdkDragContext *drag_context,
2893 guint time, FolderItem *item)
2896 GSList *msglist = NULL;
2897 list = uri_list_extract_filenames(data);
2898 if (!(item && item->folder && folder_item_parent(item) != NULL
2899 && FOLDER_CLASS(item->folder)->add_msg != NULL))
2901 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2902 debug_print("item doesn't fit\n");
2906 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2907 debug_print("list is empty\n");
2910 for (tmp = list; tmp != NULL; tmp = tmp->next) {
2911 MsgFileInfo *info = NULL;
2913 if (file_is_email((gchar *)tmp->data)) {
2914 info = g_new0(MsgFileInfo, 1);
2915 info->msginfo = NULL;
2916 info->file = (gchar *)tmp->data;
2917 msglist = g_slist_prepend(msglist, info);
2918 debug_print("file is a mail\n");
2920 debug_print("file isn't a mail\n");
2924 msglist = g_slist_reverse(msglist);
2925 folder_item_add_msgs(item, msglist, FALSE);
2926 g_slist_foreach(msglist, free_info, NULL);
2927 g_slist_free(msglist);
2928 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2930 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2932 list_free_strings(list);
2936 static void folderview_drag_received_cb(GtkWidget *widget,
2937 GdkDragContext *drag_context,
2940 GtkSelectionData *data,
2943 FolderView *folderview)
2946 FolderItem *item = NULL, *src_item;
2949 if (info == TARGET_DUMMY) {
2950 drag_state_stop(folderview);
2951 if ((void *)strstr(data->data, "FROM_OTHER_FOLDER") != (void *)data->data) {
2952 /* comes from summaryview */
2953 if (gtk_clist_get_selection_info
2954 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2957 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2958 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2959 src_item = folderview->summaryview->folder_item;
2961 /* re-check (due to acceptable possibly set for folder moves */
2962 if (!(item && item->folder && item->path && !item->no_select &&
2963 src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) {
2966 if (item && src_item) {
2967 switch (drag_context->action) {
2968 case GDK_ACTION_COPY:
2969 summary_copy_selected_to(folderview->summaryview, item);
2970 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2972 case GDK_ACTION_MOVE:
2973 case GDK_ACTION_DEFAULT:
2975 if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL)
2976 summary_copy_selected_to(folderview->summaryview, item);
2978 summary_move_selected_to(folderview->summaryview, item);
2979 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2982 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2984 /* comes from folderview */
2986 gboolean folder_is_normal = TRUE;
2987 gboolean copy = (drag_context->action == GDK_ACTION_COPY);
2989 source = data->data + 17;
2990 if (gtk_clist_get_selection_info
2991 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0
2993 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2996 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2997 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2998 src_item = folder_find_item_from_identifier(source);
3002 src_item->stype == F_NORMAL &&
3003 !folder_has_parent_of_type(src_item, F_OUTBOX) &&
3004 !folder_has_parent_of_type(src_item, F_DRAFT) &&
3005 !folder_has_parent_of_type(src_item, F_QUEUE) &&
3006 !folder_has_parent_of_type(src_item, F_TRASH);
3007 if (!item || item->no_select || !src_item
3008 || !folder_is_normal) {
3009 gtk_drag_finish(drag_context, FALSE, FALSE, time);
3013 folderview_move_folder(folderview, src_item, item, copy);
3014 gtk_drag_finish(drag_context, TRUE, TRUE, time);
3016 folderview->nodes_to_recollapse = NULL;
3017 } else if (info == TARGET_MAIL_URI_LIST) {
3018 if (gtk_clist_get_selection_info
3019 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
3022 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
3024 gtk_drag_finish(drag_context, FALSE, FALSE, time);
3025 debug_print("no node\n");
3028 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
3030 gtk_drag_finish(drag_context, FALSE, FALSE, time);
3031 debug_print("no item\n");
3034 folderview_finish_dnd(data->data, drag_context, time, item);
3038 static void folderview_drag_end_cb(GtkWidget *widget,
3039 GdkDragContext *drag_context,
3040 FolderView *folderview)
3042 drag_state_stop(folderview);
3043 g_slist_free(folderview->nodes_to_recollapse);
3044 folderview->nodes_to_recollapse = NULL;
3047 void folderview_register_popup(FolderViewPopup *fpopup)
3051 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
3052 FolderView *folderview = folderviews->data;
3053 GtkItemFactory *factory;
3055 factory = create_ifactory(folderview, fpopup);
3056 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
3058 g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
3061 void folderview_unregister_popup(FolderViewPopup *fpopup)
3065 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
3066 FolderView *folderview = folderviews->data;
3068 g_hash_table_remove(folderview->popups, fpopup->klass);
3070 g_hash_table_remove(folderview_popups, fpopup->klass);