2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include <glib/gi18n.h>
24 #include <gdk/gdkkeysyms.h>
25 #include <gtk/gtkwidget.h>
26 #include <gtk/gtkscrolledwindow.h>
27 #include <gtk/gtkctree.h>
28 #include <gtk/gtkcontainer.h>
29 #include <gtk/gtkclist.h>
30 #include <gtk/gtkstyle.h>
31 #include <gtk/gtksignal.h>
32 #include <gtk/gtkmain.h>
33 #include <gtk/gtkstatusbar.h>
34 #include <gtk/gtkmenu.h>
35 #include <gtk/gtkmenuitem.h>
36 #include <gtk/gtkitemfactory.h>
42 #include "mainwindow.h"
43 #include "folderview.h"
44 #include "summaryview.h"
45 #include "summary_search.h"
46 #include "inputdialog.h"
47 #include "manage_window.h"
48 #include "alertpanel.h"
50 #include "stock_pixmap.h"
54 #include "prefs_common.h"
55 #include "prefs_account.h"
56 #include "prefs_filtering.h"
57 #include "prefs_folder_item.h"
60 #include "foldersel.h"
62 #include "statusbar.h"
64 #include "folderutils.h"
65 #include "partial_download.h"
66 #include "prefs_folder_column.h"
67 #include "filtering.h"
68 #include "quicksearch.h"
72 #define COL_FOLDER_WIDTH 150
73 #define COL_NUM_WIDTH 32
75 static GList *folderview_list = NULL;
77 static GtkStyle *normal_style;
78 static GtkStyle *normal_color_style;
79 static GtkStyle *bold_style;
80 static GtkStyle *bold_color_style;
81 static GtkStyle *bold_tgtfold_style;
83 static GdkPixmap *inboxxpm;
84 static GdkBitmap *inboxxpmmask;
85 static GdkPixmap *inboxhrmxpm;
86 static GdkBitmap *inboxhrmxpmmask;
87 static GdkPixmap *inboxopenxpm;
88 static GdkBitmap *inboxopenxpmmask;
89 static GdkPixmap *inboxopenhrmxpm;
90 static GdkBitmap *inboxopenhrmxpmmask;
91 static GdkPixmap *outboxxpm;
92 static GdkBitmap *outboxxpmmask;
93 static GdkPixmap *outboxhrmxpm;
94 static GdkBitmap *outboxhrmxpmmask;
95 static GdkPixmap *outboxopenxpm;
96 static GdkBitmap *outboxopenxpmmask;
97 static GdkPixmap *outboxopenhrmxpm;
98 static GdkBitmap *outboxopenhrmxpmmask;
99 static GdkPixmap *folderxpm;
100 static GdkBitmap *folderxpmmask;
101 static GdkPixmap *folderhrmxpm;
102 static GdkBitmap *folderhrmxpmmask;
103 static GdkPixmap *folderopenxpm;
104 static GdkBitmap *folderopenxpmmask;
105 static GdkPixmap *folderopenhrmxpm;
106 static GdkBitmap *folderopenhrmxpmmask;
107 static GdkPixmap *trashopenxpm;
108 static GdkBitmap *trashopenxpmmask;
109 static GdkPixmap *trashopenhrmxpm;
110 static GdkBitmap *trashopenhrmxpmmask;
111 static GdkPixmap *trashxpm;
112 static GdkBitmap *trashxpmmask;
113 static GdkPixmap *trashhrmxpm;
114 static GdkBitmap *trashhrmxpmmask;
115 static GdkPixmap *queuexpm;
116 static GdkBitmap *queuexpmmask;
117 static GdkPixmap *queuehrmxpm;
118 static GdkBitmap *queuehrmxpmmask;
119 static GdkPixmap *queueopenxpm;
120 static GdkBitmap *queueopenxpmmask;
121 static GdkPixmap *queueopenhrmxpm;
122 static GdkBitmap *queueopenhrmxpmmask;
123 static GdkPixmap *draftsxpm;
124 static GdkBitmap *draftsxpmmask;
125 static GdkPixmap *draftsopenxpm;
126 static GdkBitmap *draftsopenxpmmask;
127 static GdkPixmap *noselectxpm;
128 static GdkBitmap *noselectxpmmask;
130 static GdkPixmap *m_inboxxpm;
131 static GdkBitmap *m_inboxxpmmask;
132 static GdkPixmap *m_inboxhrmxpm;
133 static GdkBitmap *m_inboxhrmxpmmask;
134 static GdkPixmap *m_inboxopenxpm;
135 static GdkBitmap *m_inboxopenxpmmask;
136 static GdkPixmap *m_inboxopenhrmxpm;
137 static GdkBitmap *m_inboxopenhrmxpmmask;
138 static GdkPixmap *m_outboxxpm;
139 static GdkBitmap *m_outboxxpmmask;
140 static GdkPixmap *m_outboxhrmxpm;
141 static GdkBitmap *m_outboxhrmxpmmask;
142 static GdkPixmap *m_outboxopenxpm;
143 static GdkBitmap *m_outboxopenxpmmask;
144 static GdkPixmap *m_outboxopenhrmxpm;
145 static GdkBitmap *m_outboxopenhrmxpmmask;
146 static GdkPixmap *m_folderxpm;
147 static GdkBitmap *m_folderxpmmask;
148 static GdkPixmap *m_folderhrmxpm;
149 static GdkBitmap *m_folderhrmxpmmask;
150 static GdkPixmap *m_folderopenxpm;
151 static GdkBitmap *m_folderopenxpmmask;
152 static GdkPixmap *m_folderopenhrmxpm;
153 static GdkBitmap *m_folderopenhrmxpmmask;
154 static GdkPixmap *m_trashopenxpm;
155 static GdkBitmap *m_trashopenxpmmask;
156 static GdkPixmap *m_trashopenhrmxpm;
157 static GdkBitmap *m_trashopenhrmxpmmask;
158 static GdkPixmap *m_trashxpm;
159 static GdkBitmap *m_trashxpmmask;
160 static GdkPixmap *m_trashhrmxpm;
161 static GdkBitmap *m_trashhrmxpmmask;
162 static GdkPixmap *m_queuexpm;
163 static GdkBitmap *m_queuexpmmask;
164 static GdkPixmap *m_queuehrmxpm;
165 static GdkBitmap *m_queuehrmxpmmask;
166 static GdkPixmap *m_queueopenxpm;
167 static GdkBitmap *m_queueopenxpmmask;
168 static GdkPixmap *m_queueopenhrmxpm;
169 static GdkBitmap *m_queueopenhrmxpmmask;
170 static GdkPixmap *m_draftsxpm;
171 static GdkBitmap *m_draftsxpmmask;
172 static GdkPixmap *m_draftsopenxpm;
173 static GdkBitmap *m_draftsopenxpmmask;
175 static GdkPixmap *newxpm;
176 static GdkBitmap *newxpmmask;
177 static GdkPixmap *unreadxpm;
178 static GdkBitmap *unreadxpmmask;
179 static GdkPixmap *readxpm;
180 static GdkBitmap *readxpmmask;
183 static void folderview_select_node (FolderView *folderview,
185 static void folderview_set_folders (FolderView *folderview);
186 static void folderview_sort_folders (FolderView *folderview,
189 static void folderview_append_folder (FolderView *folderview,
191 static void folderview_update_node (FolderView *folderview,
194 static gint folderview_clist_compare (GtkCList *clist,
198 /* callback functions */
199 static gboolean folderview_button_pressed (GtkWidget *ctree,
200 GdkEventButton *event,
201 FolderView *folderview);
202 static gboolean folderview_button_released (GtkWidget *ctree,
203 GdkEventButton *event,
204 FolderView *folderview);
205 static gboolean folderview_key_pressed (GtkWidget *widget,
207 FolderView *folderview);
208 static void folderview_selected (GtkCTree *ctree,
211 FolderView *folderview);
212 static void folderview_tree_expanded (GtkCTree *ctree,
214 FolderView *folderview);
215 static void folderview_tree_collapsed (GtkCTree *ctree,
217 FolderView *folderview);
218 static void folderview_popup_close (GtkMenuShell *menu_shell,
219 FolderView *folderview);
220 static void folderview_col_resized (GtkCList *clist,
223 FolderView *folderview);
225 static void mark_all_read_cb (FolderView *folderview,
229 static void folderview_empty_trash_cb (FolderView *folderview,
233 static void folderview_send_queue_cb (FolderView *folderview,
237 static void folderview_search_cb (FolderView *folderview,
241 static void folderview_property_cb (FolderView *folderview,
245 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
246 GdkDragContext *context,
250 FolderView *folderview);
251 static void folderview_drag_leave_cb (GtkWidget *widget,
252 GdkDragContext *context,
254 FolderView *folderview);
255 static void folderview_drag_received_cb (GtkWidget *widget,
256 GdkDragContext *drag_context,
259 GtkSelectionData *data,
262 FolderView *folderview);
263 static void folderview_start_drag (GtkWidget *widget, gint button, GdkEvent *event,
264 FolderView *folderview);
265 static void folderview_drag_data_get (GtkWidget *widget,
266 GdkDragContext *drag_context,
267 GtkSelectionData *selection_data,
270 FolderView *folderview);
271 static void folderview_drag_end_cb (GtkWidget *widget,
272 GdkDragContext *drag_context,
273 FolderView *folderview);
275 void folderview_create_folder_node (FolderView *folderview,
277 gboolean folderview_update_folder (gpointer source,
279 gboolean folderview_update_item_claws (gpointer source,
281 static void folderview_processing_cb(FolderView *folderview, guint action,
283 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
284 GdkEventButton *event);
286 GHashTable *folderview_popups;
288 static GtkItemFactoryEntry folderview_common_popup_entries[] =
290 {N_("/Mark all re_ad"), NULL, mark_all_read_cb, 0, NULL},
291 {N_("/_Search folder..."), NULL, folderview_search_cb, 0, NULL},
292 {N_("/_Properties..."), NULL, folderview_property_cb, 0, NULL},
293 {N_("/Process_ing..."), NULL, folderview_processing_cb, 0, NULL},
296 static GtkItemFactoryEntry folder_view_trash_popup_entries[] = {
297 {"/------trashsep", NULL, NULL, 0, "<Separator>"},
298 {N_("/Empty _trash..."), NULL, folderview_empty_trash_cb, 0, NULL},
301 static GtkItemFactoryEntry folder_view_queue_popup_entries[] = {
302 {"/------queuesep", NULL, NULL, 0, "<Separator>"},
303 {N_("/Send _queue..."), NULL, folderview_send_queue_cb, 0, NULL},
307 GtkTargetEntry folderview_drag_types[] =
309 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY},
310 {"text/uri-list", 0, TARGET_MAIL_URI_LIST}
313 void folderview_initialize(void)
315 FolderViewPopup *fpopup;
317 GSList *entries = NULL;
319 fpopup = g_new0(FolderViewPopup, 1);
321 n_entries = sizeof(folderview_common_popup_entries) /
322 sizeof(folderview_common_popup_entries[0]);
323 for (i = 0; i < n_entries; i++)
324 entries = g_slist_append(entries, &folderview_common_popup_entries[i]);
326 fpopup->klass = "common";
327 fpopup->path = "<CommonFolder>";
328 fpopup->entries = entries;
329 fpopup->set_sensitivity = NULL;
331 folderview_popups = g_hash_table_new(g_str_hash, g_str_equal);
332 g_hash_table_insert(folderview_popups, "common", fpopup);
335 static GtkItemFactory *create_ifactory(FolderView *folderview, FolderViewPopup *fpopup)
338 GtkItemFactory *factory;
339 FolderViewPopup *fpopup_common;
342 factory = gtk_item_factory_new(GTK_TYPE_MENU, fpopup->path, NULL);
343 gtk_item_factory_set_translate_func(factory, menu_translate,
346 for (entries = fpopup->entries; entries != NULL; entries = g_slist_next(entries))
347 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
349 fpopup_common = g_hash_table_lookup(folderview_popups, "common");
350 if (fpopup_common != fpopup)
351 for (entries = fpopup_common->entries; entries != NULL; entries = g_slist_next(entries))
352 gtk_item_factory_create_item(factory, entries->data, folderview, 1);
354 popup = gtk_item_factory_get_widget(factory, fpopup->path);
355 g_signal_connect(G_OBJECT(popup), "selection_done",
356 G_CALLBACK(folderview_popup_close),
362 static void create_ifactories(gpointer key, gpointer value, gpointer data)
364 FolderView *folderview = data;
365 FolderViewPopup *fpopup = value;
366 GtkItemFactory *factory;
368 factory = create_ifactory(folderview, fpopup);
369 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
372 static void folderview_column_set_titles(FolderView *folderview)
374 GtkWidget *ctree = folderview->ctree;
375 GtkWidget *label_new;
376 GtkWidget *label_unread;
377 GtkWidget *label_total;
379 GtkWidget *hbox_unread;
380 GtkWidget *hbox_total;
381 gint *col_pos = folderview->col_pos;
383 debug_print("setting titles...\n");
384 gtk_widget_realize(folderview->ctree);
385 gtk_widget_show_all(folderview->scrolledwin);
387 /* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
388 * instead text (text overflows making them unreadable and ugly) */
389 stock_pixmap_gdk(ctree, STOCK_PIXMAP_NEW,
390 &newxpm, &newxpmmask);
391 stock_pixmap_gdk(ctree, STOCK_PIXMAP_UNREAD,
392 &unreadxpm, &unreadxpmmask);
393 stock_pixmap_gdk(ctree, STOCK_PIXMAP_READ,
394 &readxpm, &readxpmmask);
396 label_new = gtk_pixmap_new(newxpm, newxpmmask);
397 label_unread = gtk_pixmap_new(unreadxpm, unreadxpmmask);
398 label_total = gtk_pixmap_new(readxpm, readxpmmask);
400 gtk_clist_column_titles_active(GTK_CLIST(ctree));
402 hbox_new = gtk_hbox_new(FALSE, 4);
403 hbox_unread = gtk_hbox_new(FALSE, 4);
404 hbox_total = gtk_hbox_new(FALSE, 4);
407 gtk_box_pack_start(GTK_BOX(hbox_new), label_new, TRUE, TRUE, 0);
408 gtk_misc_set_alignment (GTK_MISC (label_new), 1, 0.5);
409 gtk_box_pack_start(GTK_BOX(hbox_unread), label_unread, TRUE, TRUE, 0);
410 gtk_misc_set_alignment (GTK_MISC (label_unread), 1, 0.5);
411 gtk_box_pack_start(GTK_BOX(hbox_total), label_total, TRUE, TRUE, 0);
412 gtk_misc_set_alignment (GTK_MISC (label_total), 1, 0.5);
414 gtk_widget_show_all(hbox_new);
415 gtk_widget_show_all(hbox_unread);
416 gtk_widget_show_all(hbox_total);
418 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_NEW],hbox_new);
419 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_UNREAD],hbox_unread);
420 gtk_clist_set_column_widget(GTK_CLIST(ctree),col_pos[F_COL_TOTAL],hbox_total);
422 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_NEW], _("New"));
423 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_UNREAD], _("Unread"));
424 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_TOTAL], _("Total"));
427 static gboolean folderview_popup_menu(GtkWidget *widget, gpointer data)
429 FolderView *folderview = (FolderView *)data;
430 GdkEventButton event;
431 if (folderview_get_selected_item(folderview) == NULL)
435 event.time = gtk_get_current_event_time();
437 folderview_set_sens_and_popup_menu(folderview, -1,
444 GtkWidget *folderview_ctree_create(FolderView *folderview)
448 FolderColumnState *col_state;
449 FolderColumnType type;
450 gchar *titles[N_FOLDER_COLS];
452 GtkWidget *scrolledwin = folderview->scrolledwin;
454 debug_print("creating tree...\n");
455 memset(titles, 0, sizeof(titles));
457 col_state = prefs_folder_column_get_config();
458 memset(titles, 0, sizeof(titles));
460 col_pos = folderview->col_pos;
462 for (i = 0; i < N_FOLDER_COLS; i++) {
463 folderview->col_state[i] = col_state[i];
464 type = col_state[i].type;
468 titles[col_pos[F_COL_FOLDER]] = _("Folder");
469 titles[col_pos[F_COL_NEW]] = _("New");
470 titles[col_pos[F_COL_UNREAD]] = _("Unread");
471 /* TRANSLATORS: This in Number sign in American style */
472 titles[col_pos[F_COL_TOTAL]] = _("#");
474 ctree = gtk_sctree_new_with_titles(N_FOLDER_COLS, col_pos[F_COL_FOLDER],
477 gtk_clist_set_selection_mode(GTK_CLIST(ctree), GTK_SELECTION_BROWSE);
478 gtk_clist_set_column_justification(GTK_CLIST(ctree), col_pos[F_COL_NEW],
480 gtk_clist_set_column_justification(GTK_CLIST(ctree),
481 col_pos[F_COL_UNREAD],
483 gtk_clist_set_column_justification(GTK_CLIST(ctree),
484 col_pos[F_COL_TOTAL],
486 if (prefs_common.enable_dotted_lines) {
487 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_DOTTED);
488 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
489 GTK_CTREE_EXPANDER_SQUARE);
491 gtk_ctree_set_line_style(GTK_CTREE(ctree), GTK_CTREE_LINES_NONE);
492 gtk_ctree_set_expander_style(GTK_CTREE(ctree),
493 GTK_CTREE_EXPANDER_TRIANGLE);
496 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
497 gtk_sctree_set_recursive_expand(GTK_SCTREE(ctree), FALSE);
499 gtk_ctree_set_indent(GTK_CTREE(ctree), CTREE_INDENT);
500 gtk_clist_set_compare_func(GTK_CLIST(ctree), folderview_clist_compare);
502 /* don't let title buttons take key focus */
503 for (i = 0; i < N_FOLDER_COLS; i++) {
504 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree)->column[i].button,
506 gtk_clist_set_column_width(GTK_CLIST(ctree), col_pos[i],
507 prefs_common.folder_col_size[i]);
508 gtk_clist_set_column_visibility
509 (GTK_CLIST(ctree), i, col_state[i].visible);
512 g_signal_connect(G_OBJECT(ctree), "key_press_event",
513 G_CALLBACK(folderview_key_pressed),
515 g_signal_connect(G_OBJECT(ctree), "button_press_event",
516 G_CALLBACK(folderview_button_pressed),
518 g_signal_connect(G_OBJECT(ctree), "popup-menu",
519 G_CALLBACK(folderview_popup_menu), folderview);
520 g_signal_connect(G_OBJECT(ctree), "button_release_event",
521 G_CALLBACK(folderview_button_released),
523 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
524 G_CALLBACK(folderview_selected), folderview);
525 g_signal_connect(G_OBJECT(ctree), "start_drag",
526 G_CALLBACK(folderview_start_drag), folderview);
527 g_signal_connect(G_OBJECT(ctree), "drag_data_get",
528 G_CALLBACK(folderview_drag_data_get),
531 g_signal_connect_after(G_OBJECT(ctree), "tree_expand",
532 G_CALLBACK(folderview_tree_expanded),
534 g_signal_connect_after(G_OBJECT(ctree), "tree_collapse",
535 G_CALLBACK(folderview_tree_collapsed),
538 g_signal_connect(G_OBJECT(ctree), "resize_column",
539 G_CALLBACK(folderview_col_resized),
543 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
544 folderview_drag_types, 2,
545 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
546 g_signal_connect(G_OBJECT(ctree), "drag_motion",
547 G_CALLBACK(folderview_drag_motion_cb),
549 g_signal_connect(G_OBJECT(ctree), "drag_leave",
550 G_CALLBACK(folderview_drag_leave_cb),
552 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
553 G_CALLBACK(folderview_drag_received_cb),
555 g_signal_connect(G_OBJECT(ctree), "drag_end",
556 G_CALLBACK(folderview_drag_end_cb),
559 gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
564 void folderview_set_column_order(FolderView *folderview)
567 FolderItem *item = folderview_get_selected_item(folderview);
568 GtkWidget *scrolledwin = folderview->scrolledwin;
570 debug_print("recreating tree...\n");
571 gtk_widget_destroy(folderview->ctree);
573 folderview->ctree = ctree = folderview_ctree_create(folderview);
574 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
575 GTK_CLIST(ctree)->hadjustment);
576 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
577 GTK_CLIST(ctree)->vadjustment);
578 gtk_widget_show(ctree);
580 folderview_set(folderview);
581 folderview_column_set_titles(folderview);
583 folderview_select(folderview,item);
586 FolderView *folderview_create(void)
588 FolderView *folderview;
589 GtkWidget *scrolledwin;
592 debug_print("Creating folder view...\n");
593 folderview = g_new0(FolderView, 1);
595 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
596 gtk_scrolled_window_set_policy
597 (GTK_SCROLLED_WINDOW(scrolledwin),
598 GTK_POLICY_AUTOMATIC,
599 prefs_common.folderview_vscrollbar_policy);
600 gtk_widget_set_size_request(scrolledwin,
601 prefs_common.folderview_width,
602 prefs_common.folderview_height);
604 folderview->scrolledwin = scrolledwin;
605 ctree = folderview_ctree_create(folderview);
607 /* create popup factories */
608 folderview->popups = g_hash_table_new(g_str_hash, g_str_equal);
609 g_hash_table_foreach(folderview_popups, create_ifactories, folderview);
611 folderview->ctree = ctree;
613 folderview->folder_update_callback_id =
614 hooks_register_hook(FOLDER_UPDATE_HOOKLIST, folderview_update_folder, (gpointer) folderview);
615 folderview->folder_item_update_callback_id =
616 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item_claws, (gpointer) folderview);
618 gtk_widget_show_all(scrolledwin);
620 folderview->target_list = gtk_target_list_new(folderview_drag_types, 2);
621 folderview_list = g_list_append(folderview_list, folderview);
626 void folderview_init(FolderView *folderview)
628 GtkWidget *ctree = folderview->ctree;
631 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE, &inboxxpm, &inboxxpmmask);
632 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM, &inboxhrmxpm, &inboxhrmxpmmask);
633 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN, &inboxopenxpm, &inboxopenxpmmask);
634 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM, &inboxopenhrmxpm, &inboxopenhrmxpmmask);
635 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE, &outboxxpm, &outboxxpmmask);
636 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM, &outboxhrmxpm, &outboxhrmxpmmask);
637 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN, &outboxopenxpm, &outboxopenxpmmask);
638 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM, &outboxopenhrmxpm, &outboxopenhrmxpmmask);
639 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE, &folderxpm, &folderxpmmask);
640 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM, &folderhrmxpm, &folderhrmxpmmask);
641 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN, &folderopenxpm, &folderopenxpmmask);
642 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM, &folderopenhrmxpm, &folderopenhrmxpmmask);
643 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN, &trashopenxpm, &trashopenxpmmask);
644 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM, &trashopenhrmxpm, &trashopenhrmxpmmask);
645 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE, &trashxpm, &trashxpmmask);
646 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM, &trashhrmxpm, &trashhrmxpmmask);
647 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE, &queuexpm, &queuexpmmask);
648 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM, &queuehrmxpm, &queuehrmxpmmask);
649 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN, &queueopenxpm, &queueopenxpmmask);
650 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM, &queueopenhrmxpm, &queueopenhrmxpmmask);
651 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE, &draftsxpm, &draftsxpmmask);
652 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN, &draftsopenxpm, &draftsopenxpmmask);
653 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_NOSELECT, &noselectxpm, &noselectxpmmask);
655 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_MARK, &m_inboxxpm, &m_inboxxpmmask);
656 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK, &m_inboxhrmxpm, &m_inboxhrmxpmmask);
657 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_MARK, &m_inboxopenxpm, &m_inboxopenxpmmask);
658 stock_pixmap_gdk(ctree, STOCK_PIXMAP_INBOX_OPEN_HRM_MARK, &m_inboxopenhrmxpm, &m_inboxopenhrmxpmmask);
659 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_MARK, &m_outboxxpm, &m_outboxxpmmask);
660 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK, &m_outboxhrmxpm, &m_outboxhrmxpmmask);
661 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_MARK, &m_outboxopenxpm, &m_outboxopenxpmmask);
662 stock_pixmap_gdk(ctree, STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK, &m_outboxopenhrmxpm, &m_outboxopenhrmxpmmask);
663 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_MARK, &m_folderxpm, &m_folderxpmmask);
664 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_CLOSE_HRM_MARK, &m_folderhrmxpm, &m_folderhrmxpmmask);
665 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_MARK, &m_folderopenxpm, &m_folderopenxpmmask);
666 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DIR_OPEN_HRM_MARK, &m_folderopenhrmxpm, &m_folderopenhrmxpmmask);
667 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_MARK, &m_trashopenxpm, &m_trashopenxpmmask);
668 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_OPEN_HRM_MARK, &m_trashopenhrmxpm, &m_trashopenhrmxpmmask);
669 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_MARK, &m_trashxpm, &m_trashxpmmask);
670 stock_pixmap_gdk(ctree, STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK, &m_trashhrmxpm, &m_trashhrmxpmmask);
671 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_MARK, &m_queuexpm, &m_queuexpmmask);
672 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK, &m_queuehrmxpm, &m_queuehrmxpmmask);
673 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_MARK, &m_queueopenxpm, &m_queueopenxpmmask);
674 stock_pixmap_gdk(ctree, STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK, &m_queueopenhrmxpm, &m_queueopenhrmxpmmask);
675 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_CLOSE_MARK, &m_draftsxpm, &m_draftsxpmmask);
676 stock_pixmap_gdk(ctree, STOCK_PIXMAP_DRAFTS_OPEN_MARK, &m_draftsopenxpm, &m_draftsopenxpmmask);
679 PangoFontDescription *font_desc;
680 normal_style = gtk_style_copy(gtk_widget_get_style(ctree));
681 font_desc = pango_font_description_from_string(NORMAL_FONT);
683 if (normal_style->font_desc)
684 pango_font_description_free
685 (normal_style->font_desc);
686 normal_style->font_desc = font_desc;
688 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
689 normal_color_style = gtk_style_copy(normal_style);
690 normal_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
692 gtk_widget_set_style(ctree, normal_style);
696 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
697 bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
698 pango_font_description_set_weight
699 (bold_style->font_desc, PANGO_WEIGHT_BOLD);
700 bold_color_style = gtk_style_copy(bold_style);
701 bold_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
703 bold_tgtfold_style = gtk_style_copy(bold_style);
704 bold_tgtfold_style->fg[GTK_STATE_NORMAL] = folderview->color_op;
708 void folderview_set(FolderView *folderview)
710 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
711 MainWindow *mainwin = folderview->mainwin;
716 debug_print("Setting folder info...\n");
717 STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
719 main_window_cursor_wait(mainwin);
721 folderview->selected = NULL;
722 folderview->opened = NULL;
724 gtk_clist_freeze(GTK_CLIST(ctree));
725 gtk_clist_clear(GTK_CLIST(ctree));
726 gtk_clist_thaw(GTK_CLIST(ctree));
727 gtk_clist_freeze(GTK_CLIST(ctree));
729 folderview_set_folders(folderview);
731 gtk_clist_thaw(GTK_CLIST(ctree));
732 main_window_cursor_normal(mainwin);
733 STATUSBAR_POP(mainwin);
736 void folderview_set_all(void)
740 for (list = folderview_list; list != NULL; list = list->next)
741 folderview_set((FolderView *)list->data);
744 void folderview_select(FolderView *folderview, FolderItem *item)
746 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
748 GtkCTreeNode *old_selected = folderview->selected;
752 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
753 if (node) folderview_select_node(folderview, node);
755 if (old_selected != node)
756 folder_update_op_count();
759 static void mark_all_read_cb(FolderView *folderview, guint action,
765 item = folderview_get_selected_item(folderview);
769 if (folderview->summaryview->folder_item != item
770 && prefs_common.ask_mark_all_read) {
771 val = alertpanel_full(_("Mark all as read"),
772 _("Do you really want to mark all mails in this "
773 "folder as read ?"), GTK_STOCK_NO, GTK_STOCK_YES, NULL,
774 TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT);
776 if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
778 else if (val & G_ALERTDISABLE)
779 prefs_common.ask_mark_all_read = FALSE;
782 summary_lock(folderview->summaryview);
783 folder_item_update_freeze();
784 if (folderview->summaryview->folder_item == item)
785 summary_freeze(folderview->summaryview);
786 folderutils_mark_all_read(item);
787 if (folderview->summaryview->folder_item == item)
788 summary_thaw(folderview->summaryview);
789 folder_item_update_thaw();
790 summary_unlock(folderview->summaryview);
793 static void folderview_select_node(FolderView *folderview, GtkCTreeNode *node)
795 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
797 g_return_if_fail(node != NULL);
799 if (folderview->open_folder) {
803 folderview->open_folder = TRUE;
804 gtkut_ctree_set_focus_row(ctree, node);
805 gtk_ctree_select(ctree, node);
806 if (folderview->summaryview->folder_item &&
807 folderview->summaryview->folder_item->total_msgs > 0)
808 summary_grab_focus(folderview->summaryview);
810 gtk_widget_grab_focus(folderview->ctree);
812 gtkut_ctree_expand_parent_all(ctree, node);
815 void folderview_unselect(FolderView *folderview)
817 if (folderview->opened && !GTK_CTREE_ROW(folderview->opened)->children)
819 (GTK_CTREE(folderview->ctree), folderview->opened);
821 folderview->selected = folderview->opened = NULL;
824 static GtkCTreeNode *folderview_find_next_marked(GtkCTree *ctree,
830 node = gtkut_ctree_node_next(ctree, node);
832 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
834 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
835 item = gtk_ctree_node_get_row_data(ctree, node);
836 if (item && item->marked_msgs > 0 && item->stype != F_TRASH)
843 void folderview_select_next_marked(FolderView *folderview)
845 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
846 GtkCTreeNode *node = NULL;
847 SelectOnEntry last_sel = prefs_common.select_on_entry;
848 gboolean last_open = prefs_common.always_show_msg;
850 prefs_common.select_on_entry = SELECTONENTRY_MNU;
851 prefs_common.always_show_msg = TRUE;
853 if ((node = folderview_find_next_marked(ctree, folderview->opened))
855 folderview_select_node(folderview, node);
859 if (!folderview->opened ||
860 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
863 /* search again from the first node */
864 if ((node = folderview_find_next_marked(ctree, NULL)) != NULL)
865 folderview_select_node(folderview, node);
868 prefs_common.select_on_entry = last_sel;
869 prefs_common.always_show_msg = last_open;
872 static GtkCTreeNode *folderview_find_next_unread(GtkCTree *ctree,
878 node = gtkut_ctree_node_next(ctree, node);
880 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
882 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
883 item = gtk_ctree_node_get_row_data(ctree, node);
884 if (item && item->unread_msgs > 0 && item->stype != F_TRASH)
891 void folderview_select_next_unread(FolderView *folderview, gboolean force_open)
893 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
894 GtkCTreeNode *node = NULL;
895 SelectOnEntry last_sel = prefs_common.select_on_entry;
896 gboolean last_open = prefs_common.always_show_msg;
898 prefs_common.select_on_entry = SELECTONENTRY_UNM;
899 prefs_common.always_show_msg = force_open ? TRUE : last_open;
901 if ((node = folderview_find_next_unread(ctree, folderview->opened))
903 folderview_select_node(folderview, node);
907 if (!folderview->opened ||
908 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
911 /* search again from the first node */
912 if ((node = folderview_find_next_unread(ctree, NULL)) != NULL)
913 folderview_select_node(folderview, node);
916 prefs_common.select_on_entry = last_sel;
917 prefs_common.always_show_msg = last_open;
920 static GtkCTreeNode *folderview_find_next_new(GtkCTree *ctree,
926 node = gtkut_ctree_node_next(ctree, node);
928 node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
930 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
931 item = gtk_ctree_node_get_row_data(ctree, node);
932 if (item && item->new_msgs > 0 && item->stype != F_TRASH)
939 void folderview_select_next_new(FolderView *folderview)
941 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
942 GtkCTreeNode *node = NULL;
943 SelectOnEntry last_sel = prefs_common.select_on_entry;
944 gboolean last_open = prefs_common.always_show_msg;
946 prefs_common.select_on_entry = SELECTONENTRY_NUM;
947 prefs_common.always_show_msg = TRUE;
949 if ((node = folderview_find_next_new(ctree, folderview->opened))
951 folderview_select_node(folderview, node);
955 if (!folderview->opened ||
956 folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list)) {
959 /* search again from the first node */
960 if ((node = folderview_find_next_new(ctree, NULL)) != NULL)
961 folderview_select_node(folderview, node);
964 prefs_common.select_on_entry = last_sel;
965 prefs_common.always_show_msg = last_open;
968 FolderItem *folderview_get_selected_item(FolderView *folderview)
970 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
972 if (!folderview->selected) return NULL;
973 return gtk_ctree_node_get_row_data(ctree, folderview->selected);
976 void folderview_update_msg_num(FolderView *folderview, GtkCTreeNode *row)
978 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
979 static GtkCTreeNode *prev_row = NULL;
981 gint new, unread, total;
982 gchar *new_str, *unread_str, *total_str;
983 gint *col_pos = folderview->col_pos;
987 item = gtk_ctree_node_get_row_data(ctree, row);
990 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_NEW], &new_str);
991 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_UNREAD], &unread_str);
992 gtk_ctree_node_get_text(ctree, row, col_pos[F_COL_TOTAL], &total_str);
994 unread = atoi(unread_str);
995 total = atoi(total_str);
999 folderview_update_node(folderview, row);
1002 void folderview_append_item(FolderItem *item)
1006 g_return_if_fail(item != NULL);
1007 g_return_if_fail(item->folder != NULL);
1008 if (folder_item_parent(item)) return;
1010 for (list = folderview_list; list != NULL; list = list->next) {
1011 FolderView *folderview = (FolderView *)list->data;
1012 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1013 GtkCTreeNode *node, *child;
1014 gint *col_pos = folderview->col_pos;
1016 node = gtk_ctree_find_by_row_data(ctree, NULL,
1017 folder_item_parent(item));
1019 child = gtk_ctree_find_by_row_data(ctree, node, item);
1021 gchar *text[N_FOLDER_COLS] =
1022 {NULL, "0", "0", "0"};
1024 gtk_clist_freeze(GTK_CLIST(ctree));
1026 text[col_pos[F_COL_FOLDER]] = item->name;
1027 child = gtk_sctree_insert_node
1028 (ctree, node, NULL, text,
1030 folderxpm, folderxpmmask,
1031 folderopenxpm, folderopenxpmmask,
1033 gtk_ctree_node_set_row_data(ctree, child, item);
1034 gtk_ctree_expand(ctree, node);
1035 folderview_update_node(folderview, child);
1036 folderview_sort_folders(folderview, node,
1039 gtk_clist_thaw(GTK_CLIST(ctree));
1045 static void folderview_set_folders(FolderView *folderview)
1048 list = folder_get_list();
1050 for (; list != NULL; list = list->next) {
1051 folderview_append_folder(folderview, FOLDER(list->data));
1055 static gchar *get_scan_str(FolderItem *item)
1058 return g_strdup_printf(_("Scanning folder %s%c%s ..."),
1059 item->folder->name, G_DIR_SEPARATOR,
1062 return g_strdup_printf(_("Scanning folder %s ..."),
1063 item->folder->name);
1065 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
1069 for (list = folderview_list; list != NULL; list = list->next) {
1070 FolderView *folderview = (FolderView *)list->data;
1071 MainWindow *mainwin = folderview->mainwin;
1072 gchar *str = get_scan_str(item);
1074 STATUSBAR_PUSH(mainwin, str);
1075 STATUSBAR_POP(mainwin);
1080 void folderview_rescan_tree(Folder *folder, gboolean rebuild)
1084 g_return_if_fail(folder != NULL);
1086 if (!folder->klass->scan_tree) return;
1089 alertpanel_full(_("Rebuild folder tree"),
1090 _("Rebuilding the folder tree will remove "
1091 "local caches. Do you want to continue?"),
1092 GTK_STOCK_NO, GTK_STOCK_YES, NULL, FALSE,
1093 NULL, ALERT_WARNING, G_ALERTDEFAULT)
1094 != G_ALERTALTERNATE) {
1100 window = label_window_create(_("Rebuilding folder tree..."));
1102 window = label_window_create(_("Scanning folder tree..."));
1104 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1105 folder_scan_tree(folder, rebuild);
1106 folder_set_ui_func(folder, NULL, NULL);
1108 folderview_set_all();
1110 gtk_widget_destroy(window);
1114 /** folderview_check_new()
1115 * Scan and update the folder and return the
1116 * count the number of new messages since last check.
1117 * \param folder the folder to check for new messages
1118 * \return the number of new messages since last check
1120 gint folderview_check_new(Folder *folder)
1124 FolderView *folderview;
1128 gint former_new_msgs = 0;
1129 gint former_new = 0, former_unread = 0, former_total;
1131 for (list = folderview_list; list != NULL; list = list->next) {
1132 folderview = (FolderView *)list->data;
1133 ctree = GTK_CTREE(folderview->ctree);
1136 main_window_lock(folderview->mainwin);
1138 for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
1139 node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
1141 item = gtk_ctree_node_get_row_data(ctree, node);
1142 if (!item || !item->path || !item->folder) continue;
1143 if (item->no_select) continue;
1144 if (folder && folder != item->folder) continue;
1145 if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
1146 if (!item->prefs->newmailcheck) continue;
1147 if (item->processing_pending == TRUE) {
1148 debug_print("skipping %s, processing pending\n",
1149 item->path ? item->path : item->name);
1153 str = get_scan_str(item);
1155 STATUSBAR_PUSH(folderview->mainwin, str);
1159 folderview_scan_tree_func(item->folder, item, NULL);
1160 former_new = item->new_msgs;
1161 former_unread = item->unread_msgs;
1162 former_total = item->total_msgs;
1164 if (item->folder->klass->scan_required &&
1165 (item->folder->klass->scan_required(item->folder, item) ||
1166 item->folder->inbox == item ||
1167 item->opened == TRUE ||
1168 item->processing_pending == TRUE)) {
1169 if (folder_item_scan(item) < 0) {
1170 summaryview_unlock(folderview->summaryview, item);
1171 if (folder && !FOLDER_IS_LOCAL(folder)) {
1172 STATUSBAR_POP(folderview->mainwin);
1176 } else if (!item->folder->klass->scan_required) {
1177 if (folder_item_scan(item) < 0) {
1178 summaryview_unlock(folderview->summaryview, item);
1179 if (folder && !FOLDER_IS_LOCAL(folder)) {
1180 STATUSBAR_POP(folderview->mainwin);
1185 if (former_new != item->new_msgs ||
1186 former_unread != item->unread_msgs ||
1187 former_total != item->total_msgs)
1188 folderview_update_node(folderview, node);
1190 new_msgs += item->new_msgs;
1191 former_new_msgs += former_new;
1192 STATUSBAR_POP(folderview->mainwin);
1195 main_window_unlock(folderview->mainwin);
1199 folder_write_list();
1200 /* Number of new messages since last check is the just the difference
1201 * between former_new_msgs and new_msgs. If new_msgs is less than
1202 * former_new_msgs, that would mean another session accessed the folder
1203 * and the result is not well defined.
1205 new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
1209 void folderview_check_new_all(void)
1213 FolderView *folderview;
1215 folderview = (FolderView *)folderview_list->data;
1218 main_window_lock(folderview->mainwin);
1219 window = label_window_create
1220 (_("Checking for new messages in all folders..."));
1222 list = folder_get_list();
1223 for (; list != NULL; list = list->next) {
1224 Folder *folder = list->data;
1226 folderview_check_new(folder);
1229 folder_write_list();
1230 folderview_set_all();
1232 gtk_widget_destroy(window);
1233 main_window_unlock(folderview->mainwin);
1237 static gboolean folderview_have_new_children_sub(FolderView *folderview,
1243 if (!item || !item->folder || !item->folder->node)
1246 node = item->folder->node;
1248 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1249 node = node->children;
1252 (item->new_msgs > 0 ||
1253 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1257 while (node != NULL) {
1258 if (node && node->data) {
1259 FolderItem *next_item = (FolderItem*) node->data;
1261 if (folderview_have_new_children_sub(folderview,
1270 static gboolean folderview_have_new_children(FolderView *folderview,
1273 return folderview_have_new_children_sub(folderview, item, FALSE);
1276 static gboolean folderview_have_unread_children_sub(FolderView *folderview,
1282 if (!item || !item->folder || !item->folder->node)
1285 node = item->folder->node;
1287 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1288 node = node->children;
1291 (item->unread_msgs > 0 ||
1292 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1296 while (node != NULL) {
1297 if (node && node->data) {
1298 FolderItem *next_item = (FolderItem*) node->data;
1300 if (folderview_have_unread_children_sub(folderview,
1310 static gboolean folderview_have_unread_children(FolderView *folderview,
1313 return folderview_have_unread_children_sub(folderview, item, FALSE);
1316 static gboolean folderview_have_matching_children_sub(FolderView *folderview,
1322 if (!item || !item->folder || !item->folder->node)
1325 node = item->folder->node;
1327 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1328 node = node->children;
1330 if (in_sub && item->search_match){
1334 while (node != NULL) {
1335 if (node && node->data) {
1336 FolderItem *next_item = (FolderItem*) node->data;
1338 if (folderview_have_matching_children_sub(folderview,
1348 static gboolean folderview_have_matching_children(FolderView *folderview,
1351 return folderview_have_matching_children_sub(folderview, item, FALSE);
1354 static gboolean folderview_have_marked_children_sub(FolderView *folderview,
1360 if (!item || !item->folder || !item->folder->node)
1363 node = item->folder->node;
1365 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1366 node = node->children;
1368 if (item->marked_msgs != 0) {
1372 while (node != NULL) {
1373 if (node && node->data) {
1374 FolderItem *next_item = (FolderItem*) node->data;
1376 if (folderview_have_marked_children_sub(folderview,
1385 static gboolean folderview_have_marked_children(FolderView *folderview,
1388 return folderview_have_marked_children_sub(folderview, item, FALSE);
1391 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
1393 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1394 GtkStyle *style = NULL;
1395 GtkStyle *color_style = NULL;
1397 GdkPixmap *xpm, *openxpm;
1398 GdkBitmap *mask, *openmask;
1399 static GdkPixmap *searchicon;
1400 static GdkBitmap *searchmask;
1401 gboolean mark = FALSE;
1404 gboolean add_unread_mark;
1405 gboolean add_sub_match_mark;
1406 gboolean use_bold, use_color;
1407 gint *col_pos = folderview->col_pos;
1408 SpecialFolderItemType stype;
1410 item = gtk_ctree_node_get_row_data(ctree, node);
1411 g_return_if_fail(item != NULL);
1413 if (!GTK_CTREE_ROW(node)->expanded)
1414 mark = folderview_have_marked_children(folderview, item);
1416 mark = (item->marked_msgs != 0);
1418 stype = item->stype;
1419 if (stype == F_NORMAL) {
1420 if (folder_has_parent_of_type(item, F_TRASH))
1422 else if (folder_has_parent_of_type(item, F_DRAFT))
1424 else if (folder_has_parent_of_type(item, F_OUTBOX))
1426 else if (folder_has_parent_of_type(item, F_QUEUE))
1431 if (item->hide_read_msgs) {
1432 xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
1433 mask = mark?m_inboxhrmxpmmask:inboxhrmxpmmask;
1434 openxpm = mark?m_inboxopenhrmxpm:inboxopenhrmxpm;
1435 openmask = mark?m_inboxopenhrmxpmmask:inboxopenhrmxpmmask;
1437 xpm = mark?m_inboxxpm:inboxxpm;
1438 mask = mark?m_inboxxpmmask:inboxxpmmask;
1439 openxpm = mark?m_inboxopenxpm:inboxopenxpm;
1440 openmask = mark?m_inboxopenxpmmask:inboxopenxpmmask;
1444 if (item->hide_read_msgs) {
1445 xpm = mark?m_outboxhrmxpm:outboxhrmxpm;
1446 mask = mark?m_outboxhrmxpmmask:outboxhrmxpmmask;
1447 openxpm = mark?m_outboxopenhrmxpm:outboxopenhrmxpm;
1448 openmask = mark?m_outboxopenhrmxpmmask:outboxopenhrmxpmmask;
1450 xpm = mark?m_outboxxpm:outboxxpm;
1451 mask = mark?m_outboxxpmmask:outboxxpmmask;
1452 openxpm = mark?m_outboxopenxpm:outboxopenxpm;
1453 openmask = mark?m_outboxopenxpmmask:outboxopenxpmmask;
1457 if (item->hide_read_msgs) {
1458 xpm = mark?m_queuehrmxpm:queuehrmxpm;
1459 mask = mark?m_queuehrmxpmmask:queuehrmxpmmask;
1460 openxpm = mark?m_queueopenhrmxpm:queueopenhrmxpm;
1461 openmask = mark?m_queueopenhrmxpmmask:queueopenhrmxpmmask;
1463 xpm = mark?m_queuexpm:queuexpm;
1464 mask = mark?m_queuexpmmask:queuexpmmask;
1465 openxpm = mark?m_queueopenxpm:queueopenxpm;
1466 openmask = mark?m_queueopenxpmmask:queueopenxpmmask;
1470 if (item->hide_read_msgs) {
1471 xpm = mark?m_trashhrmxpm:trashhrmxpm;
1472 mask = mark?m_trashhrmxpmmask:trashhrmxpmmask;
1473 openxpm = mark?m_trashopenhrmxpm:trashopenhrmxpm;
1474 openmask = mark?m_trashopenhrmxpmmask:trashopenhrmxpmmask;
1476 xpm = mark?m_trashxpm:trashxpm;
1477 mask = mark?m_trashxpmmask:trashxpmmask;
1478 openxpm = mark?m_trashopenxpm:trashopenxpm;
1479 openmask = mark?m_trashopenxpmmask:trashopenxpmmask;
1483 xpm = mark?m_draftsxpm:draftsxpm;
1484 mask = mark?m_draftsxpmmask:draftsxpmmask;
1485 openxpm = mark?m_draftsopenxpm:draftsopenxpm;
1486 openmask = mark?m_draftsopenxpmmask:draftsopenxpmmask;
1489 if (item->hide_read_msgs) {
1490 xpm = mark?m_folderhrmxpm:folderhrmxpm;
1491 mask = mark?m_folderhrmxpmmask:folderhrmxpmmask;
1492 openxpm = mark?m_folderopenhrmxpm:folderopenhrmxpm;
1493 openmask = mark?m_folderopenhrmxpmmask:folderopenhrmxpmmask;
1495 xpm = mark?m_folderxpm:folderxpm;
1496 mask = mark?m_folderxpmmask:folderxpmmask;
1497 openxpm = mark?m_folderopenxpm:folderopenxpm;
1498 openmask = mark?m_folderopenxpmmask:folderopenxpmmask;
1502 if (item->no_select) {
1503 xpm = openxpm = noselectxpm;
1504 mask = openmask = noselectxpmmask;
1507 name = folder_item_get_name(item);
1509 if (!GTK_CTREE_ROW(node)->expanded) {
1510 add_unread_mark = folderview_have_unread_children(
1512 add_sub_match_mark = folderview_have_matching_children(
1515 add_unread_mark = FALSE;
1516 add_sub_match_mark = FALSE;
1519 if (item->search_match) {
1521 stock_pixmap_gdk(folderview->ctree, STOCK_PIXMAP_QUICKSEARCH,
1522 &searchicon, &searchmask);
1524 xpm = openxpm = searchicon;
1525 mask = openmask = searchmask;
1528 if (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0 &&
1529 prefs_common.display_folder_unread) {
1530 str = g_strdup_printf("%s (%d%s)", name, item->total_msgs,
1531 add_unread_mark ? "+" : "");
1532 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1533 xpm, mask, openxpm, openmask,
1534 FALSE, GTK_CTREE_ROW(node)->expanded);
1536 } else if (((item->unread_msgs > 0 || add_unread_mark) &&
1537 prefs_common.display_folder_unread)
1538 || add_sub_match_mark) {
1540 if (item->unread_msgs > 0)
1541 str = g_strdup_printf("%s (%d%s%s)", name, item->unread_msgs,
1542 add_unread_mark || add_sub_match_mark ? "+" : "",
1543 item->unreadmarked_msgs > 0 ? "!":"");
1545 str = g_strdup_printf("%s (+)", name);
1546 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1547 xpm, mask, openxpm, openmask,
1548 FALSE, GTK_CTREE_ROW(node)->expanded);
1551 str = g_strdup_printf("%s%s", name,
1552 item->unreadmarked_msgs > 0 ? " (!)":"");
1554 gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1555 xpm, mask, openxpm, openmask,
1556 FALSE, GTK_CTREE_ROW(node)->expanded);
1561 if (!folder_item_parent(item)) {
1562 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], "-");
1563 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
1564 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], "-");
1566 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_NEW], itos(item->new_msgs));
1567 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], itos(item->unread_msgs));
1568 gtk_ctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], itos(item->total_msgs));
1571 if (folder_has_parent_of_type(item, F_OUTBOX) ||
1572 folder_has_parent_of_type(item, F_DRAFT) ||
1573 folder_has_parent_of_type(item, F_TRASH)) {
1574 use_bold = use_color = FALSE;
1575 } else if (folder_has_parent_of_type(item, F_QUEUE)) {
1576 /* highlight queue folder if there are any messages */
1577 use_bold = use_color = (item->total_msgs > 0);
1579 /* if unread messages exist, print with bold font */
1580 use_bold = (item->unread_msgs > 0|| item->new_msgs > 0)
1582 /* if new messages exist, print with colored letter */
1584 (item->new_msgs > 0) ||
1586 folderview_have_new_children(folderview, item));
1589 gtk_ctree_node_set_foreground(ctree, node, NULL);
1594 if (item->prefs->color > 0 && !use_color) {
1595 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1596 color_style = gtk_style_copy(bold_style);
1597 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1598 style = color_style;
1599 } else if (use_color) {
1600 style = bold_color_style;
1603 if (item->op_count > 0) {
1604 style = bold_tgtfold_style;
1606 } else if (use_color) {
1607 style = normal_color_style;
1608 gtk_ctree_node_set_foreground(ctree, node,
1609 &folderview->color_new);
1610 } else if (item->op_count > 0) {
1611 style = bold_tgtfold_style;
1612 } else if (item->prefs->color > 0) {
1614 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1615 color_style = gtk_style_copy(normal_style);
1616 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1617 style = color_style;
1619 style = normal_style;
1622 gtk_ctree_node_set_row_style(ctree, node, style);
1624 if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1625 folderview_update_node(folderview, node);
1628 #if !CLAWS /* keep it here for syncs */
1629 void folderview_update_item(FolderItem *item, gboolean update_summary)
1632 FolderView *folderview;
1636 g_return_if_fail(item != NULL);
1638 for (list = folderview_list; list != NULL; list = list->next) {
1639 folderview = (FolderView *)list->data;
1640 ctree = GTK_CTREE(folderview->ctree);
1642 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1644 folderview_update_node(folderview, node);
1645 if (update_summary && folderview->opened == node)
1646 summary_show(folderview->summaryview,
1653 void folderview_update_search_icon(FolderItem *item, gboolean matches)
1656 FolderView *folderview;
1660 g_return_if_fail(item != NULL);
1662 for (list = folderview_list; list != NULL; list = list->next) {
1663 folderview = (FolderView *)list->data;
1664 ctree = GTK_CTREE(folderview->ctree);
1666 node = gtk_ctree_find_by_row_data(ctree, NULL, item);
1668 item->search_match = matches;
1669 folderview_update_node(folderview, node);
1674 gboolean folderview_update_item_claws(gpointer source, gpointer data)
1676 FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1677 FolderView *folderview = (FolderView *)data;
1680 g_return_val_if_fail(update_info != NULL, TRUE);
1681 g_return_val_if_fail(update_info->item != NULL, TRUE);
1682 g_return_val_if_fail(folderview != NULL, FALSE);
1684 ctree = GTK_CTREE(folderview->ctree);
1686 node = gtk_ctree_find_by_row_data(ctree, NULL, update_info->item);
1689 if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
1690 folderview_update_node(folderview, node);
1691 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) && (folderview->opened == node))
1692 if (!quicksearch_is_active(folderview->summaryview->quicksearch))
1693 summary_show(folderview->summaryview, update_info->item);
1699 static void folderview_update_item_foreach_func(gpointer key, gpointer val,
1702 /* CLAWS: share this joy with other hook functions ... */
1703 folder_item_update((FolderItem *)key,
1704 (FolderItemUpdateFlags)GPOINTER_TO_INT(data));
1707 void folderview_update_item_foreach(GHashTable *table, gboolean update_summary)
1710 FolderItemUpdateFlags flags;
1712 flags = update_summary ? F_ITEM_UPDATE_CONTENT | F_ITEM_UPDATE_MSGCNT
1714 for (list = folderview_list; list != NULL; list = list->next)
1715 g_hash_table_foreach(table, folderview_update_item_foreach_func,
1716 GINT_TO_POINTER(flags));
1719 static gboolean folderview_gnode_func(GtkCTree *ctree, guint depth,
1720 GNode *gnode, GtkCTreeNode *cnode,
1723 FolderView *folderview = (FolderView *)data;
1724 FolderItem *item = FOLDER_ITEM(gnode->data);
1726 g_return_val_if_fail(item != NULL, FALSE);
1728 gtk_ctree_node_set_row_data(ctree, cnode, item);
1729 folderview_update_node(folderview, cnode);
1734 static void folderview_expand_func(GtkCTree *ctree, GtkCTreeNode *node,
1737 FolderView *folderview = (FolderView *)data;
1740 if (GTK_CTREE_ROW(node)->children) {
1741 item = gtk_ctree_node_get_row_data(ctree, node);
1742 g_return_if_fail(item != NULL);
1744 if (!item->collapsed)
1745 gtk_ctree_expand(ctree, node);
1747 folderview_update_node(folderview, node);
1751 static void set_special_folder(GtkCTree *ctree, FolderItem *item,
1752 GtkCTreeNode *root, GtkCTreeNode **prev)
1755 GtkCTreeNode *node, *parent, *sibling;
1757 node = gtk_ctree_find_by_row_data(ctree, root, item);
1759 g_warning("%s not found.\n", item->path);
1761 parent = GTK_CTREE_ROW(node)->parent;
1762 if (*prev && parent == GTK_CTREE_ROW(*prev)->parent)
1763 sibling = GTK_CTREE_ROW(*prev)->sibling;
1765 sibling = GTK_CTREE_ROW(parent)->children;
1769 tmp = gtk_ctree_node_get_row_data
1771 if (tmp->stype != F_NORMAL)
1772 sibling = GTK_CTREE_ROW(sibling)->sibling;
1776 if (node != sibling)
1777 gtk_ctree_move(ctree, node, parent, sibling);
1784 static void folderview_sort_folders(FolderView *folderview, GtkCTreeNode *root,
1787 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1788 GtkCTreeNode *prev = NULL;
1790 gtk_clist_freeze(GTK_CLIST(ctree));
1791 gtk_sctree_sort_recursive(ctree, root);
1792 if (root && GTK_CTREE_ROW(root)->parent) {
1793 gtk_clist_thaw(GTK_CLIST(ctree));
1796 set_special_folder(ctree, folder->inbox, root, &prev);
1797 set_special_folder(ctree, folder->outbox, root, &prev);
1798 set_special_folder(ctree, folder->draft, root, &prev);
1799 set_special_folder(ctree, folder->queue, root, &prev);
1800 set_special_folder(ctree, folder->trash, root, &prev);
1801 gtk_clist_thaw(GTK_CLIST(ctree));
1804 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1806 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
1809 g_return_if_fail(folder != NULL);
1811 root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
1812 folderview_gnode_func, folderview);
1813 gtk_ctree_pre_recursive(ctree, root, folderview_expand_func,
1815 folderview_sort_folders(folderview, root, folder);
1818 /* callback functions */
1819 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
1820 GdkEventButton *event)
1822 GtkCList *clist = GTK_CLIST(folderview->ctree);
1825 FolderViewPopup *fpopup;
1826 GtkItemFactory *fpopup_factory;
1828 FolderItem *special_trash = NULL, *special_queue = NULL;
1832 item = gtk_clist_get_row_data(clist, row);
1834 item = folderview_get_selected_item(folderview);
1836 g_return_if_fail(item != NULL);
1837 g_return_if_fail(item->folder != NULL);
1838 folder = item->folder;
1840 fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1842 fpopup_factory = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1844 fpopup = g_hash_table_lookup(folderview_popups, "common");
1845 fpopup_factory = g_hash_table_lookup(folderview->popups, "common");
1848 if (fpopup->set_sensitivity != NULL)
1849 fpopup->set_sensitivity(fpopup_factory, item);
1851 if (NULL != (ac = account_find_from_item(item))) {
1852 special_trash = account_get_special_folder(ac, F_TRASH);
1853 special_queue = account_get_special_folder(ac, F_QUEUE);
1856 if ((item == folder->trash || item == special_trash
1857 || folder_has_parent_of_type(item, F_TRASH)) &&
1858 gtk_item_factory_get_item(fpopup_factory, "/Empty trash...") == NULL) {
1859 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[0], folderview, 1);
1860 gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[1], folderview, 1);
1861 } else if (item != folder->trash && (special_trash == NULL || item != special_trash)
1862 && !folder_has_parent_of_type(item, F_TRASH)) {
1863 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[0]);
1864 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[1]);
1867 if ((item == folder->queue || item == special_queue
1868 || folder_has_parent_of_type(item, F_QUEUE)) &&
1869 gtk_item_factory_get_item(fpopup_factory, "/Send queue...") == NULL) {
1870 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[0], folderview, 1);
1871 gtk_item_factory_create_item(fpopup_factory, &folder_view_queue_popup_entries[1], folderview, 1);
1872 } else if (item != folder->queue && (special_queue == NULL || item != special_queue)
1873 && !folder_has_parent_of_type(item, F_QUEUE)) {
1874 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[0]);
1875 gtk_item_factory_delete_entry(fpopup_factory, &folder_view_queue_popup_entries[1]);
1878 #define SET_SENS(name, sens) \
1879 menu_set_sensitive(fpopup_factory, name, sens)
1881 SET_SENS("/Mark all read", item->unread_msgs >= 1);
1882 SET_SENS("/Search folder...", item->total_msgs >= 1 &&
1883 folderview->selected == folderview->opened);
1884 SET_SENS("/Properties...", TRUE);
1885 SET_SENS("/Processing...", item->node->parent != NULL);
1886 if (item == folder->trash || item == special_trash
1887 || folder_has_parent_of_type(item, F_TRASH)) {
1888 GSList *msglist = folder_item_get_msg_list(item);
1889 SET_SENS("/Empty trash...", msglist != NULL);
1890 procmsg_msg_list_free(msglist);
1892 if (item == folder->queue || item == special_queue
1893 || folder_has_parent_of_type(item, F_QUEUE)) {
1894 GSList *msglist = folder_item_get_msg_list(item);
1895 SET_SENS("/Send queue...", msglist != NULL);
1896 procmsg_msg_list_free(msglist);
1900 popup = gtk_item_factory_get_widget(fpopup_factory, fpopup->path);
1901 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1902 event->button, event->time);
1907 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1908 FolderView *folderview)
1910 GtkCList *clist = GTK_CLIST(ctree);
1911 gint prev_row = -1, row = -1, column = -1;
1913 if (!event) return FALSE;
1915 if (event->button == 1 || event->button == 2) {
1916 if (!gtk_ctree_is_hot_spot (GTK_CTREE(clist), event->x, event->y))
1917 folderview->open_folder = TRUE;
1919 if (event->type == GDK_2BUTTON_PRESS) {
1920 if (clist->selection) {
1923 node = GTK_CTREE_NODE(clist->selection->data);
1925 gtk_ctree_toggle_expansion(
1928 folderview->open_folder = FALSE;
1935 if (event->button == 2 || event->button == 3) {
1937 if (clist->selection) {
1940 node = GTK_CTREE_NODE(clist->selection->data);
1942 prev_row = gtkut_ctree_get_nth_from_node
1943 (GTK_CTREE(ctree), node);
1946 if (!gtk_clist_get_selection_info(clist, event->x, event->y,
1949 if (prev_row != row) {
1950 gtk_clist_unselect_all(clist);
1951 if (event->button == 2)
1952 folderview_select_node
1954 gtk_ctree_node_nth(GTK_CTREE(ctree),
1957 gtk_clist_select_row(clist, row, column);
1961 if (event->button != 3) return FALSE;
1963 folderview_set_sens_and_popup_menu(folderview, row, event);
1967 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1968 FolderView *folderview)
1970 if (!event) return FALSE;
1972 if (event->button == 1 && folderview->open_folder == FALSE &&
1973 folderview->opened != NULL) {
1974 gtkut_ctree_set_focus_row(GTK_CTREE(ctree),
1975 folderview->opened);
1976 gtk_ctree_select(GTK_CTREE(ctree), folderview->opened);
1982 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
1983 FolderView *folderview)
1985 if (!event) return FALSE;
1987 if (quicksearch_has_focus(folderview->summaryview->quicksearch))
1990 switch (event->keyval) {
1992 if (folderview->selected) {
1993 folderview_select_node(folderview,
1994 folderview->selected);
1998 if (folderview->selected) {
1999 if (folderview->opened == folderview->selected &&
2000 (!folderview->summaryview->folder_item ||
2001 folderview->summaryview->folder_item->total_msgs == 0))
2002 folderview_select_next_unread(folderview, TRUE);
2004 folderview_select_node(folderview,
2005 folderview->selected);
2015 typedef struct _PostponedSelectData
2020 FolderView *folderview;
2021 } PostponedSelectData;
2023 static gboolean postpone_select(void *data)
2025 PostponedSelectData *psdata = (PostponedSelectData *)data;
2026 debug_print("trying again\n");
2027 psdata->folderview->open_folder = TRUE;
2028 main_window_cursor_normal(psdata->folderview->mainwin);
2029 STATUSBAR_POP(psdata->folderview->mainwin);
2030 folderview_selected(psdata->ctree, psdata->row,
2031 psdata->column, psdata->folderview);
2036 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
2037 gint column, FolderView *folderview)
2039 static gboolean can_select = TRUE; /* exclusive lock */
2045 folderview->selected = row;
2047 if (folderview->opened == row) {
2048 folderview->open_folder = FALSE;
2053 if (!can_select || summary_is_locked(folderview->summaryview)) {
2054 if (folderview->opened) {
2055 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2056 gtk_ctree_select(ctree, folderview->opened);
2062 if (!folderview->open_folder) {
2066 item = gtk_ctree_node_get_row_data(ctree, row);
2067 if (!item || item->no_select) {
2069 folderview->open_folder = FALSE;
2075 /* Save cache for old folder */
2076 /* We don't want to lose all caches if sylpheed crashed */
2077 if (folderview->opened) {
2078 FolderItem *olditem;
2080 olditem = gtk_ctree_node_get_row_data(ctree, folderview->opened);
2082 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 /* CLAWS: set compose button type: news folder items
2097 * always have a news folder as parent */
2099 toolbar_set_compose_button
2100 (folderview->mainwin->toolbar,
2101 FOLDER_TYPE(item->folder) == F_NEWS ?
2102 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
2105 debug_print("Folder %s is selected\n", item->path);
2107 if (!GTK_CTREE_ROW(row)->children)
2108 gtk_ctree_expand(ctree, row);
2109 if (folderview->opened &&
2110 !GTK_CTREE_ROW(folderview->opened)->children)
2111 gtk_ctree_collapse(ctree, folderview->opened);
2113 /* ungrab the mouse event */
2114 if (GTK_WIDGET_HAS_GRAB(ctree)) {
2115 gtk_grab_remove(GTK_WIDGET(ctree));
2116 if (gdk_pointer_is_grabbed())
2117 gdk_pointer_ungrab(GDK_CURRENT_TIME);
2121 buf = g_strdup_printf(_("Opening Folder %s..."), item->path ?
2122 item->path : "(null)");
2123 debug_print("%s\n", buf);
2124 STATUSBAR_PUSH(folderview->mainwin, buf);
2127 main_window_cursor_wait(folderview->mainwin);
2129 res = folder_item_open(item);
2131 main_window_cursor_normal(folderview->mainwin);
2132 STATUSBAR_POP(folderview->mainwin);
2134 alertpanel_error(_("Folder could not be opened."));
2136 folderview->open_folder = FALSE;
2140 } else if (res == -2) {
2141 PostponedSelectData *data = g_new0(PostponedSelectData, 1);
2142 data->ctree = ctree;
2144 data->column = column;
2145 data->folderview = folderview;
2146 debug_print("postponing open of %s till end of scan\n",
2147 item->path ? item->path:item->name);
2148 folderview->open_folder = FALSE;
2150 g_timeout_add(500, postpone_select, data);
2155 main_window_cursor_normal(folderview->mainwin);
2158 summary_set_prefs_from_folderitem(folderview->summaryview, item);
2159 opened = summary_show(folderview->summaryview, item);
2161 folder_clean_cache_memory(item);
2164 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2165 gtk_ctree_select(ctree, folderview->opened);
2167 folderview->opened = row;
2168 if (gtk_ctree_node_is_visible(ctree, row)
2169 != GTK_VISIBILITY_FULL)
2170 gtk_ctree_node_moveto(ctree, row, -1, 0.5, 0);
2173 STATUSBAR_POP(folderview->mainwin);
2175 folderview->open_folder = FALSE;
2180 static void folderview_tree_expanded(GtkCTree *ctree, GtkCTreeNode *node,
2181 FolderView *folderview)
2185 item = gtk_ctree_node_get_row_data(ctree, node);
2186 g_return_if_fail(item != NULL);
2187 item->collapsed = FALSE;
2188 folderview_update_node(folderview, node);
2191 static void folderview_tree_collapsed(GtkCTree *ctree, GtkCTreeNode *node,
2192 FolderView *folderview)
2196 item = gtk_ctree_node_get_row_data(ctree, node);
2197 g_return_if_fail(item != NULL);
2198 item->collapsed = TRUE;
2199 folderview_update_node(folderview, node);
2202 static void folderview_popup_close(GtkMenuShell *menu_shell,
2203 FolderView *folderview)
2205 if (!folderview->opened) return;
2207 gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
2210 static void folderview_col_resized(GtkCList *clist, gint column, gint width,
2211 FolderView *folderview)
2213 FolderColumnType type = folderview->col_state[column].type;
2215 prefs_common.folder_col_size[type] = width;
2218 void folderview_create_folder_node_recursive(FolderView *folderview, FolderItem *item)
2222 folderview_create_folder_node(folderview, item);
2224 if (!item || !item->folder || !item->folder->node)
2227 srcnode = item->folder->node;
2228 srcnode = g_node_find(srcnode, G_PRE_ORDER, G_TRAVERSE_ALL, item);
2229 srcnode = srcnode->children;
2230 while (srcnode != NULL) {
2231 if (srcnode && srcnode->data) {
2232 FolderItem *next_item = (FolderItem*) srcnode->data;
2233 folderview_create_folder_node_recursive(folderview, next_item);
2235 srcnode = srcnode->next;
2239 void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
2241 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2242 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2243 GtkCTreeNode *node, *parent_node;
2244 gint *col_pos = folderview->col_pos;
2245 FolderItemUpdateData hookdata;
2247 parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
2248 if (parent_node == NULL)
2251 gtk_clist_freeze(GTK_CLIST(ctree));
2253 text[col_pos[F_COL_FOLDER]] = item->name;
2254 node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
2256 folderxpm, folderxpmmask,
2257 folderopenxpm, folderopenxpmmask,
2259 gtk_ctree_expand(ctree, parent_node);
2260 gtk_ctree_node_set_row_data(ctree, node, item);
2262 gtk_ctree_node_set_row_style(ctree, node, normal_style);
2263 folderview_sort_folders(folderview, parent_node, item->folder);
2265 hookdata.item = item;
2266 hookdata.update_flags = F_ITEM_UPDATE_NAME;
2267 hookdata.msg = NULL;
2268 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
2270 gtk_clist_thaw(GTK_CLIST(ctree));
2273 static void folderview_empty_trash_cb(FolderView *folderview, guint action,
2276 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2278 GSList *mlist = NULL;
2280 FolderItem *special_trash = NULL;
2283 if (!folderview->selected) return;
2284 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2285 g_return_if_fail(item != NULL);
2286 g_return_if_fail(item->folder != NULL);
2288 if (NULL != (ac = account_find_from_item(item)))
2289 special_trash = account_get_special_folder(ac, F_TRASH);
2291 if (item != item->folder->trash && item != special_trash
2292 && !folder_has_parent_of_type(item, F_TRASH)) return;
2294 if (prefs_common.ask_on_clean) {
2295 if (alertpanel(_("Empty trash"),
2296 _("Delete all messages in trash?"),
2297 GTK_STOCK_CANCEL, _("+_Empty trash"), NULL) != G_ALERTALTERNATE)
2301 mlist = folder_item_get_msg_list(item);
2303 for (cur = mlist ; cur != NULL ; cur = cur->next) {
2304 MsgInfo * msginfo = (MsgInfo *) cur->data;
2305 if (MSG_IS_LOCKED(msginfo->flags))
2307 /* is it partially received? (partial_recv isn't cached) */
2308 if (msginfo->total_size != 0 &&
2309 msginfo->size != (off_t)msginfo->total_size)
2310 partial_mark_for_delete(msginfo);
2312 procmsg_msg_list_free(mlist);
2314 folder_item_remove_all_msg(item);
2317 static void folderview_send_queue_cb(FolderView *folderview, guint action,
2320 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2322 FolderItem *special_queue = NULL;
2324 gchar *errstr = NULL;
2326 if (!folderview->selected) return;
2327 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2328 g_return_if_fail(item != NULL);
2329 g_return_if_fail(item->folder != NULL);
2331 if (NULL != (ac = account_find_from_item(item)))
2332 special_queue = account_get_special_folder(ac, F_QUEUE);
2334 if (item != item->folder->queue && item != special_queue
2335 && !folder_has_parent_of_type(item, F_QUEUE)) return;
2337 if (procmsg_queue_is_empty(item))
2340 if (prefs_common.work_offline)
2341 if (alertpanel(_("Offline warning"),
2342 _("You're working offline. Override?"),
2343 GTK_STOCK_NO, GTK_STOCK_YES,
2344 NULL) != G_ALERTALTERNATE)
2347 /* ask for confirmation before sending queued messages only
2348 in online mode and if there is at least one message queued
2349 in any of the folder queue
2351 if (prefs_common.confirm_send_queued_messages) {
2352 if (!prefs_common.work_offline) {
2353 if (alertpanel(_("Send queued messages"),
2354 _("Send all queued messages?"),
2355 GTK_STOCK_CANCEL, _("_Send"),
2356 NULL) != G_ALERTALTERNATE)
2361 if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
2363 alertpanel_error_log(_("Some errors occurred while "
2364 "sending queued messages."));
2366 gchar *tmp = g_strdup_printf(_("Some errors occurred "
2367 "while sending queued messages:\n%s"), errstr);
2369 alertpanel_error_log(tmp);
2375 static void folderview_search_cb(FolderView *folderview, guint action,
2378 summary_search(folderview->summaryview);
2381 static void folderview_property_cb(FolderView *folderview, guint action,
2384 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2387 if (!folderview->selected) return;
2389 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2390 g_return_if_fail(item != NULL);
2391 g_return_if_fail(item->folder != NULL);
2393 prefs_folder_item_open(item);
2396 static void folderview_recollapse_nodes(FolderView *folderview, GtkCTreeNode *node)
2398 GSList *list = NULL;
2399 GSList *done = NULL;
2400 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2402 for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2403 if (!gtkut_ctree_node_is_parent(GTK_CTREE_NODE(list->data), node)
2404 && list->data != node) {
2405 gtk_ctree_collapse(ctree, GTK_CTREE_NODE(list->data));
2406 done = g_slist_append(done, GTK_CTREE_NODE(list->data));
2409 for (list = done; list != NULL; list = g_slist_next(list)) {
2410 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse,
2416 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
2417 FolderItem *to_folder)
2419 FolderItem *from_parent = NULL;
2420 FolderItem *new_folder = NULL;
2421 GtkCTreeNode *src_node = NULL;
2425 g_return_if_fail(folderview != NULL);
2426 g_return_if_fail(from_folder != NULL);
2427 g_return_if_fail(to_folder != NULL);
2429 src_node = gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree), NULL, from_folder);
2430 from_parent = folder_item_parent(from_folder);
2432 if (prefs_common.warn_dnd) {
2433 buf = g_strdup_printf(_("Do you really want to make folder '%s' a "
2434 "sub-folder of '%s' ?"), from_folder->name,
2436 status = alertpanel_full(_("Move folder"), buf,
2437 GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE,
2438 NULL, ALERT_QUESTION, G_ALERTDEFAULT);
2441 if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
2443 else if (status & G_ALERTDISABLE)
2444 prefs_common.warn_dnd = FALSE;
2447 buf = g_strdup_printf(_("Moving %s to %s..."), from_folder->name, to_folder->name);
2448 STATUSBAR_PUSH(folderview->mainwin, buf);
2450 summary_clear_all(folderview->summaryview);
2451 folderview->opened = NULL;
2452 folderview->selected = NULL;
2453 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2455 main_window_cursor_wait(folderview->mainwin);
2456 statusbar_verbosity_set(TRUE);
2457 folder_item_update_freeze();
2458 if ((status = folder_item_move_to(from_folder, to_folder, &new_folder)) == F_MOVE_OK) {
2459 statusbar_verbosity_set(FALSE);
2460 main_window_cursor_normal(folderview->mainwin);
2461 STATUSBAR_POP(folderview->mainwin);
2462 folder_item_update_thaw();
2463 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2465 folderview_sort_folders(folderview,
2466 gtk_ctree_find_by_row_data(GTK_CTREE(folderview->ctree),
2467 NULL, to_folder), new_folder->folder);
2468 folderview_select(folderview, new_folder);
2470 statusbar_verbosity_set(FALSE);
2471 main_window_cursor_normal(folderview->mainwin);
2472 STATUSBAR_POP(folderview->mainwin);
2473 folder_item_update_thaw();
2475 case F_MOVE_FAILED_DEST_IS_PARENT:
2476 alertpanel_error(_("Source and destination are the same."));
2478 case F_MOVE_FAILED_DEST_IS_CHILD:
2479 alertpanel_error(_("Can't move a folder to one of its children."));
2481 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2482 alertpanel_error(_("Folder moving cannot be done between different mailboxes."));
2485 alertpanel_error(_("Move failed!"));
2490 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2493 static gint folderview_clist_compare(GtkCList *clist,
2494 gconstpointer ptr1, gconstpointer ptr2)
2496 FolderItem *item1 = ((GtkCListRow *)ptr1)->data;
2497 FolderItem *item2 = ((GtkCListRow *)ptr2)->data;
2500 return (item2->name != NULL);
2504 return g_utf8_collate(item1->name, item2->name);
2507 static void folderview_processing_cb(FolderView *folderview, guint action,
2510 GtkCTree *ctree = GTK_CTREE(folderview->ctree);
2514 if (!folderview->selected) return;
2516 item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
2517 g_return_if_fail(item != NULL);
2518 g_return_if_fail(item->folder != NULL);
2520 id = folder_item_get_identifier(item);
2521 title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2524 prefs_filtering_open(&item->prefs->processing, title,
2525 MANUAL_ANCHOR_PROCESSING, NULL, NULL, FALSE);
2529 void folderview_set_target_folder_color(gint color_op)
2533 FolderView *folderview;
2535 for (list = folderview_list; list != NULL; list = list->next) {
2536 folderview = (FolderView *)list->data;
2537 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2539 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2540 folderview->color_op;
2546 static gchar *last_font = NULL;
2547 void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
2555 void folderview_reflect_prefs(void)
2557 gboolean update_font = TRUE;
2558 FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2559 FolderItem *item = folderview_get_selected_item(folderview);
2560 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2561 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2562 gint height = pos->value;
2564 if (last_font && !strcmp(last_font, NORMAL_FONT))
2565 update_font = FALSE;
2568 last_font = g_strdup(NORMAL_FONT);
2571 normal_style = normal_color_style = bold_style =
2572 bold_color_style = bold_tgtfold_style = NULL;
2574 folderview_init(folderview);
2576 gtk_clist_freeze(GTK_CLIST(folderview->ctree));
2577 folderview_column_set_titles(folderview);
2578 folderview_set_all();
2580 g_signal_handlers_block_by_func
2581 (G_OBJECT(folderview->ctree),
2582 G_CALLBACK(folderview_selected), folderview);
2585 GtkCTreeNode *node = gtk_ctree_find_by_row_data(
2586 GTK_CTREE(folderview->ctree), NULL, item);
2588 folderview_select(folderview, item);
2589 folderview->open_folder = FALSE;
2590 folderview->selected = node;
2593 g_signal_handlers_unblock_by_func
2594 (G_OBJECT(folderview->ctree),
2595 G_CALLBACK(folderview_selected), folderview);
2597 pos = gtk_scrolled_window_get_vadjustment(
2598 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2599 gtk_adjustment_set_value(pos, height);
2600 gtk_clist_thaw(GTK_CLIST(folderview->ctree));
2603 static void drag_state_stop(FolderView *folderview)
2605 if (folderview->drag_timer)
2606 gtk_timeout_remove(folderview->drag_timer);
2607 folderview->drag_timer = 0;
2608 folderview->drag_node = NULL;
2611 static gint folderview_defer_expand(FolderView *folderview)
2613 if (folderview->drag_node) {
2614 folderview_recollapse_nodes(folderview, folderview->drag_node);
2615 if (folderview->drag_item->collapsed) {
2616 gtk_ctree_expand(GTK_CTREE(folderview->ctree), folderview->drag_node);
2617 folderview->nodes_to_recollapse = g_slist_append
2618 (folderview->nodes_to_recollapse, folderview->drag_node);
2621 folderview->drag_item = NULL;
2622 folderview->drag_timer = 0;
2626 static void drag_state_start(FolderView *folderview, GtkCTreeNode *node, FolderItem *item)
2628 /* the idea is that we call drag_state_start() whenever we want expansion to
2629 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2630 * we need to call drag_state_stop() */
2631 drag_state_stop(folderview);
2632 /* request expansion */
2633 if (0 != (folderview->drag_timer = gtk_timeout_add
2634 (prefs_common.hover_timeout,
2635 (GtkFunction)folderview_defer_expand,
2637 folderview->drag_node = node;
2638 folderview->drag_item = item;
2642 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2643 FolderView *folderview)
2645 GdkDragContext *context;
2647 g_return_if_fail(folderview != NULL);
2648 if (folderview->selected == NULL) return;
2649 if (folderview->nodes_to_recollapse)
2650 g_slist_free(folderview->nodes_to_recollapse);
2651 folderview->nodes_to_recollapse = NULL;
2652 context = gtk_drag_begin(widget, folderview->target_list,
2653 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2654 gtk_drag_set_icon_default(context);
2657 static void folderview_drag_data_get(GtkWidget *widget,
2658 GdkDragContext *drag_context,
2659 GtkSelectionData *selection_data,
2662 FolderView *folderview)
2666 gchar *source = NULL;
2667 if (info == TARGET_DUMMY) {
2668 for (cur = GTK_CLIST(folderview->ctree)->selection;
2669 cur != NULL; cur = cur->next) {
2670 item = gtk_ctree_node_get_row_data
2671 (GTK_CTREE(folderview->ctree),
2672 GTK_CTREE_NODE(cur->data));
2674 source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2675 gtk_selection_data_set(selection_data,
2676 selection_data->target, 8,
2677 source, strlen(source));
2683 g_warning("unknown info %d\n", info);
2687 gboolean folderview_update_folder(gpointer source, gpointer userdata)
2689 FolderUpdateData *hookdata;
2690 FolderView *folderview;
2694 folderview = (FolderView *) userdata;
2695 g_return_val_if_fail(hookdata != NULL, FALSE);
2696 g_return_val_if_fail(folderview != NULL, FALSE);
2698 ctree = folderview->ctree;
2699 g_return_val_if_fail(ctree != NULL, FALSE);
2701 if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2702 folderview_create_folder_node(folderview, hookdata->item);
2703 else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2704 GtkCTreeNode *node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree),
2705 NULL, folder_item_parent(hookdata->item));
2706 folderview_sort_folders(folderview, node, hookdata->folder);
2707 } else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2710 node = gtk_ctree_find_by_row_data(GTK_CTREE(ctree), NULL, hookdata->item);
2712 gtk_ctree_remove_node(GTK_CTREE(ctree), node);
2713 } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
2714 folderview_set(folderview);
2719 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2720 GdkDragContext *context,
2724 FolderView *folderview)
2727 FolderItem *item = NULL, *src_item = NULL;
2728 GtkCTreeNode *node = NULL;
2729 gboolean acceptable = FALSE;
2730 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2731 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2732 int height = (int)pos->page_size;
2733 int total_height = (int)pos->upper;
2734 int vpos = (int) pos->value;
2736 if (gtk_clist_get_selection_info
2737 (GTK_CLIST(widget), x - 24, y - 24, &row, &column)) {
2738 GtkWidget *srcwidget;
2740 if (y > height - 24 && height + vpos < total_height)
2741 gtk_adjustment_set_value(pos, (vpos+5 > height ? height : vpos+5));
2743 if (y < 48 && y > 0)
2744 gtk_adjustment_set_value(pos, (vpos-5 < 0 ? 0 : vpos-5));
2746 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2747 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2748 src_item = folderview->summaryview->folder_item;
2750 srcwidget = gtk_drag_get_source_widget(context);
2751 if (srcwidget == summary_get_main_widget(folderview->summaryview)) {
2752 /* comes from summaryview */
2753 /* we are copying messages, so only accept folder items that are not
2754 the source item, are no root items and can copy messages */
2755 if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
2756 src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2757 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2759 } else if (srcwidget == folderview->ctree) {
2760 /* comes from folderview */
2761 /* we are moving folder items, only accept folders that are not
2762 the source items and can copy messages and create folder items */
2763 if (item && item->folder && src_item && src_item != item &&
2764 FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2765 FOLDER_CLASS(item->folder)->create_folder != NULL &&
2766 ((FOLDER_TYPE(item->folder) != F_UNKNOWN && FOLDER_TYPE(src_item->folder) != F_UNKNOWN)
2767 || item->folder == src_item->folder))
2770 /* comes from another app */
2771 /* we are adding messages, so only accept folder items that are
2772 no root items and can copy messages */
2773 if (item && item->folder && folder_item_parent(item) != NULL
2774 && FOLDER_CLASS(item->folder)->add_msg != NULL &&
2775 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2780 if (acceptable || (src_item && src_item == item))
2781 drag_state_start(folderview, node, item);
2784 g_signal_handlers_block_by_func
2786 G_CALLBACK(folderview_selected), folderview);
2787 gtk_ctree_select(GTK_CTREE(widget), node);
2788 g_signal_handlers_unblock_by_func
2790 G_CALLBACK(folderview_selected), folderview);
2791 gdk_drag_status(context,
2792 (context->actions == GDK_ACTION_COPY ?
2793 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2795 if (folderview->opened)
2796 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2797 gdk_drag_status(context, 0, time);
2803 static void folderview_drag_leave_cb(GtkWidget *widget,
2804 GdkDragContext *context,
2806 FolderView *folderview)
2808 drag_state_stop(folderview);
2809 gtk_ctree_select(GTK_CTREE(widget), folderview->opened);
2812 static void free_info (gpointer stuff, gpointer data)
2817 void folderview_finish_dnd(const gchar *data, GdkDragContext *drag_context,
2818 guint time, FolderItem *item)
2821 GSList *msglist = NULL;
2822 list = uri_list_extract_filenames(data);
2823 if (!(item && item->folder && folder_item_parent(item) != NULL
2824 && FOLDER_CLASS(item->folder)->add_msg != NULL))
2826 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2830 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2833 for (tmp = list; tmp != NULL; tmp = tmp->next) {
2834 MsgFileInfo *info = NULL;
2836 if (file_is_email((gchar *)tmp->data)) {
2837 info = g_new0(MsgFileInfo, 1);
2838 info->msginfo = NULL;
2839 info->file = (gchar *)tmp->data;
2840 msglist = g_slist_prepend(msglist, info);
2844 msglist = g_slist_reverse(msglist);
2845 folder_item_add_msgs(item, msglist, FALSE);
2846 g_slist_foreach(msglist, free_info, NULL);
2847 g_slist_free(msglist);
2848 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2850 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2852 list_free_strings(list);
2856 static void folderview_drag_received_cb(GtkWidget *widget,
2857 GdkDragContext *drag_context,
2860 GtkSelectionData *data,
2863 FolderView *folderview)
2866 FolderItem *item = NULL, *src_item;
2869 if (info == TARGET_DUMMY) {
2870 drag_state_stop(folderview);
2871 if ((void *)strstr(data->data, "FROM_OTHER_FOLDER") != (void *)data->data) {
2872 /* comes from summaryview */
2873 if (gtk_clist_get_selection_info
2874 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2877 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2878 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2879 src_item = folderview->summaryview->folder_item;
2881 /* re-check (due to acceptable possibly set for folder moves */
2882 if (!(item && item->folder && item->path && !item->no_select &&
2883 src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) {
2886 if (item && src_item) {
2887 switch (drag_context->action) {
2888 case GDK_ACTION_COPY:
2889 summary_copy_selected_to(folderview->summaryview, item);
2890 gtk_drag_finish(drag_context, TRUE, FALSE, time);
2892 case GDK_ACTION_MOVE:
2893 case GDK_ACTION_DEFAULT:
2895 if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL)
2896 summary_copy_selected_to(folderview->summaryview, item);
2898 summary_move_selected_to(folderview->summaryview, item);
2899 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2902 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2904 /* comes from folderview */
2906 gboolean folder_is_normal = TRUE;
2908 source = data->data + 17;
2909 if (gtk_clist_get_selection_info
2910 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0
2912 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2915 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2916 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2917 src_item = folder_find_item_from_identifier(source);
2921 src_item->stype == F_NORMAL &&
2922 !folder_has_parent_of_type(src_item, F_OUTBOX) &&
2923 !folder_has_parent_of_type(src_item, F_DRAFT) &&
2924 !folder_has_parent_of_type(src_item, F_QUEUE) &&
2925 !folder_has_parent_of_type(src_item, F_TRASH);
2926 if (!item || item->no_select || !src_item
2927 || !folder_is_normal) {
2928 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2932 folderview_move_folder(folderview, src_item, item);
2933 gtk_drag_finish(drag_context, TRUE, TRUE, time);
2935 folderview->nodes_to_recollapse = NULL;
2936 } else if (info == TARGET_MAIL_URI_LIST) {
2937 if (gtk_clist_get_selection_info
2938 (GTK_CLIST(widget), x - 24, y - 24, &row, &column) == 0)
2941 node = gtk_ctree_node_nth(GTK_CTREE(widget), row);
2943 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2946 item = gtk_ctree_node_get_row_data(GTK_CTREE(widget), node);
2948 gtk_drag_finish(drag_context, FALSE, FALSE, time);
2951 folderview_finish_dnd(data->data, drag_context, time, item);
2955 static void folderview_drag_end_cb(GtkWidget *widget,
2956 GdkDragContext *drag_context,
2957 FolderView *folderview)
2959 drag_state_stop(folderview);
2960 g_slist_free(folderview->nodes_to_recollapse);
2961 folderview->nodes_to_recollapse = NULL;
2964 void folderview_register_popup(FolderViewPopup *fpopup)
2968 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2969 FolderView *folderview = folderviews->data;
2970 GtkItemFactory *factory;
2972 factory = create_ifactory(folderview, fpopup);
2973 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
2975 g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
2978 void folderview_unregister_popup(FolderViewPopup *fpopup)
2982 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
2983 FolderView *folderview = folderviews->data;
2985 g_hash_table_remove(folderview->popups, fpopup->klass);
2987 g_hash_table_remove(folderview_popups, fpopup->klass);