Forgot to adjust default window size
[claws.git] / src / folderview.c
blob83dc21936fb14e894204cc787ccca5d07d1832ab
1 /*
2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2013 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/>.
20 #include "defs.h"
22 #include <glib.h>
23 #include <glib/gi18n.h>
24 #include <gdk/gdkkeysyms.h>
25 #include <gtk/gtk.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
30 #include "main.h"
31 #include "mainwindow.h"
32 #include "folderview.h"
33 #include "summaryview.h"
34 #include "summary_search.h"
35 #include "inputdialog.h"
36 #include "manage_window.h"
37 #include "alertpanel.h"
38 #include "menu.h"
39 #include "stock_pixmap.h"
40 #include "procmsg.h"
41 #include "utils.h"
42 #include "gtkutils.h"
43 #include "prefs_common.h"
44 #include "prefs_account.h"
45 #include "prefs_filtering.h"
46 #include "prefs_folder_item.h"
47 #include "account.h"
48 #include "folder.h"
49 #include "foldersel.h"
50 #include "inc.h"
51 #include "statusbar.h"
52 #include "hooks.h"
53 #include "folderutils.h"
54 #include "partial_download.h"
55 #include "prefs_folder_column.h"
56 #include "filtering.h"
57 #include "quicksearch.h"
58 #include "manual.h"
59 #include "timing.h"
60 #include "log.h"
61 #include "gtkcmctree.h"
63 #define COL_FOLDER_WIDTH 150
64 #define COL_NUM_WIDTH 32
66 static GList *folderview_list = NULL;
68 static GtkStyle *normal_style;
69 static GtkStyle *normal_color_style;
70 static GtkStyle *bold_style;
71 static GtkStyle *bold_color_style;
72 static GtkStyle *bold_tgtfold_style;
74 static GdkPixbuf *inboxxpm;
75 static GdkPixbuf *inboxhrmxpm;
76 static GdkPixbuf *inboxopenxpm;
77 static GdkPixbuf *inboxopenhrmxpm;
78 static GdkPixbuf *outboxxpm;
79 static GdkPixbuf *outboxhrmxpm;
80 static GdkPixbuf *outboxopenxpm;
81 static GdkPixbuf *outboxopenhrmxpm;
82 static GdkPixbuf *folderxpm;
83 static GdkPixbuf *folderhrmxpm;
84 static GdkPixbuf *folderopenxpm;
85 static GdkPixbuf *folderopenhrmxpm;
86 static GdkPixbuf *trashopenxpm;
87 static GdkPixbuf *trashopenhrmxpm;
88 static GdkPixbuf *trashxpm;
89 static GdkPixbuf *trashhrmxpm;
90 static GdkPixbuf *queuexpm;
91 static GdkPixbuf *queuehrmxpm;
92 static GdkPixbuf *queueopenxpm;
93 static GdkPixbuf *queueopenhrmxpm;
94 static GdkPixbuf *draftsxpm;
95 static GdkPixbuf *draftsopenxpm;
96 static GdkPixbuf *foldersubsxpm;
97 static GdkPixbuf *foldersubsopenxpm;
98 static GdkPixbuf *foldernoselectxpm;
99 static GdkPixbuf *foldernoselectopenxpm;
101 static GdkPixbuf *m_inboxxpm;
102 static GdkPixbuf *m_inboxhrmxpm;
103 static GdkPixbuf *m_inboxopenxpm;
104 static GdkPixbuf *m_inboxopenhrmxpm;
105 static GdkPixbuf *m_outboxxpm;
106 static GdkPixbuf *m_outboxhrmxpm;
107 static GdkPixbuf *m_outboxopenxpm;
108 static GdkPixbuf *m_outboxopenhrmxpm;
109 static GdkPixbuf *m_folderxpm;
110 static GdkPixbuf *m_folderhrmxpm;
111 static GdkPixbuf *m_folderopenxpm;
112 static GdkPixbuf *m_folderopenhrmxpm;
113 static GdkPixbuf *m_trashopenxpm;
114 static GdkPixbuf *m_trashopenhrmxpm;
115 static GdkPixbuf *m_trashxpm;
116 static GdkPixbuf *m_trashhrmxpm;
117 static GdkPixbuf *m_queuexpm;
118 static GdkPixbuf *m_queuehrmxpm;
119 static GdkPixbuf *m_queueopenxpm;
120 static GdkPixbuf *m_queueopenhrmxpm;
121 static GdkPixbuf *m_draftsxpm;
122 static GdkPixbuf *m_draftsopenxpm;
123 static GdkPixbuf *m_foldersubsxpm;
124 static GdkPixbuf *m_foldernoselectxpm;
126 static GdkPixbuf *newxpm;
127 static GdkPixbuf *unreadxpm;
128 static GdkPixbuf *readxpm;
130 static void folderview_select_node (FolderView *folderview,
131 GtkCMCTreeNode *node);
132 static void folderview_set_folders (FolderView *folderview);
133 static void folderview_sort_folders (FolderView *folderview,
134 GtkCMCTreeNode *root,
135 Folder *folder);
136 static void folderview_append_folder (FolderView *folderview,
137 Folder *folder);
138 static void folderview_update_node (FolderView *folderview,
139 GtkCMCTreeNode *node);
141 static gint folderview_clist_compare (GtkCMCList *clist,
142 gconstpointer ptr1,
143 gconstpointer ptr2);
145 /* callback functions */
146 static gboolean folderview_button_pressed (GtkWidget *ctree,
147 GdkEventButton *event,
148 FolderView *folderview);
149 static gboolean folderview_button_released (GtkWidget *ctree,
150 GdkEventButton *event,
151 FolderView *folderview);
152 static gboolean folderview_key_pressed (GtkWidget *widget,
153 GdkEventKey *event,
154 FolderView *folderview);
155 static void folderview_selected (GtkCMCTree *ctree,
156 GtkCMCTreeNode *row,
157 gint column,
158 FolderView *folderview);
159 static void folderview_tree_expanded (GtkCMCTree *ctree,
160 GtkCMCTreeNode *node,
161 FolderView *folderview);
162 static void folderview_tree_collapsed (GtkCMCTree *ctree,
163 GtkCMCTreeNode *node,
164 FolderView *folderview);
165 static void folderview_popup_close (GtkMenuShell *menu_shell,
166 FolderView *folderview);
167 static void folderview_col_resized (GtkCMCList *clist,
168 gint column,
169 gint width,
170 FolderView *folderview);
172 static void mark_all_read_handler (GtkAction *action,
173 gpointer data,
174 gboolean recursive);
176 static void mark_all_read_cb (GtkAction *action,
177 gpointer data);
178 static void mark_all_read_recursive_cb (GtkAction *action,
179 gpointer data);
181 static void folderview_empty_trash_cb (GtkAction *action,
182 gpointer data);
184 static void folderview_send_queue_cb (GtkAction *action,
185 gpointer data);
187 static void folderview_search_cb (GtkAction *action,
188 gpointer data);
189 static void folderview_run_processing_cb(GtkAction *action,
190 gpointer data);
192 static void folderview_property_cb (GtkAction *action,
193 gpointer data);
195 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
196 GdkDragContext *context,
197 gint x,
198 gint y,
199 guint time,
200 FolderView *folderview);
201 static void folderview_drag_leave_cb (GtkWidget *widget,
202 GdkDragContext *context,
203 guint time,
204 FolderView *folderview);
205 static void folderview_drag_received_cb (GtkWidget *widget,
206 GdkDragContext *drag_context,
207 gint x,
208 gint y,
209 GtkSelectionData *data,
210 guint info,
211 guint time,
212 FolderView *folderview);
213 #ifndef GENERIC_UMPC
214 static void folderview_start_drag (GtkWidget *widget, gint button, GdkEvent *event,
215 FolderView *folderview);
216 #endif
217 static void folderview_drag_data_get (GtkWidget *widget,
218 GdkDragContext *drag_context,
219 GtkSelectionData *selection_data,
220 guint info,
221 guint time,
222 FolderView *folderview);
223 static void folderview_drag_end_cb (GtkWidget *widget,
224 GdkDragContext *drag_context,
225 FolderView *folderview);
227 static void folderview_create_folder_node (FolderView *folderview,
228 FolderItem *item);
229 static gboolean folderview_update_folder (gpointer source,
230 gpointer userdata);
231 static gboolean folderview_update_item_claws (gpointer source,
232 gpointer data);
233 static void folderview_processing_cb(GtkAction *action, gpointer data);
234 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
235 GdkEventButton *event);
237 GHashTable *folderview_popups;
239 static GtkActionEntry folderview_common_popup_entries[] =
241 {"FolderViewPopup", NULL, "FolderViewPopup" },
242 {"FolderViewPopup/MarkAllRead", NULL, N_("Mark all re_ad"), NULL, NULL, G_CALLBACK(mark_all_read_cb) },
243 {"FolderViewPopup/MarkAllReadRec", NULL, N_("Mark all read recursi_vely"), NULL, NULL, G_CALLBACK(mark_all_read_recursive_cb) },
244 {"FolderViewPopup/---", NULL, "---" },
245 {"FolderViewPopup/RunProcessing", NULL, N_("R_un processing rules"), NULL, NULL, G_CALLBACK(folderview_run_processing_cb) },
246 {"FolderViewPopup/SearchFolder", NULL, N_("_Search folder..."), NULL, NULL, G_CALLBACK(folderview_search_cb) },
247 {"FolderViewPopup/Properties", NULL, N_("_Properties..."), NULL, NULL, G_CALLBACK(folderview_property_cb) },
248 {"FolderViewPopup/Processing", NULL, N_("Process_ing..."), NULL, NULL, G_CALLBACK(folderview_processing_cb) },
249 {"FolderViewPopup/EmptyTrash", NULL, N_("Empty _trash..."), NULL, NULL, G_CALLBACK(folderview_empty_trash_cb) },
250 {"FolderViewPopup/SendQueue", NULL, N_("Send _queue..."), NULL, NULL, G_CALLBACK(folderview_send_queue_cb) },
254 GtkTargetEntry folderview_drag_types[] =
256 {"claws-mail/internal", GTK_TARGET_SAME_APP, TARGET_DUMMY},
257 {"text/uri-list", 0, TARGET_MAIL_URI_LIST}
260 void folderview_initialize(void)
262 FolderViewPopup *fpopup;
264 fpopup = g_new0(FolderViewPopup, 1);
266 fpopup->klass = "common";
267 fpopup->path = "<CommonFolder>";
268 fpopup->entries = folderview_common_popup_entries;
269 fpopup->n_entries = G_N_ELEMENTS(folderview_common_popup_entries);
270 fpopup->set_sensitivity = NULL;
272 folderview_popups = g_hash_table_new(g_str_hash, g_str_equal);
273 g_hash_table_insert(folderview_popups, "common", fpopup);
276 static GtkActionGroup *create_action_group(FolderView *folderview, FolderViewPopup *fpopup)
278 FolderViewPopup *fpopup_common;
279 GtkActionGroup *action_group;
281 action_group = cm_menu_create_action_group(
282 fpopup->path,
283 fpopup->entries, fpopup->n_entries,
284 (gpointer)folderview);
286 if (fpopup->toggle_entries)
287 gtk_action_group_add_toggle_actions(action_group, fpopup->toggle_entries,
288 fpopup->n_toggle_entries,
289 (gpointer)folderview);
290 if (fpopup->radio_entries)
291 gtk_action_group_add_radio_actions(action_group, fpopup->radio_entries,
292 fpopup->n_radio_entries, fpopup->radio_default,
293 G_CALLBACK(fpopup->radio_callback),
294 (gpointer)folderview);
296 fpopup_common = g_hash_table_lookup(folderview_popups, "common");
297 if (fpopup_common != fpopup) {
298 gtk_action_group_add_actions(action_group, fpopup_common->entries,
299 fpopup_common->n_entries,
300 (gpointer)folderview);
301 if (fpopup_common->toggle_entries)
302 gtk_action_group_add_toggle_actions(action_group, fpopup_common->toggle_entries,
303 fpopup_common->n_toggle_entries,
304 (gpointer)folderview);
305 if (fpopup_common->radio_entries)
306 gtk_action_group_add_radio_actions(action_group, fpopup_common->radio_entries,
307 fpopup_common->n_radio_entries, fpopup_common->radio_default,
308 G_CALLBACK(fpopup_common->radio_callback),
309 (gpointer)folderview);
312 return action_group;
315 static void create_action_groups(gpointer key, gpointer value, gpointer data)
317 FolderView *folderview = data;
318 FolderViewPopup *fpopup = value;
319 GtkActionGroup *group;
321 group = create_action_group(folderview, fpopup);
322 g_hash_table_insert(folderview->popups, fpopup->klass, group);
325 static void folderview_column_set_titles(FolderView *folderview)
327 GtkWidget *ctree = folderview->ctree;
328 GtkWidget *label_folder;
329 GtkWidget *label_new;
330 GtkWidget *label_unread;
331 GtkWidget *label_total;
332 GtkWidget *hbox_folder;
333 GtkWidget *hbox_new;
334 GtkWidget *hbox_unread;
335 GtkWidget *hbox_total;
336 gint *col_pos = folderview->col_pos;
338 debug_print("setting titles...\n");
339 gtk_widget_realize(folderview->ctree);
340 gtk_widget_show_all(folderview->scrolledwin);
342 /* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
343 * instead text (text overflows making them unreadable and ugly) */
344 stock_pixbuf_gdk(STOCK_PIXMAP_NEW, &newxpm);
345 stock_pixbuf_gdk(STOCK_PIXMAP_UNREAD, &unreadxpm);
346 stock_pixbuf_gdk(STOCK_PIXMAP_READ, &readxpm);
348 label_folder = gtk_label_new(_("Folder"));
349 label_new = gtk_image_new_from_pixbuf(newxpm);
350 label_unread = gtk_image_new_from_pixbuf(unreadxpm);
351 label_total = gtk_image_new_from_pixbuf(readxpm);
353 gtk_cmclist_column_titles_active(GTK_CMCLIST(ctree));
355 hbox_folder = gtk_hbox_new(FALSE, 4);
356 hbox_new = gtk_hbox_new(FALSE, 4);
357 hbox_unread = gtk_hbox_new(FALSE, 4);
358 hbox_total = gtk_hbox_new(FALSE, 4);
360 /* left justified */
361 gtk_box_pack_start(GTK_BOX(hbox_folder), label_folder, TRUE, TRUE, 0);
362 gtk_misc_set_alignment (GTK_MISC (label_folder), 0, 0.5);
363 gtk_box_pack_start(GTK_BOX(hbox_new), label_new, TRUE, TRUE, 0);
364 gtk_misc_set_alignment (GTK_MISC (label_new), 1, 0.5);
365 gtk_box_pack_start(GTK_BOX(hbox_unread), label_unread, TRUE, TRUE, 0);
366 gtk_misc_set_alignment (GTK_MISC (label_unread), 1, 0.5);
367 gtk_box_pack_start(GTK_BOX(hbox_total), label_total, TRUE, TRUE, 0);
368 gtk_misc_set_alignment (GTK_MISC (label_total), 1, 0.5);
370 gtk_widget_show_all(hbox_folder);
371 gtk_widget_show_all(hbox_new);
372 gtk_widget_show_all(hbox_unread);
373 gtk_widget_show_all(hbox_total);
375 #ifdef GENERIC_UMPC
376 gtk_widget_set_size_request(hbox_new, -1, 20);
377 gtk_widget_set_size_request(hbox_unread, -1, 20);
378 gtk_widget_set_size_request(hbox_total, -1, 20);
379 #endif
381 gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree),col_pos[F_COL_FOLDER],hbox_folder);
382 gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree),col_pos[F_COL_NEW],hbox_new);
383 gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree),col_pos[F_COL_UNREAD],hbox_unread);
384 gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree),col_pos[F_COL_TOTAL],hbox_total);
386 #ifdef GENERIC_UMPC
387 GTK_EVENTS_FLUSH();
388 #endif
390 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_NEW], _("New"));
391 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_UNREAD], _("Unread"));
392 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree), col_pos[F_COL_TOTAL], _("Total"));
395 static gboolean folderview_popup_menu(GtkWidget *widget, gpointer data)
397 FolderView *folderview = (FolderView *)data;
398 GdkEventButton event;
399 if (folderview_get_selected_item(folderview) == NULL)
400 return FALSE;
402 event.button = 3;
403 event.time = gtk_get_current_event_time();
405 folderview_set_sens_and_popup_menu(folderview, -1,
406 &event);
408 return TRUE;
412 static GtkWidget *folderview_ctree_create(FolderView *folderview)
414 GtkWidget *ctree;
415 gint *col_pos;
416 FolderColumnState *col_state;
417 FolderColumnType type;
418 gchar *titles[N_FOLDER_COLS];
419 gint i;
420 GtkWidget *scrolledwin = folderview->scrolledwin;
422 debug_print("creating tree...\n");
423 memset(titles, 0, sizeof(titles));
425 col_state = prefs_folder_column_get_config();
426 memset(titles, 0, sizeof(titles));
428 col_pos = folderview->col_pos;
430 for (i = 0; i < N_FOLDER_COLS; i++) {
431 folderview->col_state[i] = col_state[i];
432 type = col_state[i].type;
433 col_pos[type] = i;
436 titles[col_pos[F_COL_FOLDER]] = _("Folder");
437 titles[col_pos[F_COL_NEW]] = _("New");
438 titles[col_pos[F_COL_UNREAD]] = _("Unread");
439 /* TRANSLATORS: This in Number sign in American style */
440 titles[col_pos[F_COL_TOTAL]] = _("#");
442 ctree = gtk_sctree_new_with_titles(N_FOLDER_COLS, col_pos[F_COL_FOLDER],
443 titles);
445 if (prefs_common.show_col_headers == FALSE)
446 gtk_cmclist_column_titles_hide(GTK_CMCLIST(ctree));
449 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree), GTK_SELECTION_BROWSE);
450 gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree), col_pos[F_COL_NEW],
451 GTK_JUSTIFY_RIGHT);
452 gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree),
453 col_pos[F_COL_UNREAD],
454 GTK_JUSTIFY_RIGHT);
455 gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree),
456 col_pos[F_COL_TOTAL],
457 GTK_JUSTIFY_RIGHT);
458 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree), GTK_CMCTREE_LINES_NONE);
459 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree),
460 GTK_CMCTREE_EXPANDER_TRIANGLE);
462 gtk_sctree_set_stripes(GTK_SCTREE(ctree), prefs_common.use_stripes_in_summaries);
463 gtk_sctree_set_recursive_expand(GTK_SCTREE(ctree), FALSE);
465 gtk_cmctree_set_indent(GTK_CMCTREE(ctree), CTREE_INDENT);
466 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree), folderview_clist_compare);
468 /* don't let title buttons take key focus */
469 for (i = 0; i < N_FOLDER_COLS; i++) {
470 gtkut_widget_set_can_focus(GTK_CMCLIST(ctree)->column[i].button, FALSE);
471 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree), col_pos[i],
472 prefs_common.folder_col_size[i]);
473 gtk_cmclist_set_column_visibility
474 (GTK_CMCLIST(ctree), i, col_state[i].visible);
477 g_signal_connect(G_OBJECT(ctree), "key_press_event",
478 G_CALLBACK(folderview_key_pressed),
479 folderview);
480 g_signal_connect(G_OBJECT(ctree), "button_press_event",
481 G_CALLBACK(folderview_button_pressed),
482 folderview);
483 g_signal_connect(G_OBJECT(ctree), "popup-menu",
484 G_CALLBACK(folderview_popup_menu), folderview);
485 g_signal_connect(G_OBJECT(ctree), "button_release_event",
486 G_CALLBACK(folderview_button_released),
487 folderview);
488 g_signal_connect(G_OBJECT(ctree), "tree_select_row",
489 G_CALLBACK(folderview_selected), folderview);
490 #ifndef GENERIC_UMPC
491 /* drag-n-dropping folders on maemo is impractical as this
492 * opens the folder almost everytime */
493 g_signal_connect(G_OBJECT(ctree), "start_drag",
494 G_CALLBACK(folderview_start_drag), folderview);
495 #endif
496 g_signal_connect(G_OBJECT(ctree), "drag_data_get",
497 G_CALLBACK(folderview_drag_data_get),
498 folderview);
500 g_signal_connect_after(G_OBJECT(ctree), "tree_expand",
501 G_CALLBACK(folderview_tree_expanded),
502 folderview);
503 g_signal_connect_after(G_OBJECT(ctree), "tree_collapse",
504 G_CALLBACK(folderview_tree_collapsed),
505 folderview);
507 g_signal_connect(G_OBJECT(ctree), "resize_column",
508 G_CALLBACK(folderview_col_resized),
509 folderview);
511 /* drop callback */
512 gtk_drag_dest_set(ctree, GTK_DEST_DEFAULT_ALL & ~GTK_DEST_DEFAULT_HIGHLIGHT,
513 folderview_drag_types, 2,
514 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_DEFAULT);
515 g_signal_connect(G_OBJECT(ctree), "drag_motion",
516 G_CALLBACK(folderview_drag_motion_cb),
517 folderview);
518 g_signal_connect(G_OBJECT(ctree), "drag_leave",
519 G_CALLBACK(folderview_drag_leave_cb),
520 folderview);
521 g_signal_connect(G_OBJECT(ctree), "drag_data_received",
522 G_CALLBACK(folderview_drag_received_cb),
523 folderview);
524 g_signal_connect(G_OBJECT(ctree), "drag_end",
525 G_CALLBACK(folderview_drag_end_cb),
526 folderview);
528 gtk_container_add(GTK_CONTAINER(scrolledwin), ctree);
530 return ctree;
533 void folderview_set_column_order(FolderView *folderview)
535 GtkWidget *ctree = folderview->ctree;
536 FolderItem *item = folderview_get_selected_item(folderview);
537 FolderItem *sel_item = NULL, *op_item = NULL;
538 GtkWidget *scrolledwin = folderview->scrolledwin;
540 if (folderview->drag_timer_id != 0) {
541 g_source_remove(folderview->drag_timer_id);
542 folderview->drag_timer_id = 0;
544 if (folderview->deferred_refresh_id != 0) {
545 g_source_remove(folderview->deferred_refresh_id);
546 folderview->deferred_refresh_id = 0;
548 if (folderview->scroll_timeout_id != 0) {
549 g_source_remove(folderview->scroll_timeout_id);
550 folderview->scroll_timeout_id = 0;
552 if (folderview->postpone_select_id != 0) {
553 g_source_remove(folderview->postpone_select_id);
554 folderview->postpone_select_id = 0;
557 if (folderview->selected)
558 sel_item = folderview_get_selected_item(folderview);
559 if (folderview->opened)
560 op_item = folderview_get_opened_item(folderview);
562 debug_print("recreating tree...\n");
563 gtk_widget_destroy(folderview->ctree);
566 folderview->ctree = ctree = folderview_ctree_create(folderview);
567 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
568 GTK_CMCLIST(ctree)->hadjustment);
569 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin),
570 GTK_CMCLIST(ctree)->vadjustment);
571 gtk_widget_show(ctree);
573 if (sel_item)
574 folderview->selected = gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree), NULL, sel_item);
575 if (op_item)
576 folderview->opened = gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree), NULL, op_item);
578 folderview_set(folderview);
579 folderview_column_set_titles(folderview);
581 folderview_select(folderview,item);
584 FolderView *folderview_create(void)
586 FolderView *folderview;
587 GtkWidget *scrolledwin;
588 GtkWidget *ctree;
590 debug_print("Creating folder view...\n");
591 folderview = g_new0(FolderView, 1);
593 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
594 gtk_scrolled_window_set_policy
595 (GTK_SCROLLED_WINDOW(scrolledwin),
596 GTK_POLICY_AUTOMATIC,
597 prefs_common.folderview_vscrollbar_policy);
598 gtk_widget_set_size_request(scrolledwin,
599 prefs_common.folderview_width,
600 prefs_common.folderview_height);
602 folderview->scrolledwin = scrolledwin;
603 ctree = folderview_ctree_create(folderview);
605 /* create popup factories */
606 folderview->popups = g_hash_table_new(g_str_hash, g_str_equal);
607 g_hash_table_foreach(folderview_popups, create_action_groups, folderview);
609 folderview->ctree = ctree;
611 folderview->folder_update_callback_id =
612 hooks_register_hook(FOLDER_UPDATE_HOOKLIST, folderview_update_folder, (gpointer) folderview);
613 folderview->folder_item_update_callback_id =
614 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST, folderview_update_item_claws, (gpointer) folderview);
616 gtk_widget_show_all(scrolledwin);
618 folderview->target_list = gtk_target_list_new(folderview_drag_types, 2);
619 folderview_list = g_list_append(folderview_list, folderview);
621 folderview->drag_timer_id = 0;
622 folderview->deferred_refresh_id = 0;
623 folderview->scroll_timeout_id = 0;
624 folderview->postpone_select_id = 0;
626 return folderview;
629 void folderview_init(FolderView *folderview)
631 GtkWidget *ctree = folderview->ctree;
632 GdkColor gdk_color;
633 PangoFontDescription *normal_font;
635 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE, &inboxxpm);
636 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE_HRM, &inboxhrmxpm);
637 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN, &inboxopenxpm);
638 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN_HRM, &inboxopenhrmxpm);
639 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE, &outboxxpm);
640 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE_HRM, &outboxhrmxpm);
641 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN, &outboxopenxpm);
642 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN_HRM, &outboxopenhrmxpm);
643 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE, &folderxpm);
644 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE_HRM, &folderhrmxpm);
645 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN, &folderopenxpm);
646 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN_HRM, &folderopenhrmxpm);
647 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN, &trashopenxpm);
648 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN_HRM, &trashopenhrmxpm);
649 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE, &trashxpm);
650 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE_HRM, &trashhrmxpm);
651 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE, &queuexpm);
652 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE_HRM, &queuehrmxpm);
653 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN, &queueopenxpm);
654 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN_HRM, &queueopenhrmxpm);
655 stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_CLOSE, &draftsxpm);
656 stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_OPEN, &draftsopenxpm);
657 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_SUBS_OPEN, &foldersubsopenxpm);
658 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_SUBS_CLOSE, &foldersubsxpm);
659 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_NOSELECT_OPEN, &foldernoselectopenxpm);
660 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_NOSELECT_CLOSE, &foldernoselectxpm);
662 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE_MARK, &m_inboxxpm);
663 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK, &m_inboxhrmxpm);
664 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN_MARK, &m_inboxopenxpm);
665 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN_HRM_MARK, &m_inboxopenhrmxpm);
666 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE_MARK, &m_outboxxpm);
667 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK, &m_outboxhrmxpm);
668 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN_MARK, &m_outboxopenxpm);
669 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK, &m_outboxopenhrmxpm);
670 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE_MARK, &m_folderxpm);
671 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE_HRM_MARK, &m_folderhrmxpm);
672 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN_MARK, &m_folderopenxpm);
673 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN_HRM_MARK, &m_folderopenhrmxpm);
674 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN_MARK, &m_trashopenxpm);
675 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN_HRM_MARK, &m_trashopenhrmxpm);
676 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE_MARK, &m_trashxpm);
677 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK, &m_trashhrmxpm);
678 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE_MARK, &m_queuexpm);
679 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK, &m_queuehrmxpm);
680 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN_MARK, &m_queueopenxpm);
681 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK, &m_queueopenhrmxpm);
682 stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_CLOSE_MARK, &m_draftsxpm);
683 stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_OPEN_MARK, &m_draftsopenxpm);
684 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_SUBS_CLOSE_MARK, &m_foldersubsxpm);
685 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_NOSELECT_CLOSE_MARK, &m_foldernoselectxpm);
687 normal_font = pango_font_description_from_string(NORMAL_FONT);
688 if (normal_font) {
689 gtk_widget_modify_font(ctree, normal_font);
690 pango_font_description_free(normal_font);
692 gtk_cmclist_set_row_height(GTK_CMCLIST(ctree), 0);
694 if (!normal_style) {
695 PangoFontDescription *font_desc;
696 normal_style = gtk_style_copy(gtk_widget_get_style(ctree));
697 font_desc = pango_font_description_from_string(NORMAL_FONT);
698 if (font_desc) {
699 if (normal_style->font_desc)
700 pango_font_description_free
701 (normal_style->font_desc);
702 normal_style->font_desc = font_desc;
704 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
705 normal_color_style = gtk_style_copy(normal_style);
706 normal_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
709 if (!bold_style) {
710 gtkut_convert_int_to_gdk_color(prefs_common.color_new, &gdk_color);
711 bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
712 if (prefs_common.derive_from_normal_font || !BOLD_FONT) {
713 PangoFontDescription *font_desc;
714 font_desc = pango_font_description_from_string(NORMAL_FONT);
715 if (font_desc) {
716 pango_font_description_free(bold_style->font_desc);
717 bold_style->font_desc = font_desc;
719 pango_font_description_set_weight
720 (bold_style->font_desc, PANGO_WEIGHT_BOLD);
721 } else {
722 PangoFontDescription *font_desc;
723 font_desc = pango_font_description_from_string(BOLD_FONT);
724 if (font_desc) {
725 if (bold_style->font_desc)
726 pango_font_description_free
727 (bold_style->font_desc);
728 bold_style->font_desc = font_desc;
731 bold_color_style = gtk_style_copy(bold_style);
732 bold_color_style->fg[GTK_STATE_NORMAL] = gdk_color;
734 bold_tgtfold_style = gtk_style_copy(bold_style);
735 bold_tgtfold_style->fg[GTK_STATE_NORMAL] = folderview->color_op;
739 static gboolean folderview_defer_set(gpointer data)
741 FolderView *folderview = (FolderView *)data;
742 MainWindow *mainwin = folderview->mainwin;
744 if (!mainwin)
745 return FALSE;
746 if (mainwin->lock_count)
747 return TRUE;
749 debug_print("doing deferred folderview_set now\n");
750 folderview_set(folderview);
752 folderview->deferred_refresh_id = 0;
753 return FALSE;
756 void folderview_set(FolderView *folderview)
758 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
759 MainWindow *mainwin = folderview->mainwin;
760 FolderItem *sel_item = NULL, *op_item = NULL;
762 if (!mainwin)
763 return;
765 if (mainwin->lock_count) {
766 if (folderview->deferred_refresh_id == 0)
767 folderview->deferred_refresh_id =
768 g_timeout_add(500, folderview_defer_set, folderview);
769 debug_print("deferred folderview_set\n");
770 return;
773 inc_lock();
774 debug_print("Setting folder info...\n");
775 STATUSBAR_PUSH(mainwin, _("Setting folder info..."));
777 main_window_cursor_wait(mainwin);
779 if (folderview->selected)
780 sel_item = folderview_get_selected_item(folderview);
781 if (folderview->opened)
782 op_item = folderview_get_opened_item(folderview);
784 folderview->selected = NULL;
785 folderview->opened = NULL;
787 gtk_cmclist_freeze(GTK_CMCLIST(ctree));
788 gtk_cmclist_clear(GTK_CMCLIST(ctree));
790 folderview_set_folders(folderview);
792 if (sel_item)
793 folderview->selected = gtk_cmctree_find_by_row_data(ctree, NULL, sel_item);
794 if (op_item)
795 folderview->opened = gtk_cmctree_find_by_row_data(ctree, NULL, op_item);
797 gtk_cmclist_thaw(GTK_CMCLIST(ctree));
798 main_window_cursor_normal(mainwin);
799 STATUSBAR_POP(mainwin);
800 inc_unlock();
803 void folderview_set_all(void)
805 GList *list;
807 for (list = folderview_list; list != NULL; list = list->next)
808 folderview_set((FolderView *)list->data);
811 void folderview_select(FolderView *folderview, FolderItem *item)
813 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
814 GtkCMCTreeNode *node;
815 GtkCMCTreeNode *old_selected = folderview->selected;
817 if (!item) return;
819 node = gtk_cmctree_find_by_row_data(ctree, NULL, item);
820 if (node) folderview_select_node(folderview, node);
822 if (old_selected != node)
823 folder_update_op_count();
826 static void mark_all_read_cb(GtkAction *action, gpointer data)
828 mark_all_read_handler(action, data, FALSE);
831 static void mark_all_read_recursive_cb(GtkAction *action, gpointer data)
833 mark_all_read_handler(action, data, TRUE);
836 static void mark_all_read_handler(GtkAction *action, gpointer data, gboolean recursive)
838 FolderView *folderview = (FolderView *)data;
839 FolderItem *item;
840 AlertValue val;
841 gchar *message;
843 item = folderview_get_selected_item(folderview);
844 if (item == NULL)
845 return;
847 message = recursive? _("Do you really want to mark all mails in this "
848 "folder and its sub-folders as read?") :
849 _("Do you really want to mark all mails in this "
850 "folder as read?");
851 if (folderview->summaryview->folder_item != item &&
852 prefs_common.ask_mark_all_read) {
853 val = alertpanel_full(_("Mark all as read"),
854 message, GTK_STOCK_NO, GTK_STOCK_YES, NULL,
855 TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT);
857 if ((val & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
858 return;
859 else if (val & G_ALERTDISABLE)
860 prefs_common.ask_mark_all_read = FALSE;
863 folder_item_update_freeze();
864 if (folderview->summaryview->folder_item != item && !recursive)
865 summary_lock(folderview->summaryview);
866 else
867 summary_freeze(folderview->summaryview);
869 if (recursive)
870 folderutils_mark_all_read_recursive(item);
871 else
872 folderutils_mark_all_read(item);
874 if (folderview->summaryview->folder_item != item && !recursive)
875 summary_unlock(folderview->summaryview);
876 else
877 summary_thaw(folderview->summaryview);
878 folder_item_update_thaw();
881 static void folderview_select_node(FolderView *folderview, GtkCMCTreeNode *node)
883 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
885 cm_return_if_fail(node != NULL);
887 if (folderview->open_folder) {
888 return;
891 gtk_cmclist_freeze(GTK_CMCLIST(ctree));
892 gtkut_ctree_expand_parent_all(ctree, node);
894 folderview->open_folder = TRUE;
895 gtkut_ctree_set_focus_row(ctree, node);
896 gtk_cmctree_select(ctree, node);
897 gtk_cmclist_thaw(GTK_CMCLIST(ctree));
898 if ((folderview->summaryview->folder_item &&
899 folderview->summaryview->folder_item->total_msgs > 0) ||
900 prefs_common.layout_mode == SMALL_LAYOUT)
901 summary_grab_focus(folderview->summaryview);
902 else
903 gtk_widget_grab_focus(folderview->ctree);
906 void folderview_unselect(FolderView *folderview)
908 if (folderview->opened && !GTK_CMCTREE_ROW(folderview->opened)->children)
909 gtk_cmctree_collapse
910 (GTK_CMCTREE(folderview->ctree), folderview->opened);
912 folderview->selected = folderview->opened = NULL;
915 static GtkCMCTreeNode *folderview_find_next_with_flag(GtkCMCTree *ctree,
916 GtkCMCTreeNode *node,
917 MsgPermFlags flag)
919 FolderItem *item;
921 if (node)
922 node = gtkut_ctree_node_next(ctree, node);
923 else
924 node = GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list);
926 for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
927 item = gtk_cmctree_node_get_row_data(ctree, node);
928 if (!item)
929 continue;
930 if (item->stype == F_TRASH || item->stype == F_DRAFT)
931 continue;
932 switch (flag) {
933 case MSG_UNREAD:
934 if(item->unread_msgs > 0)
935 return node;
936 break;
937 case MSG_NEW:
938 if(item->new_msgs > 0)
939 return node;
940 break;
941 case MSG_MARKED:
942 if(item->marked_msgs > 0)
943 return node;
944 break;
948 return NULL;
951 void folderview_select_next_with_flag(FolderView *folderview,
952 MsgPermFlags flag,
953 gboolean force_open)
955 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
956 GtkCMCTreeNode *node = NULL;
957 EntryAction last_summary_select_prio = prefs_common.summary_select_prio[0];
958 gboolean last_open = prefs_common.always_show_msg;
960 switch (flag) {
961 case MSG_UNREAD:
962 prefs_common.summary_select_prio[0] = ACTION_UNREAD;
963 break;
964 case MSG_NEW:
965 prefs_common.summary_select_prio[0] = ACTION_NEW;
966 break;
967 case MSG_MARKED:
968 prefs_common.summary_select_prio[0] = ACTION_MARKED;
969 break;
971 prefs_common.always_show_msg = force_open ? OPENMSG_ALWAYS : last_open;
973 node = folderview_find_next_with_flag(ctree, folderview->opened, flag);
974 if (node != NULL) {
975 folderview_select_node(folderview, node);
976 goto out;
979 if (!folderview->opened ||
980 folderview->opened == GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list)) {
981 goto out;
984 /* search again from the first node */
985 node = folderview_find_next_with_flag(ctree, NULL, flag);
986 if (node != NULL)
987 folderview_select_node(folderview, node);
989 out:
990 prefs_common.summary_select_prio[0] = last_summary_select_prio;
991 prefs_common.always_show_msg = last_open;
994 FolderItem *folderview_get_selected_item(FolderView *folderview)
996 g_return_val_if_fail(folderview != NULL, NULL);
997 g_return_val_if_fail(folderview->ctree != NULL, NULL);
999 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
1001 if (!folderview->selected) return NULL;
1002 return gtk_cmctree_node_get_row_data(ctree, folderview->selected);
1005 FolderItem *folderview_get_opened_item(FolderView *folderview)
1007 g_return_val_if_fail(folderview != NULL, NULL);
1008 g_return_val_if_fail(folderview->ctree != NULL, NULL);
1010 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
1012 if (!folderview->opened) return NULL;
1013 return gtk_cmctree_node_get_row_data(ctree, folderview->opened);
1016 static void folderview_set_folders(FolderView *folderview)
1018 GList *list;
1019 list = folder_get_list();
1021 for (; list != NULL; list = list->next) {
1022 folderview_append_folder(folderview, FOLDER(list->data));
1026 static gchar *get_scan_str(FolderItem *item)
1028 if (item->path)
1029 return g_strdup_printf(_("Scanning folder %s/%s..."),
1030 item->folder->name, item->path);
1031 else
1032 return g_strdup_printf(_("Scanning folder %s..."),
1033 item->folder->name);
1035 static void folderview_scan_tree_func(Folder *folder, FolderItem *item,
1036 gpointer data)
1038 GList *list;
1039 for (list = folderview_list; list != NULL; list = list->next) {
1040 FolderView *folderview = (FolderView *)list->data;
1041 MainWindow *mainwin = folderview->mainwin;
1042 gchar *str = get_scan_str(item);
1044 STATUSBAR_PUSH(mainwin, str);
1045 STATUSBAR_POP(mainwin);
1046 g_free(str);
1050 void folderview_rescan_tree(Folder *folder, gboolean rebuild)
1052 GtkWidget *window;
1053 MainWindow *mainwin = mainwindow_get_mainwindow();
1054 FolderView *folderview = NULL;
1055 GtkAdjustment *pos = NULL;
1056 gint height = 0;
1058 cm_return_if_fail(folder != NULL);
1060 if (!folder->klass->scan_tree) return;
1062 if (rebuild &&
1063 alertpanel_full(_("Rebuild folder tree"),
1064 _("Rebuilding the folder tree will remove "
1065 "local caches. Do you want to continue?"),
1066 GTK_STOCK_NO, GTK_STOCK_YES, NULL, FALSE,
1067 NULL, ALERT_WARNING, G_ALERTDEFAULT)
1068 != G_ALERTALTERNATE) {
1069 return;
1072 inc_lock();
1073 if (rebuild)
1074 window = label_window_create(_("Rebuilding folder tree..."));
1075 else
1076 window = label_window_create(_("Scanning folder tree..."));
1078 if (mainwin)
1079 folderview = mainwin->folderview;
1081 if (folderview) {
1082 pos = gtk_scrolled_window_get_vadjustment(
1083 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1084 height = gtk_adjustment_get_value(pos);
1087 folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
1088 folder_scan_tree(folder, rebuild);
1089 folder_set_ui_func(folder, NULL, NULL);
1091 folderview_set_all();
1093 if (folderview) {
1094 pos = gtk_scrolled_window_get_vadjustment(
1095 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
1096 gtk_adjustment_set_value(pos, height);
1097 gtk_adjustment_changed(pos);
1099 label_window_destroy(window);
1100 inc_unlock();
1103 /** folderview_check_new()
1104 * Scan and update the folder and return the
1105 * count the number of new messages since last check.
1106 * \param folder the folder to check for new messages
1107 * \return the number of new messages since last check
1109 gint folderview_check_new(Folder *folder)
1111 GList *list;
1112 FolderItem *item;
1113 FolderView *folderview;
1114 GtkCMCTree *ctree;
1115 GtkCMCTreeNode *node;
1116 gint new_msgs = 0;
1117 gint former_new_msgs = 0;
1118 gint former_new = 0, former_unread = 0, former_total;
1120 for (list = folderview_list; list != NULL; list = list->next) {
1121 folderview = (FolderView *)list->data;
1122 ctree = GTK_CMCTREE(folderview->ctree);
1123 folderview->scanning_folder = folder;
1124 inc_lock();
1125 main_window_lock(folderview->mainwin);
1127 for (node = GTK_CMCTREE_NODE(GTK_CMCLIST(ctree)->row_list);
1128 node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
1129 gchar *str = NULL;
1130 item = gtk_cmctree_node_get_row_data(ctree, node);
1131 if (!item || !item->path || !item->folder) continue;
1132 if (item->no_select) continue;
1133 if (folder && folder != item->folder) continue;
1134 if (!folder && !FOLDER_IS_LOCAL(item->folder)) continue;
1135 if (!item->prefs->newmailcheck) continue;
1136 if (item->processing_pending == TRUE) {
1137 debug_print("skipping %s, processing pending\n",
1138 item->path ? item->path : item->name);
1139 continue;
1141 if (item->scanning != ITEM_NOT_SCANNING) {
1142 debug_print("skipping %s, scanning\n",
1143 item->path ? item->path : item->name);
1144 continue;
1147 str = get_scan_str(item);
1149 STATUSBAR_PUSH(folderview->mainwin, str);
1150 GTK_EVENTS_FLUSH();
1151 g_free(str);
1153 folderview_scan_tree_func(item->folder, item, NULL);
1154 former_new = item->new_msgs;
1155 former_unread = item->unread_msgs;
1156 former_total = item->total_msgs;
1158 if (item->folder->klass->scan_required &&
1159 (item->folder->klass->scan_required(item->folder, item) ||
1160 item->folder->inbox == item ||
1161 item->opened == TRUE ||
1162 item->processing_pending == TRUE)) {
1163 if (folder_item_scan(item) < 0) {
1164 if (folder) {
1165 summaryview_unlock(folderview->summaryview, item);
1166 if (FOLDER_TYPE(item->folder) == F_NEWS || FOLDER_IS_LOCAL(folder)) {
1167 log_error(LOG_PROTOCOL, _("Couldn't scan folder %s\n"),
1168 item->path ? item->path:item->name);
1169 STATUSBAR_POP(folderview->mainwin);
1170 continue;
1171 } else if (!FOLDER_IS_LOCAL(folder)) {
1172 STATUSBAR_POP(folderview->mainwin);
1173 break;
1177 } else if (!item->folder->klass->scan_required) {
1178 if (folder_item_scan(item) < 0) {
1179 summaryview_unlock(folderview->summaryview, item);
1180 if (folder && !FOLDER_IS_LOCAL(folder)) {
1181 STATUSBAR_POP(folderview->mainwin);
1182 break;
1186 if (former_new != item->new_msgs ||
1187 former_unread != item->unread_msgs ||
1188 former_total != item->total_msgs)
1189 folderview_update_node(folderview, node);
1191 new_msgs += item->new_msgs;
1192 former_new_msgs += former_new;
1193 STATUSBAR_POP(folderview->mainwin);
1195 folderview->scanning_folder = NULL;
1196 main_window_unlock(folderview->mainwin);
1197 inc_unlock();
1200 folder_write_list();
1201 /* Number of new messages since last check is the just the difference
1202 * between former_new_msgs and new_msgs. If new_msgs is less than
1203 * former_new_msgs, that would mean another session accessed the folder
1204 * and the result is not well defined.
1206 new_msgs = (former_new_msgs < new_msgs ? new_msgs - former_new_msgs : 0);
1207 return new_msgs;
1210 void folderview_check_new_all(void)
1212 GList *list;
1213 GtkWidget *window;
1214 FolderView *folderview;
1216 folderview = (FolderView *)folderview_list->data;
1218 inc_lock();
1219 main_window_lock(folderview->mainwin);
1220 window = label_window_create
1221 (_("Checking for new messages in all folders..."));
1223 list = folder_get_list();
1224 for (; list != NULL; list = list->next) {
1225 Folder *folder = list->data;
1227 folderview_check_new(folder);
1230 folder_write_list();
1231 folderview_set_all();
1233 label_window_destroy(window);
1234 main_window_unlock(folderview->mainwin);
1235 inc_unlock();
1238 static gboolean folderview_have_children_sub(FolderView *folderview,
1239 FolderItem *item,
1240 gboolean in_sub)
1242 GNode *node = NULL;
1244 if (!item || !item->folder || !item->folder->node)
1245 return FALSE;
1247 node = item->folder->node;
1249 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1250 node = node->children;
1252 if (in_sub && item->total_msgs > 0) {
1253 return TRUE;
1256 while (node != NULL) {
1257 if (node && node->data) {
1258 FolderItem *next_item = (FolderItem*) node->data;
1259 node = node->next;
1260 if (folderview_have_children_sub(folderview,
1261 next_item, TRUE))
1262 return TRUE;
1266 return FALSE;
1269 static gboolean folderview_have_children(FolderView *folderview,
1270 FolderItem *item)
1272 return folderview_have_children_sub(folderview, item, FALSE);
1275 static gboolean folderview_have_new_children_sub(FolderView *folderview,
1276 FolderItem *item,
1277 gboolean in_sub)
1279 GNode *node = NULL;
1281 if (!item || !item->folder || !item->folder->node)
1282 return FALSE;
1284 node = item->folder->node;
1286 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1287 node = node->children;
1289 if (in_sub &&
1290 (item->new_msgs > 0 ||
1291 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1292 return TRUE;
1295 while (node != NULL) {
1296 if (node && node->data) {
1297 FolderItem *next_item = (FolderItem*) node->data;
1298 node = node->next;
1299 if (folderview_have_new_children_sub(folderview,
1300 next_item, TRUE))
1301 return TRUE;
1305 return FALSE;
1308 static gboolean folderview_have_new_children(FolderView *folderview,
1309 FolderItem *item)
1311 return folderview_have_new_children_sub(folderview, item, FALSE);
1314 static gboolean folderview_have_unread_children_sub(FolderView *folderview,
1315 FolderItem *item,
1316 gboolean in_sub)
1318 GNode *node = NULL;
1320 if (!item || !item->folder || !item->folder->node)
1321 return FALSE;
1323 node = item->folder->node;
1325 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1326 node = node->children;
1328 if (in_sub &&
1329 (item->unread_msgs > 0 ||
1330 (folder_has_parent_of_type(item, F_QUEUE) && item->total_msgs > 0))) {
1331 return TRUE;
1334 while (node != NULL) {
1335 if (node && node->data) {
1336 FolderItem *next_item = (FolderItem*) node->data;
1337 node = node->next;
1338 if (folderview_have_unread_children_sub(folderview,
1339 next_item,
1340 TRUE))
1341 return TRUE;
1345 return FALSE;
1348 static gboolean folderview_have_unread_children(FolderView *folderview,
1349 FolderItem *item)
1351 return folderview_have_unread_children_sub(folderview, item, FALSE);
1354 static gboolean folderview_have_matching_children_sub(FolderView *folderview,
1355 FolderItem *item,
1356 gboolean in_sub)
1358 GNode *node = NULL;
1360 if (!item || !item->folder || !item->folder->node)
1361 return FALSE;
1363 node = item->folder->node;
1365 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1366 node = node->children;
1368 if (in_sub && item->search_match){
1369 return TRUE;
1372 while (node != NULL) {
1373 if (node && node->data) {
1374 FolderItem *next_item = (FolderItem*) node->data;
1375 node = node->next;
1376 if (folderview_have_matching_children_sub(folderview,
1377 next_item,
1378 TRUE))
1379 return TRUE;
1383 return FALSE;
1386 static gboolean folderview_have_matching_children(FolderView *folderview,
1387 FolderItem *item)
1389 return folderview_have_matching_children_sub(folderview, item, FALSE);
1392 static gboolean folderview_have_marked_children_sub(FolderView *folderview,
1393 FolderItem *item,
1394 gboolean in_sub)
1396 GNode *node = NULL;
1398 if (!item || !item->folder || !item->folder->node)
1399 return FALSE;
1401 node = item->folder->node;
1403 node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
1404 node = node->children;
1406 if (item->marked_msgs != 0) {
1407 return TRUE;
1410 while (node != NULL) {
1411 if (node && node->data) {
1412 FolderItem *next_item = (FolderItem*) node->data;
1413 node = node->next;
1414 if (folderview_have_marked_children_sub(folderview,
1415 next_item, TRUE))
1416 return TRUE;
1420 return FALSE;
1423 static gboolean folderview_have_marked_children(FolderView *folderview,
1424 FolderItem *item)
1426 return folderview_have_marked_children_sub(folderview, item, FALSE);
1429 static void folderview_update_node(FolderView *folderview, GtkCMCTreeNode *node)
1431 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
1432 GtkStyle *style = NULL;
1433 GtkStyle *color_style = NULL;
1434 FolderItem *item;
1435 GdkPixbuf *xpm, *openxpm;
1436 static GdkPixbuf *searchicon;
1437 gboolean mark = FALSE;
1438 gchar *name;
1439 gchar *str;
1440 gboolean add_unread_mark;
1441 gboolean add_sub_match_mark;
1442 gboolean use_bold, use_color;
1443 gint *col_pos = folderview->col_pos;
1444 SpecialFolderItemType stype;
1446 item = gtk_cmctree_node_get_row_data(ctree, node);
1447 cm_return_if_fail(item != NULL);
1449 if (!GTK_CMCTREE_ROW(node)->expanded)
1450 mark = folderview_have_marked_children(folderview, item);
1451 else
1452 mark = (item->marked_msgs != 0);
1454 stype = item->stype;
1455 if (stype == F_NORMAL) {
1456 if (folder_has_parent_of_type(item, F_TRASH))
1457 stype = F_TRASH;
1458 else if (folder_has_parent_of_type(item, F_DRAFT))
1459 stype = F_DRAFT;
1460 else if (folder_has_parent_of_type(item, F_OUTBOX))
1461 stype = F_OUTBOX;
1462 else if (folder_has_parent_of_type(item, F_QUEUE))
1463 stype = F_QUEUE;
1465 switch (stype) {
1466 case F_INBOX:
1467 if (item->hide_read_msgs || item->hide_read_threads) {
1468 xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
1469 openxpm = mark?m_inboxopenhrmxpm:inboxopenhrmxpm;
1470 } else {
1471 xpm = mark?m_inboxxpm:inboxxpm;
1472 openxpm = mark?m_inboxopenxpm:inboxopenxpm;
1474 break;
1475 case F_OUTBOX:
1476 if (item->hide_read_msgs || item->hide_read_threads) {
1477 xpm = mark?m_outboxhrmxpm:outboxhrmxpm;
1478 openxpm = mark?m_outboxopenhrmxpm:outboxopenhrmxpm;
1479 } else {
1480 xpm = mark?m_outboxxpm:outboxxpm;
1481 openxpm = mark?m_outboxopenxpm:outboxopenxpm;
1483 break;
1484 case F_QUEUE:
1485 if (item->hide_read_msgs || item->hide_read_threads) {
1486 xpm = mark?m_queuehrmxpm:queuehrmxpm;
1487 openxpm = mark?m_queueopenhrmxpm:queueopenhrmxpm;
1488 } else {
1489 xpm = mark?m_queuexpm:queuexpm;
1490 openxpm = mark?m_queueopenxpm:queueopenxpm;
1492 break;
1493 case F_TRASH:
1494 if (item->hide_read_msgs || item->hide_read_threads) {
1495 xpm = mark?m_trashhrmxpm:trashhrmxpm;
1496 openxpm = mark?m_trashopenhrmxpm:trashopenhrmxpm;
1497 } else {
1498 xpm = mark?m_trashxpm:trashxpm;
1499 openxpm = mark?m_trashopenxpm:trashopenxpm;
1501 break;
1502 case F_DRAFT:
1503 xpm = mark?m_draftsxpm:draftsxpm;
1504 openxpm = mark?m_draftsopenxpm:draftsopenxpm;
1505 break;
1506 default:
1507 if (!item->path &&
1508 FOLDER_TYPE(item->folder) == F_IMAP &&
1509 item->folder->account->imap_subsonly) {
1510 xpm = mark?m_foldersubsxpm:foldersubsxpm;
1511 openxpm = foldersubsopenxpm;
1512 } else if (item->no_select) {
1513 xpm = mark?m_foldernoselectxpm:foldernoselectxpm;
1514 openxpm = foldernoselectopenxpm;
1515 } else if (item->hide_read_msgs || item->hide_read_threads) {
1516 xpm = mark?m_folderhrmxpm:folderhrmxpm;
1517 openxpm = mark?m_folderopenhrmxpm:folderopenhrmxpm;
1518 } else {
1519 xpm = mark?m_folderxpm:folderxpm;
1520 openxpm = mark?m_folderopenxpm:folderopenxpm;
1524 name = folder_item_get_name(item);
1526 if (!GTK_CMCTREE_ROW(node)->expanded) {
1527 add_unread_mark = folderview_have_unread_children(
1528 folderview, item);
1529 add_sub_match_mark = folderview_have_matching_children(
1530 folderview, item);
1531 } else {
1532 add_unread_mark = FALSE;
1533 add_sub_match_mark = FALSE;
1536 if (item->search_match) {
1537 if (!searchicon) {
1538 stock_pixbuf_gdk(STOCK_PIXMAP_QUICKSEARCH,
1539 &searchicon);
1541 xpm = openxpm = searchicon;
1544 str = NULL;
1545 if (prefs_common.display_folder_unread) {
1546 if (folder_has_parent_of_type(item, F_QUEUE)) {
1547 /* only total_msgs matters here */
1548 if (item->total_msgs > 0) {
1549 /* show total number (should be equal to the unread number)
1550 and signs if any */
1551 str = g_strdup_printf("%s (%d%s%s)",
1552 name, item->total_msgs,
1553 (add_unread_mark || add_sub_match_mark) ? "+" : "",
1554 (item->unreadmarked_msgs > 0) ? "!" : "");
1556 } else {
1557 if (prefs_common.display_folder_unread == 1) {
1558 if (item->unread_msgs > 0) {
1559 /* show unread number and signs */
1560 str = g_strdup_printf("%s (%d%s%s)",
1561 name, item->unread_msgs,
1562 (add_unread_mark || add_sub_match_mark) ? "+" : "",
1563 (item->unreadmarked_msgs > 0) ? "!" : "");
1565 } else {
1566 if (item->total_msgs > 0) {
1567 /* show unread number, total number and signs if any */
1568 str = g_strdup_printf("%s (%d/%d%s%s)",
1569 name, item->unread_msgs, item->total_msgs,
1570 (add_unread_mark || add_sub_match_mark) ? "+" : "",
1571 (item->unreadmarked_msgs > 0) ? "!" : "");
1575 if ((str == NULL) &&
1576 (add_unread_mark || add_sub_match_mark || (item->unreadmarked_msgs > 0))) {
1577 /* no unread/total numbers, but at least one sign */
1578 str = g_strdup_printf("%s (%s%s)",
1579 name,
1580 (add_unread_mark || add_sub_match_mark) ? "+" : "",
1581 (item->unreadmarked_msgs > 0) ? "!" : "");
1584 if (str == NULL) {
1585 /* last fallback, folder name only or with +! sign */
1586 if (item->unreadmarked_msgs > 0 && add_sub_match_mark) {
1587 str = g_strdup_printf("%s%s",
1588 name, " (+!)");
1589 } else if (item->unreadmarked_msgs > 0) {
1590 str = g_strdup_printf("%s%s",
1591 name, " (!)");
1592 } else if (add_sub_match_mark) {
1593 str = g_strdup_printf("%s%s",
1594 name, " (+)");
1595 } else {
1596 str = g_strdup_printf("%s", name);
1599 gtk_cmctree_set_node_info(ctree, node, str, FOLDER_SPACING,
1600 xpm, openxpm,
1601 FALSE, GTK_CMCTREE_ROW(node)->expanded);
1602 g_free(str);
1603 g_free(name);
1605 if (!folder_item_parent(item)) {
1606 gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_NEW], "-");
1607 gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], "-");
1608 gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], "-");
1609 } else {
1610 gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_NEW], item->new_msgs > 0 ? itos(item->new_msgs) : prefs_common.zero_replacement);
1611 gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_UNREAD], item->unread_msgs > 0 ? itos(item->unread_msgs) : prefs_common.zero_replacement);
1612 gtk_cmctree_node_set_text(ctree, node, col_pos[F_COL_TOTAL], item->total_msgs > 0 ? itos(item->total_msgs) : prefs_common.zero_replacement);
1615 if (folder_has_parent_of_type(item, F_OUTBOX) ||
1616 folder_has_parent_of_type(item, F_TRASH)) {
1617 use_bold = use_color = FALSE;
1618 } else if (folder_has_parent_of_type(item, F_QUEUE)) {
1619 GSList *list = folder_item_get_msg_list(item);
1620 GSList *cur;
1621 use_bold = use_color = FALSE;
1622 for (cur = list; cur; cur = cur->next) {
1623 MsgInfo *msginfo = (MsgInfo *)cur->data;
1624 if (!MSG_IS_DELETED(msginfo->flags)) {
1625 /* highlight queue folder if there are any messages */
1626 use_bold = use_color = TRUE;
1627 break;
1630 if (!GTK_CMCTREE_ROW(node)->expanded &&
1631 use_bold == FALSE &&
1632 folderview_have_children(folderview, item))
1633 use_bold = use_color = TRUE;
1634 procmsg_msg_list_free(list);
1635 } else {
1636 /* if unread messages exist, print with bold font */
1637 use_bold = (item->unread_msgs > 0|| item->new_msgs > 0)
1638 || add_unread_mark;
1639 /* if new messages exist, print with colored letter */
1640 use_color =
1641 (item->new_msgs > 0) ||
1642 (add_unread_mark &&
1643 folderview_have_new_children(folderview, item));
1646 gtk_cmctree_node_set_foreground(ctree, node, NULL);
1648 if (use_bold) {
1649 GdkColor gdk_color;
1651 if (item->prefs->color > 0 && !use_color) {
1652 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1653 color_style = gtk_style_copy(bold_style);
1654 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1655 style = color_style;
1656 } else if (use_color) {
1657 style = bold_color_style;
1658 } else
1659 style = bold_style;
1660 if (item->op_count > 0) {
1661 style = bold_tgtfold_style;
1663 } else if (use_color) {
1664 style = normal_color_style;
1665 gtk_cmctree_node_set_foreground(ctree, node,
1666 &folderview->color_new);
1667 } else if (item->op_count > 0) {
1668 style = bold_tgtfold_style;
1669 } else if (item->prefs->color > 0) {
1670 GdkColor gdk_color;
1671 gtkut_convert_int_to_gdk_color(item->prefs->color, &gdk_color);
1672 color_style = gtk_style_copy(normal_style);
1673 color_style->fg[GTK_STATE_NORMAL] = gdk_color;
1674 style = color_style;
1675 } else {
1676 style = normal_style;
1679 gtk_cmctree_node_set_row_style(ctree, node, style);
1681 if ((node = gtkut_ctree_find_collapsed_parent(ctree, node)) != NULL)
1682 folderview_update_node(folderview, node);
1685 void folderview_update_search_icon(FolderItem *item, gboolean matches)
1687 GList *list;
1688 FolderView *folderview;
1689 GtkCMCTree *ctree;
1690 GtkCMCTreeNode *node;
1692 cm_return_if_fail(item != NULL);
1694 for (list = folderview_list; list != NULL; list = list->next) {
1695 folderview = (FolderView *)list->data;
1696 ctree = GTK_CMCTREE(folderview->ctree);
1698 node = gtk_cmctree_find_by_row_data(ctree, NULL, item);
1699 if (node && item->search_match != matches) {
1700 item->search_match = matches;
1701 folderview_update_node(folderview, node);
1706 static gboolean folderview_update_item_claws(gpointer source, gpointer data)
1708 FolderItemUpdateData *update_info = (FolderItemUpdateData *)source;
1709 FolderView *folderview = (FolderView *)data;
1710 GtkCMCTree *ctree;
1711 GtkCMCTreeNode *node;
1712 cm_return_val_if_fail(update_info != NULL, TRUE);
1713 cm_return_val_if_fail(update_info->item != NULL, TRUE);
1714 cm_return_val_if_fail(folderview != NULL, FALSE);
1716 ctree = GTK_CMCTREE(folderview->ctree);
1718 node = gtk_cmctree_find_by_row_data(ctree, NULL, update_info->item);
1720 if (node) {
1721 if (update_info->update_flags & (F_ITEM_UPDATE_MSGCNT | F_ITEM_UPDATE_NAME))
1722 folderview_update_node(folderview, node);
1724 if ((update_info->update_flags & F_ITEM_UPDATE_CONTENT) &&
1725 update_info->item == folderview->summaryview->folder_item &&
1726 update_info->item != NULL)
1727 if (!quicksearch_has_sat_predicate(folderview->summaryview->quicksearch))
1728 summary_show(folderview->summaryview, update_info->item);
1731 return FALSE;
1734 static gboolean folderview_gnode_func(GtkCMCTree *ctree, guint depth,
1735 GNode *gnode, GtkCMCTreeNode *cnode,
1736 gpointer data)
1738 FolderView *folderview = (FolderView *)data;
1739 FolderItem *item = FOLDER_ITEM(gnode->data);
1741 cm_return_val_if_fail(item != NULL, FALSE);
1743 gtk_cmctree_node_set_row_data(ctree, cnode, item);
1744 folderview_update_node(folderview, cnode);
1746 return TRUE;
1749 static void folderview_expand_func(GtkCMCTree *ctree, GtkCMCTreeNode *node,
1750 gpointer data)
1752 FolderView *folderview = (FolderView *)data;
1753 FolderItem *item;
1755 if (GTK_CMCTREE_ROW(node)->children) {
1756 item = gtk_cmctree_node_get_row_data(ctree, node);
1757 cm_return_if_fail(item != NULL);
1759 if (!item->collapsed)
1760 gtk_cmctree_expand(ctree, node);
1761 else
1762 folderview_update_node(folderview, node);
1766 static void set_special_folder(GtkCMCTree *ctree, FolderItem *item,
1767 GtkCMCTreeNode *root, GtkCMCTreeNode **prev)
1769 if (item) {
1770 GtkCMCTreeNode *node, *parent, *sibling;
1772 node = gtk_cmctree_find_by_row_data(ctree, root, item);
1773 if (!node)
1774 g_warning("%s not found.", item->path);
1775 else {
1776 parent = GTK_CMCTREE_ROW(node)->parent;
1777 if (*prev && parent == GTK_CMCTREE_ROW(*prev)->parent)
1778 sibling = GTK_CMCTREE_ROW(*prev)->sibling;
1779 else
1780 sibling = GTK_CMCTREE_ROW(parent)->children;
1781 while (sibling) {
1782 FolderItem *tmp;
1784 tmp = gtk_cmctree_node_get_row_data
1785 (ctree, sibling);
1786 if (tmp && tmp->stype != F_NORMAL)
1787 sibling = GTK_CMCTREE_ROW(sibling)->sibling;
1788 else
1789 break;
1791 if (node != sibling)
1792 gtk_cmctree_move(ctree, node, parent, sibling);
1795 *prev = node;
1799 static void folderview_sort_folders(FolderView *folderview, GtkCMCTreeNode *root,
1800 Folder *folder)
1802 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
1803 GtkCMCTreeNode *prev = NULL;
1805 gtk_cmclist_freeze(GTK_CMCLIST(ctree));
1806 gtk_sctree_sort_recursive(ctree, root);
1807 if (root && GTK_CMCTREE_ROW(root)->parent) {
1808 gtk_cmclist_thaw(GTK_CMCLIST(ctree));
1809 return;
1811 set_special_folder(ctree, folder->inbox, root, &prev);
1812 set_special_folder(ctree, folder->outbox, root, &prev);
1813 set_special_folder(ctree, folder->draft, root, &prev);
1814 set_special_folder(ctree, folder->queue, root, &prev);
1815 set_special_folder(ctree, folder->trash, root, &prev);
1816 gtk_cmclist_thaw(GTK_CMCLIST(ctree));
1819 static void folderview_append_folder(FolderView *folderview, Folder *folder)
1821 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
1822 GtkCMCTreeNode *root;
1824 cm_return_if_fail(folder != NULL);
1826 root = gtk_sctree_insert_gnode(ctree, NULL, NULL, folder->node,
1827 folderview_gnode_func, folderview);
1828 gtk_cmctree_pre_recursive(ctree, root, folderview_expand_func,
1829 folderview);
1830 folderview_sort_folders(folderview, root, folder);
1833 /* callback functions */
1834 static void folderview_set_sens_and_popup_menu(FolderView *folderview, gint row,
1835 GdkEventButton *event)
1837 FolderItem *item;
1838 Folder *folder;
1839 FolderViewPopup *fpopup;
1840 GtkActionGroup *action_group;
1841 GtkWidget *popup;
1842 FolderItem *special_trash = NULL, *special_queue = NULL;
1843 PrefsAccount *ac;
1844 GtkUIManager *ui_manager = gtk_ui_manager_new();
1846 if (folderview->ui_manager)
1847 g_object_unref(folderview->ui_manager);
1849 folderview->ui_manager = ui_manager;
1850 item = folderview_get_selected_item(folderview);
1852 cm_return_if_fail(item != NULL);
1853 cm_return_if_fail(item->folder != NULL);
1854 folder = item->folder;
1856 fpopup = g_hash_table_lookup(folderview_popups, folder->klass->idstr);
1858 if (fpopup != NULL)
1859 action_group = g_hash_table_lookup(folderview->popups, folder->klass->idstr);
1860 else {
1861 fpopup = g_hash_table_lookup(folderview_popups, "common");
1862 action_group = g_hash_table_lookup(folderview->popups, "common");
1865 gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
1866 MENUITEM_ADDUI_MANAGER(ui_manager, "/", "Popup", "Popup", GTK_UI_MANAGER_MENUBAR)
1867 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup", "FolderViewPopup", "FolderViewPopup", GTK_UI_MANAGER_MENU)
1869 if (fpopup->add_menuitems)
1870 fpopup->add_menuitems(ui_manager, item);
1872 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "MarkAllRead", "FolderViewPopup/MarkAllRead", GTK_UI_MANAGER_MENUITEM)
1873 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "MarkAllReadRec", "FolderViewPopup/MarkAllReadRec", GTK_UI_MANAGER_MENUITEM)
1874 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "Separator1", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
1875 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "RunProcessing", "FolderViewPopup/RunProcessing", GTK_UI_MANAGER_MENUITEM)
1876 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SearchFolder", "FolderViewPopup/SearchFolder", GTK_UI_MANAGER_MENUITEM)
1877 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "Properties", "FolderViewPopup/Properties", GTK_UI_MANAGER_MENUITEM)
1878 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "Processing", "FolderViewPopup/Processing", GTK_UI_MANAGER_MENUITEM)
1880 if (fpopup->set_sensitivity != NULL)
1881 fpopup->set_sensitivity(ui_manager, item);
1883 if (NULL != (ac = account_find_from_item(item))) {
1884 special_trash = account_get_special_folder(ac, F_TRASH);
1885 special_queue = account_get_special_folder(ac, F_QUEUE);
1888 if ((item == folder->trash || item == special_trash
1889 || folder_has_parent_of_type(item, F_TRASH))) {
1890 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorTrash", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
1891 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "EmptyTrash", "FolderViewPopup/EmptyTrash", GTK_UI_MANAGER_MENUITEM)
1894 if ((item == folder->queue || item == special_queue
1895 || folder_has_parent_of_type(item, F_QUEUE))) {
1896 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SeparatorQueue", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR)
1897 MENUITEM_ADDUI_MANAGER(ui_manager, "/Popup/FolderViewPopup", "SendQueue", "FolderViewPopup/SendQueue", GTK_UI_MANAGER_MENUITEM)
1900 #define SET_SENS(name, sens) \
1901 cm_menu_set_sensitive_full(ui_manager, "Popup/"name, sens)
1903 SET_SENS("FolderViewPopup/MarkAllRead", item->unread_msgs >= 1);
1904 SET_SENS("FolderViewPopup/MarkAllReadRec", folderview_have_unread_children(folderview,item));
1905 SET_SENS("FolderViewPopup/SearchFolder", item->total_msgs >= 1 &&
1906 folderview->selected == folderview->opened);
1907 SET_SENS("FolderViewPopup/Properties", TRUE);
1909 SET_SENS("FolderViewPopup/RunProcessing", item->prefs->processing &&
1910 item->total_msgs >= 1 && !item->processing_pending);
1911 SET_SENS("FolderViewPopup/Processing", item->node->parent != NULL &&
1912 !item->no_select && !item->processing_pending);
1914 if (item == folder->trash || item == special_trash
1915 || folder_has_parent_of_type(item, F_TRASH)) {
1916 GSList *msglist = folder_item_get_msg_list(item);
1917 SET_SENS("FolderViewPopup/EmptyTrash", msglist != NULL);
1918 procmsg_msg_list_free(msglist);
1920 if (item == folder->queue || item == special_queue
1921 || folder_has_parent_of_type(item, F_QUEUE)) {
1922 GSList *msglist = folder_item_get_msg_list(item);
1923 SET_SENS("FolderViewPopup/SendQueue", msglist != NULL);
1924 procmsg_msg_list_free(msglist);
1926 #undef SET_SENS
1928 popup = gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1929 gtk_ui_manager_get_widget(ui_manager, "/Popup/FolderViewPopup")) );
1930 g_signal_connect(G_OBJECT(popup), "selection_done",
1931 G_CALLBACK(folderview_popup_close),
1932 folderview);
1933 gtk_menu_popup(GTK_MENU(popup), NULL, NULL, NULL, NULL,
1934 event->button, event->time);
1937 static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *event,
1938 FolderView *folderview)
1940 GtkCMCList *clist = GTK_CMCLIST(ctree);
1941 gint prev_row = -1, row = -1, column = -1;
1943 if (!event) return FALSE;
1945 if (event->button == 1 || event->button == 2) {
1946 if (!gtk_sctree_is_hot_spot (GTK_SCTREE(clist), event->x, event->y))
1947 folderview->open_folder = TRUE;
1949 if (event->type == GDK_2BUTTON_PRESS) {
1950 if (clist->selection) {
1951 GtkCMCTreeNode *node;
1953 node = GTK_CMCTREE_NODE(clist->selection->data);
1954 if (node) {
1955 gtk_cmctree_toggle_expansion(
1956 GTK_CMCTREE(ctree),
1957 node);
1958 folderview->open_folder = FALSE;
1962 return FALSE;
1965 if (event->button == 2 || event->button == 3) {
1966 /* right clicked */
1967 if (clist->selection) {
1968 GtkCMCTreeNode *node;
1970 node = GTK_CMCTREE_NODE(clist->selection->data);
1971 if (node)
1972 prev_row = gtkut_ctree_get_nth_from_node
1973 (GTK_CMCTREE(ctree), node);
1976 if (!gtk_cmclist_get_selection_info(clist, event->x, event->y,
1977 &row, &column))
1978 return FALSE;
1979 if (prev_row != row) {
1980 gtk_cmclist_unselect_all(clist);
1981 if (event->button == 2)
1982 folderview_select_node
1983 (folderview,
1984 gtk_cmctree_node_nth(GTK_CMCTREE(ctree),
1985 row));
1986 else
1987 gtk_cmclist_select_row(clist, row, column);
1991 if (event->button != 3) return FALSE;
1993 folderview_set_sens_and_popup_menu(folderview, row, event);
1994 return FALSE;
1997 static gboolean folderview_button_released(GtkWidget *ctree, GdkEventButton *event,
1998 FolderView *folderview)
2000 int row = -1, column = -1;
2002 if (!event) return FALSE;
2004 if (!gtk_cmclist_get_selection_info(GTK_CMCLIST(ctree), event->x, event->y,
2005 &row, &column))
2006 return FALSE;
2007 if (event->button == 1 && folderview->open_folder == FALSE &&
2008 folderview->opened != NULL) {
2009 gtkut_ctree_set_focus_row(GTK_CMCTREE(ctree),
2010 folderview->opened);
2011 gtk_cmctree_select(GTK_CMCTREE(ctree), folderview->opened);
2014 return FALSE;
2017 #define BREAK_ON_MODIFIER_KEY() \
2018 if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0) break
2020 static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
2021 FolderView *folderview)
2023 GtkCMCTreeNode *node;
2024 FolderItem *item;
2026 if (!event) return FALSE;
2028 if (quicksearch_has_focus(folderview->summaryview->quicksearch))
2029 return FALSE;
2031 switch (event->keyval) {
2032 case GDK_KEY_Right:
2033 if (folderview->selected) {
2034 if (GTK_CMCTREE_ROW(folderview->selected)->children != NULL
2035 && !GTK_CMCTREE_ROW(folderview->selected)->expanded)
2036 gtk_cmctree_expand(GTK_CMCTREE(folderview->ctree),
2037 folderview->selected);
2038 else
2039 folderview_select_node(folderview,
2040 folderview->selected);
2042 break;
2043 #ifdef GENERIC_UMPC
2044 case GDK_KEY_Return:
2045 if (folderview->selected && GTK_CMCTREE_ROW(folderview->selected)->children) {
2046 gtk_cmctree_toggle_expansion(
2047 GTK_CMCTREE(folderview->ctree),
2048 folderview->selected);
2050 break;
2051 #else
2052 case GDK_KEY_Return:
2053 case GDK_KEY_KP_Enter:
2054 if (folderview->selected)
2055 folderview_select_node(folderview, folderview->selected);
2056 break;
2057 #endif
2058 case GDK_KEY_space:
2059 BREAK_ON_MODIFIER_KEY();
2060 if (folderview->selected) {
2061 if (folderview->opened == folderview->selected &&
2062 (!folderview->summaryview->folder_item ||
2063 folderview->summaryview->folder_item->total_msgs == 0))
2064 folderview_select_next_with_flag(folderview, MSG_UNREAD, TRUE);
2065 else
2066 folderview_select_node(folderview,
2067 folderview->selected);
2069 break;
2070 case GDK_KEY_Left:
2071 if (folderview->selected) {
2072 if (GTK_CMCTREE_ROW(folderview->selected)->expanded) {
2073 gtk_cmctree_collapse(GTK_CMCTREE(folderview->ctree),
2074 folderview->selected);
2075 } else {
2076 if ((item = gtk_cmctree_node_get_row_data(GTK_CMCTREE(folderview->ctree),
2077 folderview->selected))) {
2078 if ((node = gtk_cmctree_find_by_row_data(GTK_CMCTREE(folderview->ctree),
2079 NULL, folder_item_parent(item)))) {
2080 gtk_sctree_select(GTK_SCTREE(folderview->ctree), node);
2081 if (!gtk_cmctree_node_is_visible(GTK_CMCTREE(folderview->ctree), node))
2082 gtk_cmctree_node_moveto(GTK_CMCTREE(folderview->ctree),
2083 node, -1, 0, 0);
2088 break;
2089 case GDK_KEY_Home:
2090 case GDK_KEY_End:
2091 if (event->keyval == GDK_KEY_Home)
2092 node = gtk_cmctree_node_nth(GTK_CMCTREE(folderview->ctree), 0);
2093 else
2094 node = gtk_cmctree_last(GTK_CMCTREE(folderview->ctree),
2095 gtk_cmctree_node_nth(GTK_CMCTREE(folderview->ctree), 0));
2097 gtk_sctree_select(GTK_SCTREE(folderview->ctree), node);
2099 if (!gtk_cmctree_node_is_visible(GTK_CMCTREE(folderview->ctree), node))
2100 gtk_cmctree_node_moveto(GTK_CMCTREE(folderview->ctree),
2101 node, -1, 0, 0);
2102 break;
2103 default:
2104 break;
2107 return FALSE;
2110 typedef struct _PostponedSelectData
2112 GtkCMCTree *ctree;
2113 GtkCMCTreeNode *row;
2114 gint column;
2115 FolderView *folderview;
2116 } PostponedSelectData;
2118 static gboolean postpone_select(void *data)
2120 PostponedSelectData *psdata = (PostponedSelectData *)data;
2121 debug_print("trying again\n");
2123 psdata->folderview->postpone_select_id = 0;
2124 psdata->folderview->open_folder = TRUE;
2125 main_window_cursor_normal(psdata->folderview->mainwin);
2126 STATUSBAR_POP(psdata->folderview->mainwin);
2127 folderview_selected(psdata->ctree, psdata->row,
2128 psdata->column, psdata->folderview);
2129 g_free(psdata);
2130 return FALSE;
2133 void folderview_close_opened(FolderView *folderview, gboolean dirty)
2135 if (folderview->opened) {
2136 if (dirty) {
2137 folderview->opened = NULL;
2138 return;
2141 FolderItem *olditem =
2142 gtk_cmctree_node_get_row_data(GTK_CMCTREE(folderview->ctree),
2143 folderview->opened);
2144 if (olditem) {
2145 gchar *buf = g_strdup_printf(_("Closing folder %s..."),
2146 olditem->path ? olditem->path:olditem->name);
2147 /* will be null if we just moved the previously opened folder */
2148 STATUSBAR_PUSH(folderview->mainwin, buf);
2149 main_window_cursor_wait(folderview->mainwin);
2150 g_free(buf);
2151 summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
2152 summary_show(folderview->summaryview, NULL);
2153 folder_item_close(olditem);
2154 main_window_cursor_normal(folderview->mainwin);
2155 STATUSBAR_POP(folderview->mainwin);
2156 if (olditem->folder->klass->item_closed)
2157 olditem->folder->klass->item_closed(olditem);
2162 if (folderview->opened &&
2163 !GTK_CMCTREE_ROW(folderview->opened)->children)
2164 gtk_cmctree_collapse(GTK_CMCTREE(folderview->ctree), folderview->opened);
2166 folderview->opened = NULL;
2168 static void folderview_selected(GtkCMCTree *ctree, GtkCMCTreeNode *row,
2169 gint column, FolderView *folderview)
2171 static gboolean can_select = TRUE; /* exclusive lock */
2172 gboolean opened;
2173 FolderItem *item;
2174 gchar *buf;
2175 int res = 0;
2176 GtkCMCTreeNode *old_opened = folderview->opened;
2177 START_TIMING("");
2178 folderview->selected = row;
2180 debug_print("newly selected %p, opened %p\n", folderview->selected,
2181 folderview->opened);
2182 if (folderview->opened == row) {
2183 folderview->open_folder = FALSE;
2184 END_TIMING();
2185 return;
2188 item = gtk_cmctree_node_get_row_data(ctree, row);
2189 if (!item) {
2190 END_TIMING();
2191 folderview->open_folder = FALSE;
2192 return;
2195 if (!can_select || summary_is_locked(folderview->summaryview)) {
2196 if (folderview->opened) {
2197 gtkut_ctree_set_focus_row(ctree, folderview->opened);
2198 gtk_cmctree_select(ctree, folderview->opened);
2200 folderview->open_folder = FALSE;
2201 END_TIMING();
2202 return;
2205 if (!folderview->open_folder) {
2206 END_TIMING();
2207 return;
2210 can_select = FALSE;
2212 /* Save cache for old folder */
2213 /* We don't want to lose all caches if sylpheed crashed */
2214 /* resets folderview->opened to NULL */
2215 folderview_close_opened(folderview, FALSE);
2217 /* CLAWS: set compose button type: news folder items
2218 * always have a news folder as parent */
2219 if (item->folder)
2220 toolbar_set_compose_button
2221 (folderview->mainwin->toolbar,
2222 FOLDER_TYPE(item->folder) == F_NEWS ?
2223 COMPOSEBUTTON_NEWS : COMPOSEBUTTON_MAIL);
2225 if (item->path)
2226 debug_print("Folder %s is selected\n", item->path);
2228 if (!GTK_CMCTREE_ROW(row)->children)
2229 gtk_cmctree_expand(ctree, row);
2231 /* ungrab the mouse event */
2232 if (gtk_widget_has_grab(GTK_WIDGET(ctree))) {
2233 gtk_grab_remove(GTK_WIDGET(ctree));
2234 if (gdk_pointer_is_grabbed())
2235 gdk_pointer_ungrab(GDK_CURRENT_TIME);
2238 /* Open Folder */
2239 /* TODO: wwp: avoid displaying (null) in the status bar */
2240 buf = g_strdup_printf(_("Opening folder %s..."), item->path ?
2241 item->path : "(null)");
2242 debug_print("%s\n", buf);
2243 STATUSBAR_PUSH(folderview->mainwin, buf);
2244 g_free(buf);
2246 main_window_cursor_wait(folderview->mainwin);
2248 if (folderview->scanning_folder == item->folder) {
2249 res = -2;
2250 } else {
2251 res = folder_item_open(item);
2254 if (res == -1 && item->no_select == FALSE) {
2255 main_window_cursor_normal(folderview->mainwin);
2256 STATUSBAR_POP(folderview->mainwin);
2258 alertpanel_error(_("Folder could not be opened."));
2260 folderview->open_folder = FALSE;
2261 can_select = TRUE;
2262 END_TIMING();
2263 return;
2264 } else if (res == -2 && item->no_select == FALSE) {
2265 PostponedSelectData *data = g_new0(PostponedSelectData, 1);
2266 data->ctree = ctree;
2267 data->row = row;
2268 data->column = column;
2269 data->folderview = folderview;
2270 debug_print("postponing open of %s till end of scan\n",
2271 item->path ? item->path:item->name);
2272 folderview->open_folder = FALSE;
2273 can_select = TRUE;
2274 if (folderview->postpone_select_id != 0)
2275 g_source_remove(folderview->postpone_select_id);
2276 folderview->postpone_select_id = g_timeout_add(500, postpone_select, data);
2277 END_TIMING();
2278 return;
2281 main_window_cursor_normal(folderview->mainwin);
2283 /* Show messages */
2284 summary_set_prefs_from_folderitem(folderview->summaryview, item);
2285 opened = summary_show(folderview->summaryview, item);
2287 folder_clean_cache_memory(item);
2289 if (!opened) {
2290 gtkut_ctree_set_focus_row(ctree, old_opened);
2291 gtk_cmctree_select(ctree, old_opened);
2292 folderview->opened = old_opened;
2293 } else {
2294 folderview->opened = row;
2295 if (gtk_cmctree_node_is_visible(ctree, row)
2296 != GTK_VISIBILITY_FULL)
2297 gtk_cmctree_node_moveto(ctree, row, -1, 0.5, 0);
2300 STATUSBAR_POP(folderview->mainwin);
2302 folderview->open_folder = FALSE;
2303 can_select = TRUE;
2304 END_TIMING();
2307 static void folderview_tree_expanded(GtkCMCTree *ctree, GtkCMCTreeNode *node,
2308 FolderView *folderview)
2310 FolderItem *item;
2312 item = gtk_cmctree_node_get_row_data(ctree, node);
2313 cm_return_if_fail(item != NULL);
2314 item->collapsed = FALSE;
2315 folderview_update_node(folderview, node);
2318 static void folderview_tree_collapsed(GtkCMCTree *ctree, GtkCMCTreeNode *node,
2319 FolderView *folderview)
2321 FolderItem *item;
2323 item = gtk_cmctree_node_get_row_data(ctree, node);
2324 cm_return_if_fail(item != NULL);
2325 item->collapsed = TRUE;
2326 folderview_update_node(folderview, node);
2329 static void folderview_popup_close(GtkMenuShell *menu_shell,
2330 FolderView *folderview)
2332 if (!folderview->opened) return;
2334 gtk_cmctree_select(GTK_CMCTREE(folderview->ctree), folderview->opened);
2337 static void folderview_col_resized(GtkCMCList *clist, gint column, gint width,
2338 FolderView *folderview)
2340 FolderColumnType type = folderview->col_state[column].type;
2342 prefs_common.folder_col_size[type] = width;
2345 static void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
2347 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
2348 gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
2349 GtkCMCTreeNode *node, *parent_node;
2350 gint *col_pos = folderview->col_pos;
2351 FolderItemUpdateData hookdata;
2353 parent_node = gtk_cmctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
2354 if (parent_node == NULL)
2355 return;
2357 gtk_cmclist_freeze(GTK_CMCLIST(ctree));
2359 text[col_pos[F_COL_FOLDER]] = item->name;
2360 node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
2361 FOLDER_SPACING,
2362 folderxpm,
2363 folderopenxpm,
2364 FALSE, FALSE);
2365 gtk_cmctree_expand(ctree, parent_node);
2366 gtk_cmctree_node_set_row_data(ctree, node, item);
2367 if (normal_style)
2368 gtk_cmctree_node_set_row_style(ctree, node, normal_style);
2369 folderview_sort_folders(folderview, parent_node, item->folder);
2371 hookdata.item = item;
2372 hookdata.update_flags = F_ITEM_UPDATE_NAME;
2373 hookdata.msg = NULL;
2374 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
2376 gtk_cmclist_thaw(GTK_CMCLIST(ctree));
2379 static void folderview_empty_trash_cb(GtkAction *action, gpointer data)
2381 FolderView *folderview = (FolderView *)data;
2382 FolderItem *item;
2383 GSList *mlist = NULL;
2384 GSList *cur = NULL;
2385 FolderItem *special_trash = NULL;
2386 PrefsAccount *ac;
2388 if (!folderview->selected) return;
2389 item = folderview_get_selected_item(folderview);
2390 cm_return_if_fail(item != NULL);
2391 cm_return_if_fail(item->folder != NULL);
2393 if (NULL != (ac = account_find_from_item(item)))
2394 special_trash = account_get_special_folder(ac, F_TRASH);
2396 if (item != item->folder->trash && item != special_trash
2397 && !folder_has_parent_of_type(item, F_TRASH)) return;
2399 if (prefs_common.ask_on_clean) {
2400 if (alertpanel(_("Empty trash"),
2401 _("Delete all messages in trash?"),
2402 GTK_STOCK_CANCEL, g_strconcat("+", _("_Empty trash"), NULL), NULL) != G_ALERTALTERNATE)
2403 return;
2406 mlist = folder_item_get_msg_list(item);
2408 for (cur = mlist ; cur != NULL ; cur = cur->next) {
2409 MsgInfo * msginfo = (MsgInfo *) cur->data;
2410 if (MSG_IS_LOCKED(msginfo->flags))
2411 continue;
2412 /* is it partially received? (partial_recv isn't cached) */
2413 if (msginfo->total_size != 0 &&
2414 msginfo->size != (off_t)msginfo->total_size)
2415 partial_mark_for_delete(msginfo);
2417 procmsg_msg_list_free(mlist);
2419 folder_item_remove_all_msg(item);
2422 static void folderview_send_queue_cb(GtkAction *action, gpointer data)
2424 FolderView *folderview = (FolderView *)data;
2425 FolderItem *item;
2426 FolderItem *special_queue = NULL;
2427 PrefsAccount *ac;
2428 gchar *errstr = NULL;
2430 if (!folderview->selected) return;
2431 item = folderview_get_selected_item(folderview);
2432 cm_return_if_fail(item != NULL);
2433 cm_return_if_fail(item->folder != NULL);
2435 if (NULL != (ac = account_find_from_item(item)))
2436 special_queue = account_get_special_folder(ac, F_QUEUE);
2438 if (item != item->folder->queue && item != special_queue
2439 && !folder_has_parent_of_type(item, F_QUEUE)) return;
2441 if (procmsg_queue_is_empty(item))
2442 return;
2444 if (prefs_common.work_offline)
2445 if (alertpanel(_("Offline warning"),
2446 _("You're working offline. Override?"),
2447 GTK_STOCK_NO, GTK_STOCK_YES,
2448 NULL) != G_ALERTALTERNATE)
2449 return;
2451 /* ask for confirmation before sending queued messages only
2452 in online mode and if there is at least one message queued
2453 in any of the folder queue
2455 if (prefs_common.confirm_send_queued_messages) {
2456 if (!prefs_common.work_offline) {
2457 if (alertpanel(_("Send queued messages"),
2458 _("Send all queued messages?"),
2459 GTK_STOCK_CANCEL, _("_Send"),
2460 NULL) != G_ALERTALTERNATE)
2461 return;
2465 if (procmsg_send_queue(item, prefs_common.savemsg, &errstr) < 0) {
2466 if (!errstr)
2467 alertpanel_error_log(_("Some errors occurred while "
2468 "sending queued messages."));
2469 else {
2470 alertpanel_error_log(_("Some errors occurred "
2471 "while sending queued messages:\n%s"), errstr);
2472 g_free(errstr);
2477 static void folderview_search_cb(GtkAction *action, gpointer data)
2479 FolderView *folderview = (FolderView *)data;
2480 summary_search(folderview->summaryview);
2483 static void folderview_run_processing_cb(GtkAction *action, gpointer data)
2485 FolderView *folderview = (FolderView *)data;
2486 FolderItem *item;
2488 if (!folderview->selected) return;
2490 item = folderview_get_selected_item(folderview);
2491 cm_return_if_fail(item != NULL);
2492 cm_return_if_fail(item->folder != NULL);
2494 item->processing_pending = TRUE;
2495 folder_item_apply_processing(item);
2496 item->processing_pending = FALSE;
2499 static void folderview_property_cb(GtkAction *action, gpointer data)
2501 FolderView *folderview = (FolderView *)data;
2502 FolderItem *item;
2504 if (!folderview->selected) return;
2506 item = folderview_get_selected_item(folderview);
2507 cm_return_if_fail(item != NULL);
2508 cm_return_if_fail(item->folder != NULL);
2510 prefs_folder_item_open(item);
2513 static void folderview_recollapse_nodes(FolderView *folderview, GtkCMCTreeNode *node)
2515 GSList *list = NULL;
2516 GSList *done = NULL;
2517 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
2519 for (list = folderview->nodes_to_recollapse; list != NULL; list = g_slist_next(list)) {
2520 if (!gtkut_ctree_node_is_parent(GTK_CMCTREE_NODE(list->data), node)
2521 && list->data != node) {
2522 gtk_cmctree_collapse(ctree, GTK_CMCTREE_NODE(list->data));
2523 done = g_slist_append(done, GTK_CMCTREE_NODE(list->data));
2526 for (list = done; list != NULL; list = g_slist_next(list)) {
2527 folderview->nodes_to_recollapse = g_slist_remove(folderview->nodes_to_recollapse,
2528 list->data);
2530 g_slist_free(done);
2533 void folderview_move_folder(FolderView *folderview, FolderItem *from_folder,
2534 FolderItem *to_folder, gboolean copy)
2536 FolderItem *new_folder = NULL;
2537 gchar *buf;
2538 gint status;
2540 cm_return_if_fail(folderview != NULL);
2541 cm_return_if_fail(from_folder != NULL);
2542 cm_return_if_fail(to_folder != NULL);
2544 if (prefs_common.warn_dnd) {
2545 buf = g_strdup_printf(copy ? _("Do you really want to copy folder '%s' in '%s'?"):
2546 _("Do you really want to make folder '%s' a subfolder of '%s'?"),
2547 from_folder->name, to_folder->name);
2548 status = alertpanel_full(copy ? _("Copy folder"):_("Move folder"), buf,
2549 GTK_STOCK_NO, GTK_STOCK_YES, NULL, TRUE,
2550 NULL, ALERT_QUESTION, G_ALERTDEFAULT);
2551 g_free(buf);
2553 if ((status & ~G_ALERTDISABLE) != G_ALERTALTERNATE)
2554 return;
2555 else if (status & G_ALERTDISABLE)
2556 prefs_common.warn_dnd = FALSE;
2559 buf = g_strdup_printf(copy ? _("Copying %s to %s..."):_("Moving %s to %s..."),
2560 from_folder->name, to_folder->name);
2561 STATUSBAR_PUSH(folderview->mainwin, buf);
2562 g_free(buf);
2563 summary_clear_all(folderview->summaryview);
2564 folderview->opened = NULL;
2565 folderview->selected = NULL;
2566 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), FALSE);
2567 inc_lock();
2568 main_window_cursor_wait(folderview->mainwin);
2570 statusbar_verbosity_set(FALSE);
2571 folder_item_update_freeze();
2572 gtk_cmclist_freeze(GTK_CMCLIST(folderview->ctree));
2573 if ((status = folder_item_move_to(from_folder, to_folder, &new_folder, copy)) == F_MOVE_OK) {
2574 statusbar_verbosity_set(FALSE);
2575 main_window_cursor_normal(folderview->mainwin);
2576 STATUSBAR_POP(folderview->mainwin);
2577 folder_item_update_thaw();
2578 folder_item_update_recursive(new_folder, F_ITEM_UPDATE_MSGCNT);
2580 folderview_sort_folders(folderview,
2581 gtk_cmctree_find_by_row_data(GTK_CMCTREE(folderview->ctree),
2582 NULL, to_folder), new_folder->folder);
2583 folderview_select(folderview, new_folder);
2584 gtk_cmclist_thaw(GTK_CMCLIST(folderview->ctree));
2585 } else {
2586 statusbar_verbosity_set(FALSE);
2587 main_window_cursor_normal(folderview->mainwin);
2588 STATUSBAR_POP(folderview->mainwin);
2589 gtk_cmclist_thaw(GTK_CMCLIST(folderview->ctree));
2590 folder_item_update_thaw();
2591 switch (status) {
2592 case F_MOVE_FAILED_DEST_IS_PARENT:
2593 alertpanel_error(_("Source and destination are the same."));
2594 break;
2595 case F_MOVE_FAILED_DEST_IS_CHILD:
2596 alertpanel_error(copy ? _("Can't copy a folder to one of its children."):
2597 _("Can't move a folder to one of its children."));
2598 break;
2599 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX:
2600 alertpanel_error(_("A folder cannot be moved between different mailboxes."));
2601 break;
2602 default:
2603 alertpanel_error(copy ? _("Copy failed!"):_("Move failed!"));
2604 break;
2607 inc_unlock();
2608 gtk_widget_set_sensitive(GTK_WIDGET(folderview->ctree), TRUE);
2611 static gint folderview_clist_compare(GtkCMCList *clist,
2612 gconstpointer ptr1, gconstpointer ptr2)
2614 FolderItem *item1 = ((GtkCMCListRow *)ptr1)->data;
2615 FolderItem *item2 = ((GtkCMCListRow *)ptr2)->data;
2617 if (item1->order > 0 && item2->order > 0) // if we have an order item, use it
2619 return item1->order - item2->order;
2622 // if only one folder has an order it comes first
2623 if (item1->order > 0)
2625 return -1;
2627 if (item2->order > 0)
2629 return 1;
2632 if (!item1->name)
2633 return (item2->name != NULL);
2634 if (!item2->name)
2635 return -1;
2637 return g_utf8_collate(item1->name, item2->name);
2640 static void folderview_processing_cb(GtkAction *action, gpointer data)
2642 FolderView *folderview = (FolderView *)data;
2643 FolderItem *item;
2644 gchar *id, *title;
2646 if (!folderview->selected) return;
2648 item = folderview_get_selected_item(folderview);
2649 cm_return_if_fail(item != NULL);
2650 cm_return_if_fail(item->folder != NULL);
2652 id = folder_item_get_identifier(item);
2653 title = g_strdup_printf (_("Processing configuration for folder %s"), id);
2654 g_free (id);
2656 prefs_filtering_open(&item->prefs->processing, title,
2657 MANUAL_ANCHOR_PROCESSING, NULL, NULL, FALSE);
2658 g_free (title);
2661 void folderview_set_target_folder_color(gint color_op)
2663 gint firstone = 1;
2664 GList *list;
2665 FolderView *folderview;
2667 for (list = folderview_list; list != NULL; list = list->next) {
2668 folderview = (FolderView *)list->data;
2669 gtkut_convert_int_to_gdk_color(color_op, &folderview->color_op);
2670 if (firstone) {
2671 bold_tgtfold_style->fg[GTK_STATE_NORMAL] =
2672 folderview->color_op;
2673 firstone = 0;
2678 static gchar *last_smallfont = NULL;
2679 static gchar *last_normalfont = NULL;
2680 static gchar *last_boldfont = NULL;
2681 static gboolean last_derive = 0;
2683 void folderview_reinit_fonts(FolderView *folderview)
2685 /* force reinit */
2686 g_free(last_smallfont);
2687 last_smallfont = NULL;
2688 g_free(last_normalfont);
2689 last_normalfont = NULL;
2690 g_free(last_boldfont);
2691 last_boldfont = NULL;
2694 void folderview_reflect_prefs(void)
2696 gboolean update_font = FALSE;
2697 FolderView *folderview = mainwindow_get_mainwindow()->folderview;
2698 FolderItem *item = folderview_get_selected_item(folderview);
2699 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2700 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2701 gint height = gtk_adjustment_get_value(pos);
2703 if (!last_smallfont || strcmp(last_smallfont, SMALL_FONT) ||
2704 !last_normalfont || strcmp(last_normalfont, NORMAL_FONT) ||
2705 !last_boldfont || strcmp(last_boldfont, BOLD_FONT) ||
2706 last_derive != prefs_common.derive_from_normal_font)
2707 update_font = TRUE;
2709 if (!update_font)
2710 return;
2712 g_free(last_smallfont);
2713 last_smallfont = g_strdup(SMALL_FONT);
2714 g_free(last_normalfont);
2715 last_normalfont = g_strdup(NORMAL_FONT);
2716 g_free(last_boldfont);
2717 last_boldfont = g_strdup(BOLD_FONT);
2718 last_derive = prefs_common.derive_from_normal_font;
2720 normal_style = normal_color_style = bold_style =
2721 bold_color_style = bold_tgtfold_style = NULL;
2723 folderview_init(folderview);
2724 gtk_cmclist_freeze(GTK_CMCLIST(folderview->ctree));
2725 folderview_column_set_titles(folderview);
2726 folderview_set_all();
2728 g_signal_handlers_block_by_func
2729 (G_OBJECT(folderview->ctree),
2730 G_CALLBACK(folderview_selected), folderview);
2732 if (item) {
2733 GtkCMCTreeNode *node = gtk_cmctree_find_by_row_data(
2734 GTK_CMCTREE(folderview->ctree), NULL, item);
2736 folderview_select(folderview, item);
2737 folderview->open_folder = FALSE;
2738 folderview->selected = node;
2741 g_signal_handlers_unblock_by_func
2742 (G_OBJECT(folderview->ctree),
2743 G_CALLBACK(folderview_selected), folderview);
2745 pos = gtk_scrolled_window_get_vadjustment(
2746 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2747 gtk_adjustment_set_value(pos, height);
2748 gtk_adjustment_changed(pos);
2749 gtk_cmclist_thaw(GTK_CMCLIST(folderview->ctree));
2752 static void drag_state_stop(FolderView *folderview)
2754 if (folderview->drag_timer_id)
2755 g_source_remove(folderview->drag_timer_id);
2756 folderview->drag_timer_id = 0;
2757 folderview->drag_node = NULL;
2760 static gboolean folderview_defer_expand(FolderView *folderview)
2762 if (folderview->drag_node) {
2763 folderview_recollapse_nodes(folderview, folderview->drag_node);
2764 if (folderview->drag_item->collapsed) {
2765 gtk_cmctree_expand(GTK_CMCTREE(folderview->ctree), folderview->drag_node);
2766 folderview->nodes_to_recollapse = g_slist_append
2767 (folderview->nodes_to_recollapse, folderview->drag_node);
2770 folderview->drag_item = NULL;
2771 folderview->drag_timer_id = 0;
2772 return FALSE;
2775 static void drag_state_start(FolderView *folderview, GtkCMCTreeNode *node, FolderItem *item)
2777 /* the idea is that we call drag_state_start() whenever we want expansion to
2778 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2779 * we need to call drag_state_stop() */
2780 drag_state_stop(folderview);
2781 /* request expansion */
2782 if (0 != (folderview->drag_timer_id = g_timeout_add
2783 (prefs_common.hover_timeout,
2784 (GSourceFunc)folderview_defer_expand,
2785 folderview))) {
2786 folderview->drag_node = node;
2787 folderview->drag_item = item;
2790 #ifndef GENERIC_UMPC
2791 static void folderview_start_drag(GtkWidget *widget, gint button, GdkEvent *event,
2792 FolderView *folderview)
2794 GdkDragContext *context;
2796 cm_return_if_fail(folderview != NULL);
2797 if (folderview->selected == NULL) return;
2798 if (folderview->nodes_to_recollapse)
2799 g_slist_free(folderview->nodes_to_recollapse);
2800 folderview->nodes_to_recollapse = NULL;
2801 context = gtk_drag_begin(widget, folderview->target_list,
2802 GDK_ACTION_MOVE|GDK_ACTION_COPY|GDK_ACTION_DEFAULT, button, event);
2803 gtk_drag_set_icon_default(context);
2805 #endif
2806 static void folderview_drag_data_get(GtkWidget *widget,
2807 GdkDragContext *drag_context,
2808 GtkSelectionData *selection_data,
2809 guint info,
2810 guint time,
2811 FolderView *folderview)
2813 FolderItem *item;
2814 GList *sel;
2815 gchar *source = NULL;
2816 if (info == TARGET_DUMMY) {
2817 sel = GTK_CMCLIST(folderview->ctree)->selection;
2818 if (!sel)
2819 return;
2821 item = gtk_cmctree_node_get_row_data
2822 (GTK_CMCTREE(folderview->ctree),
2823 GTK_CMCTREE_NODE(sel->data));
2824 if (item) {
2825 source = g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item));
2826 gtk_selection_data_set(selection_data,
2827 gtk_selection_data_get_target(selection_data), 8,
2828 source, strlen(source));
2830 } else {
2831 g_warning("unknown info %d", info);
2835 static gboolean folderview_update_folder(gpointer source, gpointer userdata)
2837 FolderUpdateData *hookdata;
2838 FolderView *folderview;
2839 GtkWidget *ctree;
2841 hookdata = source;
2842 folderview = (FolderView *) userdata;
2843 cm_return_val_if_fail(hookdata != NULL, FALSE);
2844 cm_return_val_if_fail(folderview != NULL, FALSE);
2846 ctree = folderview->ctree;
2847 cm_return_val_if_fail(ctree != NULL, FALSE);
2849 if (hookdata->update_flags & FOLDER_ADD_FOLDERITEM)
2850 folderview_create_folder_node(folderview, hookdata->item);
2851 else if (hookdata->update_flags & FOLDER_RENAME_FOLDERITEM) {
2852 GtkCMCTreeNode *node = gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree),
2853 NULL, folder_item_parent(hookdata->item));
2854 folderview_sort_folders(folderview, node, hookdata->folder);
2855 } else if (hookdata->update_flags & FOLDER_REMOVE_FOLDERITEM) {
2856 GtkCMCTreeNode *node;
2858 node = gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree), NULL, hookdata->item);
2859 if (node != NULL) {
2860 gtk_cmctree_remove_node(GTK_CMCTREE(ctree), node);
2861 if (folderview->selected == node)
2862 folderview->selected = NULL;
2863 if (folderview->opened == node)
2864 folderview->opened = NULL;
2866 } else if (hookdata->update_flags & FOLDER_MOVE_FOLDERITEM) {
2867 /* do nothing, it's done by the ADD and REMOVE) */
2868 } else if (hookdata->update_flags & (FOLDER_TREE_CHANGED | FOLDER_ADD_FOLDER | FOLDER_REMOVE_FOLDER))
2869 folderview_set(folderview);
2871 return FALSE;
2874 static gboolean folderview_dnd_scroll_cb(gpointer data)
2876 FolderView *folderview = (FolderView *)data;
2877 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2878 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2879 gint new_val = (int)gtk_adjustment_get_value(pos) + folderview->scroll_value;
2880 gint max = (int)gtk_adjustment_get_upper(pos) -
2881 (int)gtk_adjustment_get_page_size(pos);
2883 if (folderview->scroll_value == 0) {
2884 folderview->scroll_timeout_id = 0;
2885 return FALSE;
2888 if (folderview->scroll_value > 0 && new_val > max) {
2889 new_val = max;
2890 } else if (folderview->scroll_value < 0 && new_val < 0) {
2891 new_val = 0;
2893 gtk_adjustment_set_value(pos, new_val);
2895 return TRUE;
2898 static gboolean folderview_drag_motion_cb(GtkWidget *widget,
2899 GdkDragContext *context,
2900 gint x,
2901 gint y,
2902 guint time,
2903 FolderView *folderview)
2905 gint row, column;
2906 FolderItem *item = NULL, *src_item = NULL;
2907 GtkCMCTreeNode *node = NULL;
2908 gboolean acceptable = FALSE;
2909 GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
2910 GTK_SCROLLED_WINDOW(folderview->scrolledwin));
2911 int height = (int)gtk_adjustment_get_page_size(pos);
2912 int total_height = (int)gtk_adjustment_get_upper(pos);
2913 int vpos = (int)gtk_adjustment_get_value(pos);
2914 int offset = prefs_common.show_col_headers ? 24:0;
2915 int dist;
2917 if (gtk_cmclist_get_selection_info
2918 (GTK_CMCLIST(widget), x - offset, y - offset, &row, &column)) {
2919 GtkWidget *srcwidget;
2921 if (y > height - (48 - offset) && height + vpos < total_height) {
2922 dist = -(height - (48 - offset) - y);
2923 folderview->scroll_value = 1.41f * (1+(dist / 6));
2924 } else if (y < 72 - (24 - offset) && y >= 0) {
2925 dist = 72 - (24 - offset) - y;
2926 folderview->scroll_value = -1.41f * (1+(dist / 6));
2927 } else {
2928 folderview->scroll_value = 0;
2930 if (folderview->scroll_value != 0 && folderview->scroll_timeout_id == 0) {
2931 folderview->scroll_timeout_id =
2932 g_timeout_add(30, folderview_dnd_scroll_cb,
2933 folderview);
2936 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
2937 item = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node);
2938 src_item = folderview->summaryview->folder_item;
2940 srcwidget = gtk_drag_get_source_widget(context);
2941 if (srcwidget == summary_get_main_widget(folderview->summaryview)) {
2942 /* comes from summaryview */
2943 /* we are copying messages, so only accept folder items that are not
2944 the source item, are no root items and can copy messages */
2945 if (item && item->folder && folder_item_parent(item) != NULL && src_item &&
2946 src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2947 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2948 acceptable = TRUE;
2949 } else if (srcwidget == folderview->ctree) {
2950 /* comes from folderview */
2951 /* we are moving folder items, only accept folders that are not
2952 the source items and can copy messages and create folder items */
2953 if (item && item->folder && src_item && src_item != item &&
2954 FOLDER_CLASS(item->folder)->copy_msg != NULL &&
2955 FOLDER_CLASS(item->folder)->create_folder != NULL &&
2956 ((FOLDER_TYPE(item->folder) != F_UNKNOWN && FOLDER_TYPE(src_item->folder) != F_UNKNOWN)
2957 || item->folder == src_item->folder))
2958 acceptable = TRUE;
2959 } else {
2960 /* comes from another app */
2961 /* we are adding messages, so only accept folder items that are
2962 no root items and can copy messages */
2963 if (item && item->folder && folder_item_parent(item) != NULL
2964 && FOLDER_CLASS(item->folder)->add_msg != NULL &&
2965 FOLDER_TYPE(item->folder) != F_UNKNOWN)
2966 acceptable = TRUE;
2970 if (acceptable || (src_item && src_item == item))
2971 drag_state_start(folderview, node, item);
2973 if (acceptable) {
2974 g_signal_handlers_block_by_func
2975 (G_OBJECT(widget),
2976 G_CALLBACK(folderview_selected), folderview);
2977 gtk_cmctree_select(GTK_CMCTREE(widget), node);
2978 g_signal_handlers_unblock_by_func
2979 (G_OBJECT(widget),
2980 G_CALLBACK(folderview_selected), folderview);
2981 gdk_drag_status(context,
2982 (gdk_drag_context_get_actions(context) == GDK_ACTION_COPY ?
2983 GDK_ACTION_COPY : GDK_ACTION_MOVE) , time);
2984 } else {
2985 if (folderview->opened)
2986 gtk_cmctree_select(GTK_CMCTREE(widget), folderview->opened);
2987 gdk_drag_status(context, 0, time);
2990 return acceptable;
2993 static void folderview_drag_leave_cb(GtkWidget *widget,
2994 GdkDragContext *context,
2995 guint time,
2996 FolderView *folderview)
2998 drag_state_stop(folderview);
2999 folderview->scroll_value = 0;
3000 gtk_cmctree_select(GTK_CMCTREE(widget), folderview->opened);
3003 static void free_info (gpointer stuff, gpointer data)
3005 g_free(stuff);
3008 void folderview_finish_dnd(const gchar *data, GdkDragContext *drag_context,
3009 guint time, FolderItem *item)
3011 GList *list, *tmp;
3012 GSList *msglist = NULL;
3013 list = uri_list_extract_filenames(data);
3014 if (!(item && item->folder && folder_item_parent(item) != NULL
3015 && FOLDER_CLASS(item->folder)->add_msg != NULL))
3017 gtk_drag_finish(drag_context, FALSE, FALSE, time);
3018 debug_print("item doesn't fit\n");
3019 return;
3021 if (!list) {
3022 gtk_drag_finish(drag_context, FALSE, FALSE, time);
3023 debug_print("list is empty\n");
3024 return;
3026 for (tmp = list; tmp != NULL; tmp = tmp->next) {
3027 MsgFileInfo *info = NULL;
3029 if (file_is_email((gchar *)tmp->data)) {
3030 info = g_new0(MsgFileInfo, 1);
3031 info->msginfo = NULL;
3032 info->file = (gchar *)tmp->data;
3033 msglist = g_slist_prepend(msglist, info);
3034 debug_print("file is a mail\n");
3035 } else {
3036 debug_print("file isn't a mail\n");
3039 if (msglist) {
3040 msglist = g_slist_reverse(msglist);
3041 folder_item_add_msgs(item, msglist, FALSE);
3042 g_slist_foreach(msglist, free_info, NULL);
3043 g_slist_free(msglist);
3044 gtk_drag_finish(drag_context, TRUE, FALSE, time);
3045 } else {
3046 gtk_drag_finish(drag_context, FALSE, FALSE, time);
3048 list_free_strings(list);
3049 g_list_free(list);
3052 static void folderview_drag_received_cb(GtkWidget *widget,
3053 GdkDragContext *drag_context,
3054 gint x,
3055 gint y,
3056 GtkSelectionData *data,
3057 guint info,
3058 guint time,
3059 FolderView *folderview)
3061 gint row, column;
3062 FolderItem *item = NULL, *src_item;
3063 GtkCMCTreeNode *node;
3064 int offset = prefs_common.show_col_headers ? 24:0;
3066 folderview->scroll_value = 0;
3068 if (info == TARGET_DUMMY) {
3069 drag_state_stop(folderview);
3070 const gchar *ddata = (const gchar *)gtk_selection_data_get_data(data);
3071 if ((gchar *)strstr(ddata, "FROM_OTHER_FOLDER") != ddata) {
3072 /* comes from summaryview */
3073 if (gtk_cmclist_get_selection_info
3074 (GTK_CMCLIST(widget), x - offset, y - offset, &row, &column) == 0)
3075 return;
3077 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
3078 item = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node);
3079 src_item = folderview->summaryview->folder_item;
3081 if (item->no_select) {
3082 alertpanel_error(_("The destination folder can only be used to "
3083 "store subfolders."));
3084 return;
3086 /* re-check (due to acceptable possibly set for folder moves */
3087 if (!(item && item->folder && item->path && !item->no_select &&
3088 src_item && src_item != item && FOLDER_CLASS(item->folder)->copy_msg != NULL)) {
3089 return;
3091 if (item && src_item) {
3092 switch (gdk_drag_context_get_selected_action(drag_context)) {
3093 case GDK_ACTION_COPY:
3094 summary_copy_selected_to(folderview->summaryview, item);
3095 gtk_drag_finish(drag_context, TRUE, FALSE, time);
3096 break;
3097 case GDK_ACTION_MOVE:
3098 case GDK_ACTION_DEFAULT:
3099 default:
3100 if (FOLDER_CLASS(src_item->folder)->remove_msg == NULL)
3101 summary_copy_selected_to(folderview->summaryview, item);
3102 else
3103 summary_move_selected_to(folderview->summaryview, item);
3104 gtk_drag_finish(drag_context, TRUE, TRUE, time);
3106 } else
3107 gtk_drag_finish(drag_context, FALSE, FALSE, time);
3108 } else {
3109 /* comes from folderview */
3110 char *source;
3111 gboolean folder_is_normal = TRUE;
3112 gboolean copy = (GDK_ACTION_COPY ==
3113 gdk_drag_context_get_selected_action(drag_context));
3115 source = (char *)gtk_selection_data_get_data(data) + 17;
3116 if (gtk_cmclist_get_selection_info
3117 (GTK_CMCLIST(widget), x - offset, y - offset, &row, &column) == 0
3118 || *source == 0) {
3119 gtk_drag_finish(drag_context, FALSE, FALSE, time);
3120 return;
3122 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
3123 item = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node);
3124 src_item = folder_find_item_from_identifier(source);
3126 folder_is_normal =
3127 src_item != NULL &&
3128 src_item->stype == F_NORMAL &&
3129 !folder_has_parent_of_type(src_item, F_OUTBOX) &&
3130 !folder_has_parent_of_type(src_item, F_DRAFT) &&
3131 !folder_has_parent_of_type(src_item, F_QUEUE) &&
3132 !folder_has_parent_of_type(src_item, F_TRASH);
3133 if (!item || !src_item || !folder_is_normal) {
3134 gtk_drag_finish(drag_context, FALSE, FALSE, time);
3135 return;
3138 folderview_move_folder(folderview, src_item, item, copy);
3139 gtk_drag_finish(drag_context, TRUE, TRUE, time);
3141 folderview->nodes_to_recollapse = NULL;
3142 } else if (info == TARGET_MAIL_URI_LIST) {
3143 if (gtk_cmclist_get_selection_info
3144 (GTK_CMCLIST(widget), x - offset, y - offset, &row, &column) == 0)
3145 return;
3147 node = gtk_cmctree_node_nth(GTK_CMCTREE(widget), row);
3148 if (!node) {
3149 gtk_drag_finish(drag_context, FALSE, FALSE, time);
3150 debug_print("no node\n");
3151 return;
3153 item = gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget), node);
3154 if (!item) {
3155 gtk_drag_finish(drag_context, FALSE, FALSE, time);
3156 debug_print("no item\n");
3157 return;
3159 folderview_finish_dnd(gtk_selection_data_get_data(data),
3160 drag_context, time, item);
3164 static void folderview_drag_end_cb(GtkWidget *widget,
3165 GdkDragContext *drag_context,
3166 FolderView *folderview)
3168 drag_state_stop(folderview);
3169 folderview->scroll_value = 0;
3170 g_slist_free(folderview->nodes_to_recollapse);
3171 folderview->nodes_to_recollapse = NULL;
3174 void folderview_register_popup(FolderViewPopup *fpopup)
3176 GList *folderviews;
3178 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
3179 FolderView *folderview = folderviews->data;
3180 GtkActionGroup *factory;
3182 factory = create_action_group(folderview, fpopup);
3183 g_hash_table_insert(folderview->popups, fpopup->klass, factory);
3185 g_hash_table_insert(folderview_popups, fpopup->klass, fpopup);
3188 void folderview_unregister_popup(FolderViewPopup *fpopup)
3190 GList *folderviews;
3193 for (folderviews = folderview_list; folderviews != NULL; folderviews = g_list_next(folderviews)) {
3194 FolderView *folderview = folderviews->data;
3196 g_hash_table_remove(folderview->popups, fpopup->klass);
3198 g_hash_table_remove(folderview_popups, fpopup->klass);
3201 void folderview_remove_item(FolderView *folderview, FolderItem *item)
3203 g_return_if_fail(folderview != NULL);
3204 g_return_if_fail(item != NULL);
3206 GtkCMCTree *ctree = GTK_CMCTREE(folderview->ctree);
3207 g_return_if_fail(ctree != NULL);
3209 GtkCMCTreeNode *node =
3210 gtk_cmctree_find_by_row_data(ctree, NULL, item);
3211 g_return_if_fail(node != NULL);
3213 gtk_cmctree_remove_node(ctree, node);
3216 void folderview_freeze(FolderView *folderview)
3218 if (folderview)
3219 gtk_cmclist_freeze(GTK_CMCLIST(folderview->ctree));
3222 void folderview_thaw(FolderView *folderview)
3224 if (folderview)
3225 gtk_cmclist_thaw(GTK_CMCLIST(folderview->ctree));
3228 void folderview_grab_focus(FolderView *folderview)
3230 if (folderview)
3231 gtk_widget_grab_focus(folderview->ctree);