2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2022 the Claws Mail team and Hiroyuki Yamamoto
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include <glib/gi18n.h>
24 #include <gdk/gdkkeysyms.h>
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"
39 #include "stock_pixmap.h"
43 #include "prefs_common.h"
44 #include "prefs_account.h"
45 #include "prefs_filtering.h"
46 #include "prefs_folder_item.h"
49 #include "foldersel.h"
51 #include "statusbar.h"
53 #include "folderutils.h"
54 #include "partial_download.h"
55 #include "prefs_folder_column.h"
56 #include "filtering.h"
57 #include "quicksearch.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
*bold_style
;
70 static GdkPixbuf
*inboxxpm
;
71 static GdkPixbuf
*inboxhrmxpm
;
72 static GdkPixbuf
*inboxopenxpm
;
73 static GdkPixbuf
*inboxopenhrmxpm
;
74 static GdkPixbuf
*outboxxpm
;
75 static GdkPixbuf
*outboxhrmxpm
;
76 static GdkPixbuf
*outboxopenxpm
;
77 static GdkPixbuf
*outboxopenhrmxpm
;
78 static GdkPixbuf
*folderxpm
;
79 static GdkPixbuf
*folderhrmxpm
;
80 static GdkPixbuf
*folderopenxpm
;
81 static GdkPixbuf
*folderopenhrmxpm
;
82 static GdkPixbuf
*trashopenxpm
;
83 static GdkPixbuf
*trashopenhrmxpm
;
84 static GdkPixbuf
*trashxpm
;
85 static GdkPixbuf
*trashhrmxpm
;
86 static GdkPixbuf
*queuexpm
;
87 static GdkPixbuf
*queuehrmxpm
;
88 static GdkPixbuf
*queueopenxpm
;
89 static GdkPixbuf
*queueopenhrmxpm
;
90 static GdkPixbuf
*draftsxpm
;
91 static GdkPixbuf
*draftsopenxpm
;
92 static GdkPixbuf
*foldersubsxpm
;
93 static GdkPixbuf
*foldersubsopenxpm
;
94 static GdkPixbuf
*foldernoselectxpm
;
95 static GdkPixbuf
*foldernoselectopenxpm
;
97 static GdkPixbuf
*m_inboxxpm
;
98 static GdkPixbuf
*m_inboxhrmxpm
;
99 static GdkPixbuf
*m_inboxopenxpm
;
100 static GdkPixbuf
*m_inboxopenhrmxpm
;
101 static GdkPixbuf
*m_outboxxpm
;
102 static GdkPixbuf
*m_outboxhrmxpm
;
103 static GdkPixbuf
*m_outboxopenxpm
;
104 static GdkPixbuf
*m_outboxopenhrmxpm
;
105 static GdkPixbuf
*m_folderxpm
;
106 static GdkPixbuf
*m_folderhrmxpm
;
107 static GdkPixbuf
*m_folderopenxpm
;
108 static GdkPixbuf
*m_folderopenhrmxpm
;
109 static GdkPixbuf
*m_trashopenxpm
;
110 static GdkPixbuf
*m_trashopenhrmxpm
;
111 static GdkPixbuf
*m_trashxpm
;
112 static GdkPixbuf
*m_trashhrmxpm
;
113 static GdkPixbuf
*m_queuexpm
;
114 static GdkPixbuf
*m_queuehrmxpm
;
115 static GdkPixbuf
*m_queueopenxpm
;
116 static GdkPixbuf
*m_queueopenhrmxpm
;
117 static GdkPixbuf
*m_draftsxpm
;
118 static GdkPixbuf
*m_draftsopenxpm
;
119 static GdkPixbuf
*m_foldersubsxpm
;
120 static GdkPixbuf
*m_foldernoselectxpm
;
122 static GdkPixbuf
*newxpm
;
123 static GdkPixbuf
*unreadxpm
;
124 static GdkPixbuf
*readxpm
;
126 static void folderview_select_node (FolderView
*folderview
,
127 GtkCMCTreeNode
*node
);
128 static void folderview_set_folders (FolderView
*folderview
);
129 static void folderview_sort_folders (FolderView
*folderview
,
130 GtkCMCTreeNode
*root
,
132 static void folderview_append_folder (FolderView
*folderview
,
134 static void folderview_update_node (FolderView
*folderview
,
135 GtkCMCTreeNode
*node
);
137 static gint
folderview_clist_compare (GtkCMCList
*clist
,
141 /* callback functions */
142 static gboolean
folderview_button_pressed (GtkWidget
*ctree
,
143 GdkEventButton
*event
,
144 FolderView
*folderview
);
145 static gboolean
folderview_button_released (GtkWidget
*ctree
,
146 GdkEventButton
*event
,
147 FolderView
*folderview
);
148 static gboolean
folderview_key_pressed (GtkWidget
*widget
,
150 FolderView
*folderview
);
151 static void folderview_selected (GtkCMCTree
*ctree
,
154 FolderView
*folderview
);
155 static void folderview_tree_expanded (GtkCMCTree
*ctree
,
156 GtkCMCTreeNode
*node
,
157 FolderView
*folderview
);
158 static void folderview_tree_collapsed (GtkCMCTree
*ctree
,
159 GtkCMCTreeNode
*node
,
160 FolderView
*folderview
);
161 static void folderview_popup_close (GtkMenuShell
*menu_shell
,
162 FolderView
*folderview
);
163 static void folderview_col_resized (GtkCMCList
*clist
,
166 FolderView
*folderview
);
168 static void mark_all_read_unread_handler (GtkAction
*action
,
173 static void mark_all_read_cb (GtkAction
*action
,
175 static void mark_all_unread_cb (GtkAction
*action
,
177 static void mark_all_read_recursive_cb (GtkAction
*action
,
179 static void mark_all_unread_recursive_cb (GtkAction
*action
,
182 static void folderview_empty_trash_cb (GtkAction
*action
,
185 static void folderview_send_queue_cb (GtkAction
*action
,
188 static void folderview_search_cb (GtkAction
*action
,
190 static void folderview_run_processing_cb(GtkAction
*action
,
193 static void folderview_property_cb (GtkAction
*action
,
196 static gboolean
folderview_drag_motion_cb(GtkWidget
*widget
,
197 GdkDragContext
*context
,
201 FolderView
*folderview
);
202 static void folderview_drag_leave_cb (GtkWidget
*widget
,
203 GdkDragContext
*context
,
205 FolderView
*folderview
);
206 static void folderview_drag_received_cb (GtkWidget
*widget
,
207 GdkDragContext
*drag_context
,
210 GtkSelectionData
*data
,
213 FolderView
*folderview
);
215 static void folderview_start_drag (GtkWidget
*widget
, gint button
, GdkEvent
*event
,
216 FolderView
*folderview
);
218 static void folderview_drag_data_get (GtkWidget
*widget
,
219 GdkDragContext
*drag_context
,
220 GtkSelectionData
*selection_data
,
223 FolderView
*folderview
);
224 static void folderview_drag_end_cb (GtkWidget
*widget
,
225 GdkDragContext
*drag_context
,
226 FolderView
*folderview
);
228 static void folderview_create_folder_node (FolderView
*folderview
,
230 static gboolean
folderview_update_folder (gpointer source
,
232 static gboolean
folderview_update_item_claws (gpointer source
,
234 static void folderview_processing_cb(GtkAction
*action
, gpointer data
);
235 static void folderview_set_sens_and_popup_menu(FolderView
*folderview
, gint row
,
236 GdkEventButton
*event
);
237 static void folderview_header_set_displayed_columns_cb(GtkAction
*gaction
,
239 static gboolean
folderview_header_button_pressed(GtkWidget
*widget
,
243 GHashTable
*folderview_popups
;
245 static GtkActionEntry folderview_common_popup_entries
[] =
247 {"FolderViewPopup", NULL
, "FolderViewPopup", NULL
, NULL
, NULL
},
248 {"FolderViewPopup/MarkAllRead", NULL
, N_("Mark all re_ad"), NULL
, NULL
, G_CALLBACK(mark_all_read_cb
) },
249 {"FolderViewPopup/MarkAllUnread", NULL
, N_("Mark all u_nread"), NULL
, NULL
, G_CALLBACK(mark_all_unread_cb
) },
250 {"FolderViewPopup/MarkAllReadRec", NULL
, N_("Mark all read recursi_vely"), NULL
, NULL
, G_CALLBACK(mark_all_read_recursive_cb
) },
251 {"FolderViewPopup/MarkAllUnreadRec", NULL
, N_("Mark all unread recursi_vely"), NULL
, NULL
, G_CALLBACK(mark_all_unread_recursive_cb
) },
252 {"FolderViewPopup/---", NULL
, "---", NULL
, NULL
, NULL
},
253 {"FolderViewPopup/RunProcessing", NULL
, N_("R_un processing rules"), NULL
, NULL
, G_CALLBACK(folderview_run_processing_cb
) },
254 {"FolderViewPopup/SearchFolder", NULL
, N_("_Search folder..."), NULL
, NULL
, G_CALLBACK(folderview_search_cb
) },
255 {"FolderViewPopup/Properties", NULL
, N_("_Properties..."), NULL
, NULL
, G_CALLBACK(folderview_property_cb
) },
256 {"FolderViewPopup/Processing", NULL
, N_("Process_ing..."), NULL
, NULL
, G_CALLBACK(folderview_processing_cb
) },
257 {"FolderViewPopup/EmptyTrash", NULL
, N_("Empty _trash..."), NULL
, NULL
, G_CALLBACK(folderview_empty_trash_cb
) },
258 {"FolderViewPopup/SendQueue", NULL
, N_("Send _queue..."), NULL
, NULL
, G_CALLBACK(folderview_send_queue_cb
) },
262 static GtkActionEntry folderview_header_popup_entries
[] =
264 {"FolderViewHeaderPopup", NULL
, "FolderViewHeaderPopup", NULL
, NULL
, NULL
},
265 {"FolderViewHeaderPopup/SetDisplayedColumns", NULL
, N_("Set Displayed columns"), NULL
, NULL
, G_CALLBACK(folderview_header_set_displayed_columns_cb
) }
268 GtkTargetEntry folderview_drag_types
[] =
270 {"claws-mail/internal", GTK_TARGET_SAME_APP
, TARGET_DUMMY
},
271 {"text/uri-list", 0, TARGET_MAIL_URI_LIST
}
274 void folderview_initialize(void)
276 FolderViewPopup
*fpopup
;
278 fpopup
= g_new0(FolderViewPopup
, 1);
280 fpopup
->klass
= "common";
281 fpopup
->path
= "<CommonFolder>";
282 fpopup
->entries
= folderview_common_popup_entries
;
283 fpopup
->n_entries
= G_N_ELEMENTS(folderview_common_popup_entries
);
284 fpopup
->set_sensitivity
= NULL
;
286 folderview_popups
= g_hash_table_new(g_str_hash
, g_str_equal
);
287 g_hash_table_insert(folderview_popups
, "common", fpopup
);
290 static GtkActionGroup
*create_action_group(FolderView
*folderview
, FolderViewPopup
*fpopup
)
292 FolderViewPopup
*fpopup_common
;
293 GtkActionGroup
*action_group
;
295 action_group
= cm_menu_create_action_group(
297 fpopup
->entries
, fpopup
->n_entries
,
298 (gpointer
)folderview
);
300 if (fpopup
->toggle_entries
)
301 gtk_action_group_add_toggle_actions(action_group
, fpopup
->toggle_entries
,
302 fpopup
->n_toggle_entries
,
303 (gpointer
)folderview
);
304 if (fpopup
->radio_entries
)
305 gtk_action_group_add_radio_actions(action_group
, fpopup
->radio_entries
,
306 fpopup
->n_radio_entries
, fpopup
->radio_default
,
307 G_CALLBACK(fpopup
->radio_callback
),
308 (gpointer
)folderview
);
310 fpopup_common
= g_hash_table_lookup(folderview_popups
, "common");
311 if (fpopup_common
!= fpopup
) {
312 gtk_action_group_add_actions(action_group
, fpopup_common
->entries
,
313 fpopup_common
->n_entries
,
314 (gpointer
)folderview
);
315 if (fpopup_common
->toggle_entries
)
316 gtk_action_group_add_toggle_actions(action_group
, fpopup_common
->toggle_entries
,
317 fpopup_common
->n_toggle_entries
,
318 (gpointer
)folderview
);
319 if (fpopup_common
->radio_entries
)
320 gtk_action_group_add_radio_actions(action_group
, fpopup_common
->radio_entries
,
321 fpopup_common
->n_radio_entries
, fpopup_common
->radio_default
,
322 G_CALLBACK(fpopup_common
->radio_callback
),
323 (gpointer
)folderview
);
329 static void create_action_groups(gpointer key
, gpointer value
, gpointer data
)
331 FolderView
*folderview
= data
;
332 FolderViewPopup
*fpopup
= value
;
333 GtkActionGroup
*group
;
335 group
= create_action_group(folderview
, fpopup
);
336 g_hash_table_insert(folderview
->popups
, fpopup
->klass
, group
);
339 static void folderview_column_set_titles(FolderView
*folderview
)
341 GtkWidget
*ctree
= folderview
->ctree
;
342 GtkWidget
*label_folder
;
343 GtkWidget
*label_new
;
344 GtkWidget
*label_unread
;
345 GtkWidget
*label_total
;
346 GtkWidget
*hbox_folder
;
348 GtkWidget
*hbox_unread
;
349 GtkWidget
*hbox_total
;
350 gint
*col_pos
= folderview
->col_pos
;
352 debug_print("setting titles...\n");
353 gtk_widget_realize(folderview
->ctree
);
354 gtk_widget_show_all(folderview
->scrolledwin
);
356 /* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
357 * instead text (text overflows making them unreadable and ugly) */
358 stock_pixbuf_gdk(STOCK_PIXMAP_NEW
, &newxpm
);
359 stock_pixbuf_gdk(STOCK_PIXMAP_UNREAD
, &unreadxpm
);
360 stock_pixbuf_gdk(STOCK_PIXMAP_READ
, &readxpm
);
362 label_folder
= gtk_label_new(_("Folder"));
363 label_new
= gtk_image_new_from_pixbuf(newxpm
);
364 label_unread
= gtk_image_new_from_pixbuf(unreadxpm
);
365 label_total
= gtk_image_new_from_pixbuf(readxpm
);
367 gtk_cmclist_column_titles_active(GTK_CMCLIST(ctree
));
369 hbox_folder
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 4);
370 hbox_new
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 4);
371 hbox_unread
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 4);
372 hbox_total
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 4);
375 gtk_box_pack_start(GTK_BOX(hbox_folder
), label_folder
, TRUE
, TRUE
, 0);
376 gtk_widget_set_halign(label_folder
, GTK_ALIGN_START
);
377 gtk_box_pack_start(GTK_BOX(hbox_new
), label_new
, TRUE
, TRUE
, 0);
378 gtk_widget_set_halign(label_new
, GTK_ALIGN_END
);
379 gtk_box_pack_start(GTK_BOX(hbox_unread
), label_unread
, TRUE
, TRUE
, 0);
380 gtk_widget_set_halign(label_unread
, GTK_ALIGN_END
);
381 gtk_box_pack_start(GTK_BOX(hbox_total
), label_total
, TRUE
, TRUE
, 0);
382 gtk_widget_set_halign(label_total
, GTK_ALIGN_END
);
384 gtk_widget_show_all(hbox_folder
);
385 gtk_widget_show_all(hbox_new
);
386 gtk_widget_show_all(hbox_unread
);
387 gtk_widget_show_all(hbox_total
);
390 gtk_widget_set_size_request(hbox_new
, -1, 20);
391 gtk_widget_set_size_request(hbox_unread
, -1, 20);
392 gtk_widget_set_size_request(hbox_total
, -1, 20);
395 gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree
),col_pos
[F_COL_FOLDER
],hbox_folder
);
396 gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree
),col_pos
[F_COL_NEW
],hbox_new
);
397 gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree
),col_pos
[F_COL_UNREAD
],hbox_unread
);
398 gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree
),col_pos
[F_COL_TOTAL
],hbox_total
);
404 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree
), col_pos
[F_COL_NEW
], _("New"));
405 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree
), col_pos
[F_COL_UNREAD
], _("Unread"));
406 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree
), col_pos
[F_COL_TOTAL
], _("Total"));
409 static gboolean
folderview_popup_menu(GtkWidget
*widget
, gpointer data
)
411 FolderView
*folderview
= (FolderView
*)data
;
412 GdkEventButton event
;
413 if (folderview_get_selected_item(folderview
) == NULL
)
417 event
.time
= gtk_get_current_event_time();
419 folderview_set_sens_and_popup_menu(folderview
, -1,
426 static GtkWidget
*folderview_ctree_create(FolderView
*folderview
)
430 FolderColumnState
*col_state
;
431 FolderColumnType type
;
432 gchar
*titles
[N_FOLDER_COLS
];
434 GtkWidget
*scrolledwin
= folderview
->scrolledwin
;
436 debug_print("creating tree...\n");
437 memset(titles
, 0, sizeof(titles
));
439 col_state
= prefs_folder_column_get_config();
440 memset(titles
, 0, sizeof(titles
));
442 col_pos
= folderview
->col_pos
;
444 for (i
= 0; i
< N_FOLDER_COLS
; i
++) {
445 folderview
->col_state
[i
] = col_state
[i
];
446 type
= col_state
[i
].type
;
450 titles
[col_pos
[F_COL_FOLDER
]] = _("Folder");
451 titles
[col_pos
[F_COL_NEW
]] = _("New");
452 titles
[col_pos
[F_COL_UNREAD
]] = _("Unread");
453 /* TRANSLATORS: This in Number sign in American style */
454 titles
[col_pos
[F_COL_TOTAL
]] = _("#");
456 ctree
= gtk_sctree_new_with_titles(N_FOLDER_COLS
, col_pos
[F_COL_FOLDER
],
459 gtk_widget_set_name(GTK_WIDGET(ctree
), "folderview_sctree");
461 if (prefs_common
.show_col_headers
== FALSE
)
462 gtk_cmclist_column_titles_hide(GTK_CMCLIST(ctree
));
465 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree
), GTK_SELECTION_BROWSE
);
466 gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree
), col_pos
[F_COL_NEW
],
468 gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree
),
469 col_pos
[F_COL_UNREAD
],
471 gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree
),
472 col_pos
[F_COL_TOTAL
],
474 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree
),
475 GTK_CMCTREE_EXPANDER_TRIANGLE
);
477 gtk_sctree_set_stripes(GTK_SCTREE(ctree
), prefs_common
.use_stripes_in_summaries
);
478 gtk_sctree_set_recursive_expand(GTK_SCTREE(ctree
), FALSE
);
480 gtk_cmctree_set_indent(GTK_CMCTREE(ctree
), CTREE_INDENT
);
481 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree
), folderview_clist_compare
);
483 /* don't let title buttons take key focus */
484 for (i
= 0; i
< N_FOLDER_COLS
; i
++) {
485 gtk_widget_set_can_focus(GTK_CMCLIST(ctree
)->column
[i
].button
, FALSE
);
486 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree
), col_pos
[i
],
487 prefs_common
.folder_col_size
[i
]);
488 gtk_cmclist_set_column_visibility
489 (GTK_CMCLIST(ctree
), i
, col_state
[i
].visible
);
491 g_signal_connect(G_OBJECT(GTK_CMCLIST(ctree
)->column
[i
].button
),
492 "button-press-event",
493 G_CALLBACK(folderview_header_button_pressed
),
497 g_signal_connect(G_OBJECT(ctree
), "key_press_event",
498 G_CALLBACK(folderview_key_pressed
),
500 g_signal_connect(G_OBJECT(ctree
), "button_press_event",
501 G_CALLBACK(folderview_button_pressed
),
503 g_signal_connect(G_OBJECT(ctree
), "popup-menu",
504 G_CALLBACK(folderview_popup_menu
), folderview
);
505 g_signal_connect(G_OBJECT(ctree
), "button_release_event",
506 G_CALLBACK(folderview_button_released
),
508 g_signal_connect(G_OBJECT(ctree
), "tree_select_row",
509 G_CALLBACK(folderview_selected
), folderview
);
511 /* drag-n-dropping folders on maemo is impractical as this
512 * opens the folder almost everytime */
513 g_signal_connect(G_OBJECT(ctree
), "start_drag",
514 G_CALLBACK(folderview_start_drag
), folderview
);
516 g_signal_connect(G_OBJECT(ctree
), "drag_data_get",
517 G_CALLBACK(folderview_drag_data_get
),
520 g_signal_connect_after(G_OBJECT(ctree
), "tree_expand",
521 G_CALLBACK(folderview_tree_expanded
),
523 g_signal_connect_after(G_OBJECT(ctree
), "tree_collapse",
524 G_CALLBACK(folderview_tree_collapsed
),
527 g_signal_connect(G_OBJECT(ctree
), "resize_column",
528 G_CALLBACK(folderview_col_resized
),
532 gtk_drag_dest_set(ctree
, GTK_DEST_DEFAULT_ALL
& ~GTK_DEST_DEFAULT_HIGHLIGHT
,
533 folderview_drag_types
, 2,
534 GDK_ACTION_MOVE
| GDK_ACTION_COPY
| GDK_ACTION_DEFAULT
);
535 g_signal_connect(G_OBJECT(ctree
), "drag_motion",
536 G_CALLBACK(folderview_drag_motion_cb
),
538 g_signal_connect(G_OBJECT(ctree
), "drag_leave",
539 G_CALLBACK(folderview_drag_leave_cb
),
541 g_signal_connect(G_OBJECT(ctree
), "drag_data_received",
542 G_CALLBACK(folderview_drag_received_cb
),
544 g_signal_connect(G_OBJECT(ctree
), "drag_end",
545 G_CALLBACK(folderview_drag_end_cb
),
548 gtk_container_add(GTK_CONTAINER(scrolledwin
), ctree
);
553 void folderview_set_column_order(FolderView
*folderview
)
555 GtkWidget
*ctree
= folderview
->ctree
;
556 FolderItem
*item
= folderview_get_selected_item(folderview
);
557 FolderItem
*sel_item
= NULL
, *op_item
= NULL
;
558 GtkWidget
*scrolledwin
= folderview
->scrolledwin
;
560 if (folderview
->drag_timer_id
!= 0) {
561 g_source_remove(folderview
->drag_timer_id
);
562 folderview
->drag_timer_id
= 0;
564 if (folderview
->deferred_refresh_id
!= 0) {
565 g_source_remove(folderview
->deferred_refresh_id
);
566 folderview
->deferred_refresh_id
= 0;
568 if (folderview
->scroll_timeout_id
!= 0) {
569 g_source_remove(folderview
->scroll_timeout_id
);
570 folderview
->scroll_timeout_id
= 0;
572 if (folderview
->postpone_select_id
!= 0) {
573 g_source_remove(folderview
->postpone_select_id
);
574 folderview
->postpone_select_id
= 0;
577 if (folderview
->selected
)
578 sel_item
= folderview_get_selected_item(folderview
);
579 if (folderview
->opened
)
580 op_item
= folderview_get_opened_item(folderview
);
582 debug_print("recreating tree...\n");
583 gtk_widget_destroy(folderview
->ctree
);
586 folderview
->ctree
= ctree
= folderview_ctree_create(folderview
);
587 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin
),
588 GTK_CMCLIST(ctree
)->hadjustment
);
589 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin
),
590 GTK_CMCLIST(ctree
)->vadjustment
);
591 gtk_widget_show(ctree
);
594 folderview
->selected
= gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree
), NULL
, sel_item
);
596 folderview
->opened
= gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree
), NULL
, op_item
);
598 folderview_set(folderview
);
599 folderview_column_set_titles(folderview
);
601 folderview_select(folderview
,item
);
604 FolderView
*folderview_create(MainWindow
*mainwin
)
606 FolderView
*folderview
;
607 GtkWidget
*scrolledwin
;
610 debug_print("Creating folder view...\n");
611 folderview
= g_new0(FolderView
, 1);
613 scrolledwin
= gtk_scrolled_window_new(NULL
, NULL
);
614 gtk_widget_set_name(GTK_WIDGET(scrolledwin
), "folderview");
615 gtk_scrolled_window_set_policy
616 (GTK_SCROLLED_WINDOW(scrolledwin
),
617 GTK_POLICY_AUTOMATIC
,
618 prefs_common
.folderview_vscrollbar_policy
);
620 folderview
->scrolledwin
= scrolledwin
;
621 ctree
= folderview_ctree_create(folderview
);
622 gtk_cmclist_set_row_height(GTK_CMCLIST(ctree
), 0);
624 /* create popup factories */
625 folderview
->popups
= g_hash_table_new(g_str_hash
, g_str_equal
);
626 g_hash_table_foreach(folderview_popups
, create_action_groups
, folderview
);
628 gtk_action_group_add_actions(mainwin
->action_group
,
629 folderview_header_popup_entries
,
630 G_N_ELEMENTS(folderview_header_popup_entries
),
631 (gpointer
)folderview
);
633 MENUITEM_ADDUI_MANAGER(mainwin
->ui_manager
, "/Menus", "FolderViewHeaderPopup", "FolderViewHeaderPopup", GTK_UI_MANAGER_MENU
)
634 MENUITEM_ADDUI_MANAGER(mainwin
->ui_manager
, "/Menus/FolderViewHeaderPopup", "SetDisplayedColumns", "FolderViewHeaderPopup/SetDisplayedColumns", GTK_UI_MANAGER_MENUITEM
)
636 folderview
->headerpopupmenu
= gtk_menu_item_get_submenu(GTK_MENU_ITEM(
637 gtk_ui_manager_get_widget(mainwin
->ui_manager
,
638 "/Menus/FolderViewHeaderPopup") ));
640 folderview
->ctree
= ctree
;
642 folderview
->folder_update_callback_id
=
643 hooks_register_hook(FOLDER_UPDATE_HOOKLIST
, folderview_update_folder
, (gpointer
) folderview
);
644 folderview
->folder_item_update_callback_id
=
645 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST
, folderview_update_item_claws
, (gpointer
) folderview
);
647 gtk_widget_show_all(scrolledwin
);
649 folderview
->target_list
= gtk_target_list_new(folderview_drag_types
, 2);
650 folderview_list
= g_list_append(folderview_list
, folderview
);
652 folderview
->drag_timer_id
= 0;
653 folderview
->deferred_refresh_id
= 0;
654 folderview
->scroll_timeout_id
= 0;
655 folderview
->postpone_select_id
= 0;
660 static void folderview_set_fonts(FolderView
*folderview
)
662 PangoFontDescription
*font_desc
;
663 GtkWidget
*ctree
= folderview
->ctree
;
665 font_desc
= pango_font_description_from_string(NORMAL_FONT
);
667 gtk_widget_override_font(ctree
, font_desc
);
668 pango_font_description_free(font_desc
);
672 bold_style
= gtk_style_copy(gtk_widget_get_style(ctree
));
674 if (prefs_common
.derive_from_normal_font
|| !BOLD_FONT
) {
675 font_desc
= pango_font_description_from_string(NORMAL_FONT
);
677 pango_font_description_free(bold_style
->font_desc
);
678 bold_style
->font_desc
= font_desc
;
680 pango_font_description_set_weight
681 (bold_style
->font_desc
, PANGO_WEIGHT_BOLD
);
683 font_desc
= pango_font_description_from_string(BOLD_FONT
);
685 pango_font_description_free(bold_style
->font_desc
);
686 bold_style
->font_desc
= font_desc
;
692 void folderview_init(FolderView
*folderview
)
694 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE
, &inboxxpm
);
695 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE_HRM
, &inboxhrmxpm
);
696 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN
, &inboxopenxpm
);
697 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN_HRM
, &inboxopenhrmxpm
);
698 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE
, &outboxxpm
);
699 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE_HRM
, &outboxhrmxpm
);
700 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN
, &outboxopenxpm
);
701 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN_HRM
, &outboxopenhrmxpm
);
702 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE
, &folderxpm
);
703 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE_HRM
, &folderhrmxpm
);
704 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN
, &folderopenxpm
);
705 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN_HRM
, &folderopenhrmxpm
);
706 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN
, &trashopenxpm
);
707 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN_HRM
, &trashopenhrmxpm
);
708 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE
, &trashxpm
);
709 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE_HRM
, &trashhrmxpm
);
710 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE
, &queuexpm
);
711 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE_HRM
, &queuehrmxpm
);
712 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN
, &queueopenxpm
);
713 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN_HRM
, &queueopenhrmxpm
);
714 stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_CLOSE
, &draftsxpm
);
715 stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_OPEN
, &draftsopenxpm
);
716 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_SUBS_OPEN
, &foldersubsopenxpm
);
717 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_SUBS_CLOSE
, &foldersubsxpm
);
718 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_NOSELECT_OPEN
, &foldernoselectopenxpm
);
719 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_NOSELECT_CLOSE
, &foldernoselectxpm
);
721 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE_MARK
, &m_inboxxpm
);
722 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK
, &m_inboxhrmxpm
);
723 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN_MARK
, &m_inboxopenxpm
);
724 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN_HRM_MARK
, &m_inboxopenhrmxpm
);
725 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE_MARK
, &m_outboxxpm
);
726 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK
, &m_outboxhrmxpm
);
727 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN_MARK
, &m_outboxopenxpm
);
728 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK
, &m_outboxopenhrmxpm
);
729 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE_MARK
, &m_folderxpm
);
730 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE_HRM_MARK
, &m_folderhrmxpm
);
731 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN_MARK
, &m_folderopenxpm
);
732 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN_HRM_MARK
, &m_folderopenhrmxpm
);
733 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN_MARK
, &m_trashopenxpm
);
734 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN_HRM_MARK
, &m_trashopenhrmxpm
);
735 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE_MARK
, &m_trashxpm
);
736 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK
, &m_trashhrmxpm
);
737 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE_MARK
, &m_queuexpm
);
738 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK
, &m_queuehrmxpm
);
739 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN_MARK
, &m_queueopenxpm
);
740 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK
, &m_queueopenhrmxpm
);
741 stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_CLOSE_MARK
, &m_draftsxpm
);
742 stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_OPEN_MARK
, &m_draftsopenxpm
);
743 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_SUBS_CLOSE_MARK
, &m_foldersubsxpm
);
744 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_NOSELECT_CLOSE_MARK
, &m_foldernoselectxpm
);
746 folderview_set_fonts(folderview
);
749 static gboolean
folderview_defer_set(gpointer data
)
751 FolderView
*folderview
= (FolderView
*)data
;
752 MainWindow
*mainwin
= folderview
->mainwin
;
756 if (mainwin
->lock_count
)
759 debug_print("doing deferred folderview_set now\n");
760 folderview_set(folderview
);
762 folderview
->deferred_refresh_id
= 0;
766 void folderview_set(FolderView
*folderview
)
768 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
769 MainWindow
*mainwin
= folderview
->mainwin
;
770 FolderItem
*sel_item
= NULL
, *op_item
= NULL
;
775 if (mainwin
->lock_count
) {
776 if (folderview
->deferred_refresh_id
== 0)
777 folderview
->deferred_refresh_id
=
778 g_timeout_add(500, folderview_defer_set
, folderview
);
779 debug_print("deferred folderview_set\n");
784 debug_print("Setting folder info...\n");
785 STATUSBAR_PUSH(mainwin
, _("Setting folder info..."));
787 main_window_cursor_wait(mainwin
);
789 if (folderview
->selected
)
790 sel_item
= folderview_get_selected_item(folderview
);
791 if (folderview
->opened
)
792 op_item
= folderview_get_opened_item(folderview
);
794 folderview
->selected
= NULL
;
795 folderview
->opened
= NULL
;
797 gtk_cmclist_freeze(GTK_CMCLIST(ctree
));
798 gtk_cmclist_clear(GTK_CMCLIST(ctree
));
800 folderview_set_folders(folderview
);
803 folderview
->selected
= gtk_cmctree_find_by_row_data(ctree
, NULL
, sel_item
);
805 folderview
->opened
= gtk_cmctree_find_by_row_data(ctree
, NULL
, op_item
);
807 gtk_cmclist_thaw(GTK_CMCLIST(ctree
));
808 main_window_cursor_normal(mainwin
);
809 STATUSBAR_POP(mainwin
);
813 void folderview_set_all(void)
817 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
)
818 folderview_set((FolderView
*)list
->data
);
821 void folderview_select(FolderView
*folderview
, FolderItem
*item
)
823 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
824 GtkCMCTreeNode
*node
;
825 GtkCMCTreeNode
*old_selected
= folderview
->selected
;
829 node
= gtk_cmctree_find_by_row_data(ctree
, NULL
, item
);
830 if (node
) folderview_select_node(folderview
, node
);
832 if (old_selected
!= node
)
833 folder_update_op_count();
836 static void mark_all_read_cb(GtkAction
*action
, gpointer data
)
838 mark_all_read_unread_handler(action
, data
, FALSE
, TRUE
);
841 static void mark_all_unread_cb(GtkAction
*action
, gpointer data
)
843 mark_all_read_unread_handler(action
, data
, FALSE
, FALSE
);
846 static void mark_all_read_recursive_cb(GtkAction
*action
, gpointer data
)
848 mark_all_read_unread_handler(action
, data
, TRUE
, TRUE
);
851 static void mark_all_unread_recursive_cb(GtkAction
*action
, gpointer data
)
853 mark_all_read_unread_handler(action
, data
, TRUE
, FALSE
);
856 static void mark_all_read_unread_handler(GtkAction
*action
, gpointer data
,
857 gboolean recursive
, gboolean read
)
859 FolderView
*folderview
= (FolderView
*)data
;
865 item
= folderview_get_selected_item(folderview
);
870 title
= _("Mark all as read");
871 message
= recursive
? _("Do you really want to mark all mails in this "
872 "folder and its subfolders as read?") :
873 _("Do you really want to mark all mails in this "
876 title
= _("Mark all as unread");
877 message
= recursive
? _("Do you really want to mark all mails in this "
878 "folder and its subfolders as unread?") :
879 _("Do you really want to mark all mails in this "
880 "folder as unread?");
882 if (prefs_common
.ask_mark_all_read
) {
883 val
= alertpanel_full(title
, message
,
884 NULL
, _("_No"), NULL
, _("_Yes"), NULL
, NULL
,
885 ALERTFOCUS_FIRST
, TRUE
, NULL
, ALERT_QUESTION
);
887 if ((val
& ~G_ALERTDISABLE
) != G_ALERTALTERNATE
)
889 else if (val
& G_ALERTDISABLE
)
890 prefs_common
.ask_mark_all_read
= FALSE
;
893 folder_item_update_freeze();
894 if (folderview
->summaryview
->folder_item
!= item
&& !recursive
)
895 summary_lock(folderview
->summaryview
);
897 summary_freeze(folderview
->summaryview
);
901 folderutils_mark_all_read_recursive(item
, TRUE
);
903 if (prefs_common
.run_processingrules_before_mark_all
)
904 folderview_run_processing(item
);
905 folderutils_mark_all_read(item
, TRUE
);
909 folderutils_mark_all_read_recursive(item
, FALSE
);
911 folderutils_mark_all_read(item
, FALSE
);
912 if (prefs_common
.run_processingrules_before_mark_all
)
913 folderview_run_processing(item
);
916 if (folderview
->summaryview
->folder_item
!= item
&& !recursive
)
917 summary_unlock(folderview
->summaryview
);
919 summary_thaw(folderview
->summaryview
);
920 folder_item_update_thaw();
923 static void folderview_select_node(FolderView
*folderview
, GtkCMCTreeNode
*node
)
925 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
927 cm_return_if_fail(node
!= NULL
);
929 if (folderview
->open_folder
) {
933 gtk_cmclist_freeze(GTK_CMCLIST(ctree
));
934 gtkut_ctree_expand_parent_all(ctree
, node
);
936 folderview
->open_folder
= TRUE
;
937 gtkut_ctree_set_focus_row(ctree
, node
);
938 gtk_cmctree_select(ctree
, node
);
939 gtk_cmclist_thaw(GTK_CMCLIST(ctree
));
940 if ((folderview
->summaryview
->folder_item
&&
941 folderview
->summaryview
->folder_item
->total_msgs
> 0) ||
942 prefs_common
.layout_mode
== SMALL_LAYOUT
)
943 summary_select_node(folderview
->summaryview
,
944 folderview
->summaryview
->selected
, OPEN_SELECTED_ON_FOLDER_OPEN
);
946 gtk_widget_grab_focus(folderview
->ctree
);
949 void folderview_unselect(FolderView
*folderview
)
951 if (folderview
->opened
&& !GTK_CMCTREE_ROW(folderview
->opened
)->children
)
953 (GTK_CMCTREE(folderview
->ctree
), folderview
->opened
);
955 folderview
->selected
= folderview
->opened
= NULL
;
958 static GtkCMCTreeNode
*folderview_find_next_with_flag(GtkCMCTree
*ctree
,
959 GtkCMCTreeNode
*node
,
965 node
= gtkut_ctree_node_next(ctree
, node
);
967 node
= GTK_CMCTREE_NODE(GTK_CMCLIST(ctree
)->row_list
);
969 for (; node
!= NULL
; node
= gtkut_ctree_node_next(ctree
, node
)) {
970 item
= gtk_cmctree_node_get_row_data(ctree
, node
);
973 if (item
->stype
== F_TRASH
|| item
->stype
== F_DRAFT
)
977 if((item
->unread_msgs
> 0) && (!item
->prefs
|| !item
->prefs
->skip_on_goto_unread_or_new
))
981 if((item
->new_msgs
> 0) && (!item
->prefs
|| !item
->prefs
->skip_on_goto_unread_or_new
))
985 if(item
->marked_msgs
> 0)
989 if(item
->total_msgs
> 0)
998 void folderview_select_next_with_flag(FolderView
*folderview
,
1001 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
1002 GtkCMCTreeNode
*node
= NULL
;
1003 EntryAction last_summary_select_prio
= prefs_common
.summary_select_prio
[0];
1007 prefs_common
.summary_select_prio
[0] = ACTION_OLDEST_UNREAD
;
1010 prefs_common
.summary_select_prio
[0] = ACTION_OLDEST_NEW
;
1013 prefs_common
.summary_select_prio
[0] = ACTION_OLDEST_MARKED
;
1016 prefs_common
.summary_select_prio
[0] = ACTION_OLDEST_LIST
;
1020 node
= folderview_find_next_with_flag(ctree
, folderview
->opened
, flag
);
1022 folderview_select_node(folderview
, node
);
1026 if (!folderview
->opened
||
1027 folderview
->opened
== GTK_CMCTREE_NODE(GTK_CMCLIST(ctree
)->row_list
)) {
1031 /* search again from the first node */
1032 node
= folderview_find_next_with_flag(ctree
, NULL
, flag
);
1034 folderview_select_node(folderview
, node
);
1037 prefs_common
.summary_select_prio
[0] = last_summary_select_prio
;
1040 FolderItem
*folderview_get_selected_item(FolderView
*folderview
)
1042 g_return_val_if_fail(folderview
!= NULL
, NULL
);
1043 g_return_val_if_fail(folderview
->ctree
!= NULL
, NULL
);
1045 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
1047 if (!folderview
->selected
) return NULL
;
1048 return gtk_cmctree_node_get_row_data(ctree
, folderview
->selected
);
1051 FolderItem
*folderview_get_opened_item(FolderView
*folderview
)
1053 g_return_val_if_fail(folderview
!= NULL
, NULL
);
1054 g_return_val_if_fail(folderview
->ctree
!= NULL
, NULL
);
1056 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
1058 if (!folderview
->opened
) return NULL
;
1059 return gtk_cmctree_node_get_row_data(ctree
, folderview
->opened
);
1062 static void folderview_set_folders(FolderView
*folderview
)
1065 list
= folder_get_list();
1067 for (; list
!= NULL
; list
= list
->next
) {
1068 folderview_append_folder(folderview
, FOLDER(list
->data
));
1072 static gchar
*get_scan_str(FolderItem
*item
)
1075 return g_strdup_printf(_("Scanning folder %s/%s..."),
1076 item
->folder
->name
, item
->path
);
1078 return g_strdup_printf(_("Scanning folder %s..."),
1079 item
->folder
->name
);
1081 static void folderview_scan_tree_func(Folder
*folder
, FolderItem
*item
,
1085 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
) {
1086 FolderView
*folderview
= (FolderView
*)list
->data
;
1087 MainWindow
*mainwin
= folderview
->mainwin
;
1088 gchar
*str
= get_scan_str(item
);
1090 STATUSBAR_PUSH(mainwin
, str
);
1091 STATUSBAR_POP(mainwin
);
1096 void folderview_rescan_tree(Folder
*folder
, gboolean rebuild
)
1099 MainWindow
*mainwin
= mainwindow_get_mainwindow();
1100 FolderView
*folderview
= NULL
;
1101 GtkAdjustment
*pos
= NULL
;
1104 cm_return_if_fail(folder
!= NULL
);
1106 if (!folder
->klass
->scan_tree
) return;
1109 alertpanel_full(_("Rebuild folder tree"),
1110 _("Rebuilding the folder tree will remove "
1111 "local caches. Do you want to continue?"),
1112 NULL
, _("_No"), NULL
, _("_Yes"), NULL
, NULL
,
1113 ALERTFOCUS_FIRST
, FALSE
, NULL
, ALERT_WARNING
)
1114 != G_ALERTALTERNATE
) {
1120 window
= label_window_create(_("Rebuilding folder tree..."));
1122 window
= label_window_create(_("Scanning folder tree..."));
1125 folderview
= mainwin
->folderview
;
1128 pos
= gtk_scrolled_window_get_vadjustment(
1129 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
1130 height
= gtk_adjustment_get_value(pos
);
1133 folder_set_ui_func(folder
, folderview_scan_tree_func
, NULL
);
1134 folder_scan_tree(folder
, rebuild
);
1135 folder_set_ui_func(folder
, NULL
, NULL
);
1137 folderview_set_all();
1140 pos
= gtk_scrolled_window_get_vadjustment(
1141 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
1142 gtk_adjustment_set_value(pos
, height
);
1144 label_window_destroy(window
);
1148 /** folderview_check_new()
1149 * Scan and update the folder and return the
1150 * count the number of new messages since last check.
1151 * \param folder the folder to check for new messages
1152 * \return the number of new messages since last check
1154 gint
folderview_check_new(Folder
*folder
)
1158 FolderView
*folderview
;
1160 GtkCMCTreeNode
*node
;
1162 gint former_new_msgs
= 0;
1163 gint former_new
= 0, former_unread
= 0, former_total
;
1165 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
) {
1166 folderview
= (FolderView
*)list
->data
;
1167 ctree
= GTK_CMCTREE(folderview
->ctree
);
1168 folderview
->scanning_folder
= folder
;
1170 main_window_lock(folderview
->mainwin
);
1172 for (node
= GTK_CMCTREE_NODE(GTK_CMCLIST(ctree
)->row_list
);
1173 node
!= NULL
; node
= gtkut_ctree_node_next(ctree
, node
)) {
1175 item
= gtk_cmctree_node_get_row_data(ctree
, node
);
1176 if (!item
|| !item
->path
|| !item
->folder
) continue;
1177 if (item
->no_select
) continue;
1178 if (folder
&& folder
!= item
->folder
) continue;
1179 if (!folder
&& !FOLDER_IS_LOCAL(item
->folder
)) continue;
1180 if (!item
->prefs
->newmailcheck
) continue;
1181 if (item
->processing_pending
== TRUE
) {
1182 debug_print("skipping %s, processing pending\n",
1183 item
->path
? item
->path
: item
->name
);
1186 if (item
->scanning
!= ITEM_NOT_SCANNING
) {
1187 debug_print("skipping %s, scanning\n",
1188 item
->path
? item
->path
: item
->name
);
1192 str
= get_scan_str(item
);
1194 STATUSBAR_PUSH(folderview
->mainwin
, str
);
1198 folderview_scan_tree_func(item
->folder
, item
, NULL
);
1199 former_new
= item
->new_msgs
;
1200 former_unread
= item
->unread_msgs
;
1201 former_total
= item
->total_msgs
;
1203 if (item
->folder
->klass
->scan_required
&&
1204 (item
->folder
->klass
->scan_required(item
->folder
, item
) ||
1205 item
->folder
->inbox
== item
||
1206 item
->opened
== TRUE
||
1207 item
->processing_pending
== TRUE
)) {
1208 if (folder_item_scan(item
) < 0) {
1210 summaryview_unlock(folderview
->summaryview
, item
);
1211 if (FOLDER_TYPE(item
->folder
) == F_NEWS
|| FOLDER_IS_LOCAL(folder
)) {
1212 log_error(LOG_PROTOCOL
, _("Couldn't scan folder %s\n"),
1213 item
->path
? item
->path
:item
->name
);
1214 STATUSBAR_POP(folderview
->mainwin
);
1216 } else if (!FOLDER_IS_LOCAL(folder
)) {
1217 STATUSBAR_POP(folderview
->mainwin
);
1222 } else if (!item
->folder
->klass
->scan_required
) {
1223 if (folder_item_scan(item
) < 0) {
1224 summaryview_unlock(folderview
->summaryview
, item
);
1225 if (folder
&& !FOLDER_IS_LOCAL(folder
)) {
1226 STATUSBAR_POP(folderview
->mainwin
);
1231 if (former_new
!= item
->new_msgs
||
1232 former_unread
!= item
->unread_msgs
||
1233 former_total
!= item
->total_msgs
)
1234 folderview_update_node(folderview
, node
);
1236 new_msgs
+= item
->new_msgs
;
1237 former_new_msgs
+= former_new
;
1238 STATUSBAR_POP(folderview
->mainwin
);
1240 folderview
->scanning_folder
= NULL
;
1241 main_window_unlock(folderview
->mainwin
);
1245 folder_write_list();
1246 /* Number of new messages since last check is the just the difference
1247 * between former_new_msgs and new_msgs. If new_msgs is less than
1248 * former_new_msgs, that would mean another session accessed the folder
1249 * and the result is not well defined.
1251 new_msgs
= (former_new_msgs
< new_msgs
? new_msgs
- former_new_msgs
: 0);
1255 void folderview_check_new_all(void)
1259 FolderView
*folderview
;
1261 folderview
= (FolderView
*)folderview_list
->data
;
1264 main_window_lock(folderview
->mainwin
);
1265 window
= label_window_create
1266 (_("Checking for new messages in all folders..."));
1268 list
= folder_get_list();
1269 for (; list
!= NULL
; list
= list
->next
) {
1270 Folder
*folder
= list
->data
;
1272 folderview_check_new(folder
);
1275 folder_write_list();
1276 folderview_set_all();
1278 label_window_destroy(window
);
1279 main_window_unlock(folderview
->mainwin
);
1283 static gboolean
folderview_have_children_sub(FolderView
*folderview
,
1289 if (!item
|| !item
->folder
|| !item
->folder
->node
)
1292 node
= item
->folder
->node
;
1294 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1295 node
= node
->children
;
1297 if (in_sub
&& item
->total_msgs
> 0) {
1301 while (node
!= NULL
) {
1302 if (node
&& node
->data
) {
1303 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1305 if (folderview_have_children_sub(folderview
,
1314 static gboolean
folderview_have_children(FolderView
*folderview
,
1317 return folderview_have_children_sub(folderview
, item
, FALSE
);
1320 static gboolean
folderview_have_new_children_sub(FolderView
*folderview
,
1326 if (!item
|| !item
->folder
|| !item
->folder
->node
)
1329 node
= item
->folder
->node
;
1331 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1332 node
= node
->children
;
1335 (item
->new_msgs
> 0 ||
1336 (folder_has_parent_of_type(item
, F_QUEUE
) && item
->total_msgs
> 0))) {
1340 while (node
!= NULL
) {
1341 if (node
&& node
->data
) {
1342 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1344 if (folderview_have_new_children_sub(folderview
,
1353 static gboolean
folderview_have_new_children(FolderView
*folderview
,
1356 return folderview_have_new_children_sub(folderview
, item
, FALSE
);
1359 static gboolean
folderview_have_unread_children_sub(FolderView
*folderview
,
1365 if (!item
|| !item
->folder
|| !item
->folder
->node
)
1368 node
= item
->folder
->node
;
1370 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1371 node
= node
->children
;
1374 (item
->unread_msgs
> 0 ||
1375 (folder_has_parent_of_type(item
, F_QUEUE
) && item
->total_msgs
> 0))) {
1379 while (node
!= NULL
) {
1380 if (node
&& node
->data
) {
1381 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1383 if (folderview_have_unread_children_sub(folderview
,
1393 static gboolean
folderview_have_unread_children(FolderView
*folderview
,
1396 return folderview_have_unread_children_sub(folderview
, item
, FALSE
);
1399 static gboolean
folderview_have_read_children_sub(FolderView
*folderview
,
1405 if (!item
|| !item
->folder
|| !item
->folder
->node
) {
1409 node
= item
->folder
->node
;
1411 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1412 node
= node
->children
;
1415 (((item
->total_msgs
> 0) &&
1416 (item
->unread_msgs
!= (item
->total_msgs
- item
->ignored_msgs
))))) {
1420 while (node
!= NULL
) {
1421 if (node
&& node
->data
) {
1422 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1424 if (folderview_have_read_children_sub(folderview
,
1435 static gboolean
folderview_have_read_children(FolderView
*folderview
,
1438 return folderview_have_read_children_sub(folderview
, item
, FALSE
);
1441 static gboolean
folderview_have_matching_children_sub(FolderView
*folderview
,
1447 if (!item
|| !item
->folder
|| !item
->folder
->node
)
1450 node
= item
->folder
->node
;
1452 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1453 node
= node
->children
;
1455 if (in_sub
&& item
->search_match
){
1459 while (node
!= NULL
) {
1460 if (node
&& node
->data
) {
1461 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1463 if (folderview_have_matching_children_sub(folderview
,
1473 static gboolean
folderview_have_matching_children(FolderView
*folderview
,
1476 return folderview_have_matching_children_sub(folderview
, item
, FALSE
);
1479 static gboolean
folderview_have_marked_children_sub(FolderView
*folderview
,
1485 if (!item
|| !item
->folder
|| !item
->folder
->node
)
1488 node
= item
->folder
->node
;
1490 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1491 node
= node
->children
;
1493 if (item
->marked_msgs
!= 0) {
1497 while (node
!= NULL
) {
1498 if (node
&& node
->data
) {
1499 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1501 if (folderview_have_marked_children_sub(folderview
,
1510 static gboolean
folderview_have_marked_children(FolderView
*folderview
,
1513 return folderview_have_marked_children_sub(folderview
, item
, FALSE
);
1516 static void folderview_update_node(FolderView
*folderview
, GtkCMCTreeNode
*node
)
1518 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
1519 GtkStyle
*style
= NULL
, *prev_style
;
1521 GdkRGBA black
= { 0, 0, 0, 1 };
1522 GdkPixbuf
*xpm
, *openxpm
;
1523 static GdkPixbuf
*searchicon
;
1524 gboolean mark
= FALSE
;
1527 gboolean add_unread_mark
;
1528 gboolean add_sub_match_mark
;
1529 gboolean use_bold
, use_color
;
1530 gint
*col_pos
= folderview
->col_pos
;
1531 SpecialFolderItemType stype
;
1533 item
= gtk_cmctree_node_get_row_data(ctree
, node
);
1534 cm_return_if_fail(item
!= NULL
);
1536 if (!GTK_CMCTREE_ROW(node
)->expanded
)
1537 mark
= folderview_have_marked_children(folderview
, item
);
1539 mark
= (item
->marked_msgs
!= 0);
1541 stype
= item
->stype
;
1542 if (stype
== F_NORMAL
) {
1543 if (folder_has_parent_of_type(item
, F_TRASH
))
1545 else if (folder_has_parent_of_type(item
, F_DRAFT
))
1547 else if (folder_has_parent_of_type(item
, F_OUTBOX
))
1549 else if (folder_has_parent_of_type(item
, F_QUEUE
))
1554 if (item
->hide_read_msgs
|| item
->hide_read_threads
) {
1555 xpm
= mark
?m_inboxhrmxpm
:inboxhrmxpm
;
1556 openxpm
= mark
?m_inboxopenhrmxpm
:inboxopenhrmxpm
;
1558 xpm
= mark
?m_inboxxpm
:inboxxpm
;
1559 openxpm
= mark
?m_inboxopenxpm
:inboxopenxpm
;
1563 if (item
->hide_read_msgs
|| item
->hide_read_threads
) {
1564 xpm
= mark
?m_outboxhrmxpm
:outboxhrmxpm
;
1565 openxpm
= mark
?m_outboxopenhrmxpm
:outboxopenhrmxpm
;
1567 xpm
= mark
?m_outboxxpm
:outboxxpm
;
1568 openxpm
= mark
?m_outboxopenxpm
:outboxopenxpm
;
1572 if (item
->hide_read_msgs
|| item
->hide_read_threads
) {
1573 xpm
= mark
?m_queuehrmxpm
:queuehrmxpm
;
1574 openxpm
= mark
?m_queueopenhrmxpm
:queueopenhrmxpm
;
1576 xpm
= mark
?m_queuexpm
:queuexpm
;
1577 openxpm
= mark
?m_queueopenxpm
:queueopenxpm
;
1581 if (item
->hide_read_msgs
|| item
->hide_read_threads
) {
1582 xpm
= mark
?m_trashhrmxpm
:trashhrmxpm
;
1583 openxpm
= mark
?m_trashopenhrmxpm
:trashopenhrmxpm
;
1585 xpm
= mark
?m_trashxpm
:trashxpm
;
1586 openxpm
= mark
?m_trashopenxpm
:trashopenxpm
;
1590 xpm
= mark
?m_draftsxpm
:draftsxpm
;
1591 openxpm
= mark
?m_draftsopenxpm
:draftsopenxpm
;
1595 FOLDER_TYPE(item
->folder
) == F_IMAP
&&
1596 item
->folder
->account
->imap_subsonly
) {
1597 xpm
= mark
?m_foldersubsxpm
:foldersubsxpm
;
1598 openxpm
= foldersubsopenxpm
;
1599 } else if (item
->no_select
) {
1600 xpm
= mark
?m_foldernoselectxpm
:foldernoselectxpm
;
1601 openxpm
= foldernoselectopenxpm
;
1602 } else if (item
->hide_read_msgs
|| item
->hide_read_threads
) {
1603 xpm
= mark
?m_folderhrmxpm
:folderhrmxpm
;
1604 openxpm
= mark
?m_folderopenhrmxpm
:folderopenhrmxpm
;
1606 xpm
= mark
?m_folderxpm
:folderxpm
;
1607 openxpm
= mark
?m_folderopenxpm
:folderopenxpm
;
1611 name
= folder_item_get_name(item
);
1613 if (!GTK_CMCTREE_ROW(node
)->expanded
) {
1614 add_unread_mark
= folderview_have_unread_children(
1616 add_sub_match_mark
= folderview_have_matching_children(
1619 add_unread_mark
= FALSE
;
1620 add_sub_match_mark
= FALSE
;
1623 if (item
->search_match
) {
1625 stock_pixbuf_gdk(STOCK_PIXMAP_QUICKSEARCH
,
1628 xpm
= openxpm
= searchicon
;
1632 if (prefs_common
.display_folder_unread
) {
1633 if (folder_has_parent_of_type(item
, F_QUEUE
)) {
1634 /* only total_msgs matters here */
1635 if (item
->total_msgs
> 0) {
1636 /* show total number (should be equal to the unread number)
1638 str
= g_strdup_printf("%s (%d%s%s)",
1639 name
, item
->total_msgs
,
1640 (add_unread_mark
|| add_sub_match_mark
) ? "+" : "",
1641 (item
->unreadmarked_msgs
> 0) ? "!" : "");
1644 if (prefs_common
.display_folder_unread
== 1) {
1645 if (item
->unread_msgs
> 0) {
1646 /* show unread number and signs */
1647 str
= g_strdup_printf("%s (%d%s%s)",
1648 name
, item
->unread_msgs
,
1649 (add_unread_mark
|| add_sub_match_mark
) ? "+" : "",
1650 (item
->unreadmarked_msgs
> 0) ? "!" : "");
1653 if (item
->total_msgs
> 0) {
1654 /* show unread number, total number and signs if any */
1655 str
= g_strdup_printf("%s (%d/%d%s%s)",
1656 name
, item
->unread_msgs
, item
->total_msgs
,
1657 (add_unread_mark
|| add_sub_match_mark
) ? "+" : "",
1658 (item
->unreadmarked_msgs
> 0) ? "!" : "");
1662 if ((str
== NULL
) &&
1663 (add_unread_mark
|| add_sub_match_mark
|| (item
->unreadmarked_msgs
> 0))) {
1664 /* no unread/total numbers, but at least one sign */
1665 str
= g_strdup_printf("%s (%s%s)",
1667 (add_unread_mark
|| add_sub_match_mark
) ? "+" : "",
1668 (item
->unreadmarked_msgs
> 0) ? "!" : "");
1672 /* last fallback, folder name only or with +! sign */
1673 if (item
->unreadmarked_msgs
> 0 && add_sub_match_mark
) {
1674 str
= g_strdup_printf("%s%s",
1676 } else if (item
->unreadmarked_msgs
> 0) {
1677 str
= g_strdup_printf("%s%s",
1679 } else if (add_sub_match_mark
) {
1680 str
= g_strdup_printf("%s%s",
1683 str
= g_strdup_printf("%s", name
);
1686 gtk_cmctree_set_node_info(ctree
, node
, str
, FOLDER_SPACING
,
1688 FALSE
, GTK_CMCTREE_ROW(node
)->expanded
);
1692 if (!folder_item_parent(item
)) {
1693 gtk_cmctree_node_set_text(ctree
, node
, col_pos
[F_COL_NEW
], "-");
1694 gtk_cmctree_node_set_text(ctree
, node
, col_pos
[F_COL_UNREAD
], "-");
1695 gtk_cmctree_node_set_text(ctree
, node
, col_pos
[F_COL_TOTAL
], "-");
1697 gtk_cmctree_node_set_text(ctree
, node
, col_pos
[F_COL_NEW
], item
->new_msgs
> 0 ? itos(item
->new_msgs
) : prefs_common
.zero_replacement
);
1698 gtk_cmctree_node_set_text(ctree
, node
, col_pos
[F_COL_UNREAD
], item
->unread_msgs
> 0 ? itos(item
->unread_msgs
) : prefs_common
.zero_replacement
);
1699 gtk_cmctree_node_set_text(ctree
, node
, col_pos
[F_COL_TOTAL
], item
->total_msgs
> 0 ? itos(item
->total_msgs
) : prefs_common
.zero_replacement
);
1702 if (folder_has_parent_of_type(item
, F_OUTBOX
) ||
1703 folder_has_parent_of_type(item
, F_TRASH
)) {
1704 use_bold
= use_color
= FALSE
;
1705 } else if (folder_has_parent_of_type(item
, F_QUEUE
)) {
1706 GSList
*list
= folder_item_get_msg_list(item
);
1708 use_bold
= use_color
= FALSE
;
1709 for (cur
= list
; cur
; cur
= cur
->next
) {
1710 MsgInfo
*msginfo
= (MsgInfo
*)cur
->data
;
1711 if (!MSG_IS_DELETED(msginfo
->flags
)) {
1712 /* highlight queue folder if there are any messages */
1713 use_bold
= use_color
= TRUE
;
1717 if (!GTK_CMCTREE_ROW(node
)->expanded
&&
1718 use_bold
== FALSE
&&
1719 folderview_have_children(folderview
, item
))
1720 use_bold
= use_color
= TRUE
;
1721 procmsg_msg_list_free(list
);
1723 /* if unread messages exist or target folder is set, print with bold font */
1724 use_bold
= (item
->unread_msgs
> 0 || item
->new_msgs
> 0 || item
->op_count
> 0)
1726 /* if new messages exist, print with colored letter */
1728 (item
->new_msgs
> 0) ||
1730 folderview_have_new_children(folderview
, item
));
1733 gtk_cmctree_node_set_foreground(ctree
, node
, NULL
);
1737 if (item
->op_count
> 0)
1738 gtk_cmctree_node_set_foreground(ctree
, node
, &folderview
->color_op
);
1740 gtk_cmctree_node_set_foreground(ctree
, node
, &folderview
->color_new
);
1741 else if (!gdk_rgba_equal(&item
->prefs
->color
, &black
))
1742 gtk_cmctree_node_set_foreground(ctree
, node
, &item
->prefs
->color
);
1743 } else if (use_color
)
1744 gtk_cmctree_node_set_foreground(ctree
, node
, &folderview
->color_new
);
1745 else if (item
->op_count
> 0)
1746 gtk_cmctree_node_set_foreground(ctree
, node
, &folderview
->color_op
);
1747 else if (!gdk_rgba_equal(&item
->prefs
->color
, &black
))
1748 gtk_cmctree_node_set_foreground(ctree
, node
, &item
->prefs
->color
);
1750 gtk_cmctree_node_set_row_style(ctree
, node
, style
);
1752 prev_style
= gtk_cmctree_node_get_row_style(ctree
, node
);
1754 GtkStyle
*ctree_style
= gtk_widget_get_style(GTK_WIDGET(ctree
));
1756 style
= gtk_style_copy(prev_style
);
1757 style
->text
[GTK_STATE_NORMAL
] = ctree_style
->text
[GTK_STATE_NORMAL
];
1758 style
->text
[GTK_STATE_SELECTED
] = ctree_style
->text
[GTK_STATE_SELECTED
];
1759 gtk_cmctree_node_set_row_style(ctree
, node
, style
);
1760 g_object_unref(style
);
1763 if ((node
= gtkut_ctree_find_collapsed_parent(ctree
, node
)) != NULL
)
1764 folderview_update_node(folderview
, node
);
1767 void folderview_update_search_icon(FolderItem
*item
, gboolean matches
)
1770 FolderView
*folderview
;
1772 GtkCMCTreeNode
*node
;
1774 cm_return_if_fail(item
!= NULL
);
1776 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
) {
1777 folderview
= (FolderView
*)list
->data
;
1778 ctree
= GTK_CMCTREE(folderview
->ctree
);
1780 node
= gtk_cmctree_find_by_row_data(ctree
, NULL
, item
);
1781 if (node
&& item
->search_match
!= matches
) {
1782 item
->search_match
= matches
;
1783 folderview_update_node(folderview
, node
);
1788 static gboolean
folderview_update_item_claws(gpointer source
, gpointer data
)
1790 FolderItemUpdateData
*update_info
= (FolderItemUpdateData
*)source
;
1791 FolderView
*folderview
= (FolderView
*)data
;
1793 GtkCMCTreeNode
*node
;
1794 cm_return_val_if_fail(update_info
!= NULL
, TRUE
);
1795 cm_return_val_if_fail(update_info
->item
!= NULL
, TRUE
);
1796 cm_return_val_if_fail(folderview
!= NULL
, FALSE
);
1798 ctree
= GTK_CMCTREE(folderview
->ctree
);
1800 node
= gtk_cmctree_find_by_row_data(ctree
, NULL
, update_info
->item
);
1803 if (update_info
->update_flags
& (F_ITEM_UPDATE_MSGCNT
| F_ITEM_UPDATE_NAME
))
1804 folderview_update_node(folderview
, node
);
1806 if ((update_info
->update_flags
& F_ITEM_UPDATE_CONTENT
) &&
1807 update_info
->item
== folderview
->summaryview
->folder_item
&&
1808 update_info
->item
!= NULL
)
1809 if (!quicksearch_has_sat_predicate(folderview
->summaryview
->quicksearch
))
1810 summary_show(folderview
->summaryview
, update_info
->item
, FALSE
);
1816 static gboolean
folderview_gnode_func(GtkCMCTree
*ctree
, guint depth
,
1817 GNode
*gnode
, GtkCMCTreeNode
*cnode
,
1820 FolderView
*folderview
= (FolderView
*)data
;
1821 FolderItem
*item
= FOLDER_ITEM(gnode
->data
);
1823 cm_return_val_if_fail(item
!= NULL
, FALSE
);
1825 gtk_cmctree_node_set_row_data(ctree
, cnode
, item
);
1826 folderview_update_node(folderview
, cnode
);
1831 static void folderview_expand_func(GtkCMCTree
*ctree
, GtkCMCTreeNode
*node
,
1834 FolderView
*folderview
= (FolderView
*)data
;
1837 if (GTK_CMCTREE_ROW(node
)->children
) {
1838 item
= gtk_cmctree_node_get_row_data(ctree
, node
);
1839 cm_return_if_fail(item
!= NULL
);
1841 if (!item
->collapsed
)
1842 gtk_cmctree_expand(ctree
, node
);
1844 folderview_update_node(folderview
, node
);
1848 static void set_special_folder(GtkCMCTree
*ctree
, FolderItem
*item
,
1849 GtkCMCTreeNode
*root
, GtkCMCTreeNode
**prev
)
1852 GtkCMCTreeNode
*node
, *parent
, *sibling
;
1854 node
= gtk_cmctree_find_by_row_data(ctree
, root
, item
);
1856 g_warning("%s not found", item
->path
);
1858 parent
= GTK_CMCTREE_ROW(node
)->parent
;
1859 if (*prev
&& parent
== GTK_CMCTREE_ROW(*prev
)->parent
)
1860 sibling
= GTK_CMCTREE_ROW(*prev
)->sibling
;
1862 sibling
= GTK_CMCTREE_ROW(parent
)->children
;
1866 tmp
= gtk_cmctree_node_get_row_data
1868 if (tmp
&& tmp
->stype
!= F_NORMAL
)
1869 sibling
= GTK_CMCTREE_ROW(sibling
)->sibling
;
1873 if (node
!= sibling
)
1874 gtk_cmctree_move(ctree
, node
, parent
, sibling
);
1881 static void folderview_sort_folders(FolderView
*folderview
, GtkCMCTreeNode
*root
,
1884 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
1885 GtkCMCTreeNode
*prev
= NULL
;
1887 gtk_cmclist_freeze(GTK_CMCLIST(ctree
));
1888 gtk_sctree_sort_recursive(ctree
, root
);
1889 if (root
&& GTK_CMCTREE_ROW(root
)->parent
) {
1890 gtk_cmclist_thaw(GTK_CMCLIST(ctree
));
1893 set_special_folder(ctree
, folder
->inbox
, root
, &prev
);
1894 set_special_folder(ctree
, folder
->outbox
, root
, &prev
);
1895 set_special_folder(ctree
, folder
->draft
, root
, &prev
);
1896 set_special_folder(ctree
, folder
->queue
, root
, &prev
);
1897 set_special_folder(ctree
, folder
->trash
, root
, &prev
);
1898 gtk_cmclist_thaw(GTK_CMCLIST(ctree
));
1901 static void folderview_append_folder(FolderView
*folderview
, Folder
*folder
)
1903 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
1904 GtkCMCTreeNode
*root
;
1906 cm_return_if_fail(folder
!= NULL
);
1908 root
= gtk_sctree_insert_gnode(ctree
, NULL
, NULL
, folder
->node
,
1909 folderview_gnode_func
, folderview
);
1910 gtk_cmctree_pre_recursive(ctree
, root
, folderview_expand_func
,
1912 folderview_sort_folders(folderview
, root
, folder
);
1915 /* callback functions */
1916 static void folderview_set_sens_and_popup_menu(FolderView
*folderview
, gint row
,
1917 GdkEventButton
*event
)
1921 FolderViewPopup
*fpopup
;
1922 GtkActionGroup
*action_group
;
1924 FolderItem
*special_trash
= NULL
, *special_queue
= NULL
;
1926 GtkUIManager
*ui_manager
= gtk_ui_manager_new();
1928 if (folderview
->ui_manager
)
1929 g_object_unref(folderview
->ui_manager
);
1931 folderview
->ui_manager
= ui_manager
;
1932 item
= folderview_get_selected_item(folderview
);
1934 cm_return_if_fail(item
!= NULL
);
1935 cm_return_if_fail(item
->folder
!= NULL
);
1936 folder
= item
->folder
;
1938 fpopup
= g_hash_table_lookup(folderview_popups
, folder
->klass
->idstr
);
1941 action_group
= g_hash_table_lookup(folderview
->popups
, folder
->klass
->idstr
);
1943 fpopup
= g_hash_table_lookup(folderview_popups
, "common");
1944 action_group
= g_hash_table_lookup(folderview
->popups
, "common");
1947 gtk_ui_manager_insert_action_group(ui_manager
, action_group
, 0);
1948 MENUITEM_ADDUI_MANAGER(ui_manager
, "/", "Popup", "Popup", GTK_UI_MANAGER_MENUBAR
)
1949 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup", "FolderViewPopup", "FolderViewPopup", GTK_UI_MANAGER_MENU
)
1951 if (fpopup
->add_menuitems
)
1952 fpopup
->add_menuitems(ui_manager
, item
);
1954 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "MarkAllRead", "FolderViewPopup/MarkAllRead", GTK_UI_MANAGER_MENUITEM
)
1955 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "MarkAllUnread", "FolderViewPopup/MarkAllUnread", GTK_UI_MANAGER_MENUITEM
)
1956 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "MarkAllReadRec", "FolderViewPopup/MarkAllReadRec", GTK_UI_MANAGER_MENUITEM
)
1957 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "MarkAllUnreadRec", "FolderViewPopup/MarkAllUnreadRec", GTK_UI_MANAGER_MENUITEM
)
1958 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "Separator1", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR
)
1959 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "RunProcessing", "FolderViewPopup/RunProcessing", GTK_UI_MANAGER_MENUITEM
)
1960 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "SearchFolder", "FolderViewPopup/SearchFolder", GTK_UI_MANAGER_MENUITEM
)
1961 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "Properties", "FolderViewPopup/Properties", GTK_UI_MANAGER_MENUITEM
)
1962 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "Processing", "FolderViewPopup/Processing", GTK_UI_MANAGER_MENUITEM
)
1964 if (fpopup
->set_sensitivity
!= NULL
)
1965 fpopup
->set_sensitivity(ui_manager
, item
);
1967 if (NULL
!= (ac
= account_find_from_item(item
))) {
1968 special_trash
= account_get_special_folder(ac
, F_TRASH
);
1969 special_queue
= account_get_special_folder(ac
, F_QUEUE
);
1972 if ((item
== folder
->trash
|| item
== special_trash
1973 || folder_has_parent_of_type(item
, F_TRASH
))) {
1974 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "SeparatorTrash", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR
)
1975 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "EmptyTrash", "FolderViewPopup/EmptyTrash", GTK_UI_MANAGER_MENUITEM
)
1978 if ((item
== folder
->queue
|| item
== special_queue
1979 || folder_has_parent_of_type(item
, F_QUEUE
))) {
1980 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "SeparatorQueue", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR
)
1981 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "SendQueue", "FolderViewPopup/SendQueue", GTK_UI_MANAGER_MENUITEM
)
1984 #define SET_SENS(name, sens) \
1985 cm_menu_set_sensitive_full(ui_manager, "Popup/"name, sens)
1987 SET_SENS("FolderViewPopup/MarkAllRead", item
->unread_msgs
> 0);
1988 SET_SENS("FolderViewPopup/MarkAllUnread", (item
->total_msgs
> 0) &&
1989 (item
->unread_msgs
!= (item
->total_msgs
- item
->ignored_msgs
)));
1990 SET_SENS("FolderViewPopup/MarkAllReadRec", folderview_have_unread_children(folderview
,item
));
1991 SET_SENS("FolderViewPopup/MarkAllUnreadRec", folderview_have_read_children(folderview
,item
));
1992 SET_SENS("FolderViewPopup/SearchFolder", item
->total_msgs
> 0 &&
1993 folderview
->selected
== folderview
->opened
);
1994 SET_SENS("FolderViewPopup/Properties", TRUE
);
1996 SET_SENS("FolderViewPopup/RunProcessing", item
->prefs
->processing
&&
1997 item
->total_msgs
>= 1 && !item
->processing_pending
);
1998 SET_SENS("FolderViewPopup/Processing", item
->node
->parent
!= NULL
&&
1999 !item
->no_select
&& !item
->processing_pending
);
2001 if (item
== folder
->trash
|| item
== special_trash
2002 || folder_has_parent_of_type(item
, F_TRASH
)) {
2003 GSList
*msglist
= folder_item_get_msg_list(item
);
2004 SET_SENS("FolderViewPopup/EmptyTrash", msglist
!= NULL
);
2005 procmsg_msg_list_free(msglist
);
2007 if (item
== folder
->queue
|| item
== special_queue
2008 || folder_has_parent_of_type(item
, F_QUEUE
)) {
2009 GSList
*msglist
= folder_item_get_msg_list(item
);
2010 SET_SENS("FolderViewPopup/SendQueue", msglist
!= NULL
);
2011 procmsg_msg_list_free(msglist
);
2015 popup
= gtk_menu_item_get_submenu(GTK_MENU_ITEM(
2016 gtk_ui_manager_get_widget(ui_manager
, "/Popup/FolderViewPopup")) );
2017 g_signal_connect(G_OBJECT(popup
), "selection_done",
2018 G_CALLBACK(folderview_popup_close
),
2020 gtk_menu_popup_at_pointer(GTK_MENU(popup
), NULL
);
2023 static gboolean
folderview_button_pressed(GtkWidget
*ctree
, GdkEventButton
*event
,
2024 FolderView
*folderview
)
2026 GtkCMCList
*clist
= GTK_CMCLIST(ctree
);
2027 gint prev_row
= -1, row
= -1, column
= -1;
2029 if (!event
) return FALSE
;
2030 if (event
->window
!= clist
->clist_window
) return FALSE
;
2032 if (event
->button
== 1 || event
->button
== 2) {
2033 if (!gtk_sctree_is_hot_spot (GTK_SCTREE(clist
), event
->x
, event
->y
))
2034 folderview
->open_folder
= TRUE
;
2036 if (event
->type
== GDK_2BUTTON_PRESS
) {
2037 if (clist
->selection
) {
2038 GtkCMCTreeNode
*node
;
2040 node
= GTK_CMCTREE_NODE(clist
->selection
->data
);
2042 gtk_cmctree_toggle_expansion(
2045 folderview
->open_folder
= FALSE
;
2052 if (event
->button
== 2 || event
->button
== 3) {
2054 if (clist
->selection
) {
2055 GtkCMCTreeNode
*node
;
2057 node
= GTK_CMCTREE_NODE(clist
->selection
->data
);
2059 prev_row
= gtkut_ctree_get_nth_from_node
2060 (GTK_CMCTREE(ctree
), node
);
2063 if (!gtk_cmclist_get_selection_info(clist
, event
->x
, event
->y
,
2066 if (prev_row
!= row
) {
2067 gtk_cmclist_unselect_all(clist
);
2068 if (event
->button
== 2)
2069 folderview_select_node
2071 gtk_cmctree_node_nth(GTK_CMCTREE(ctree
),
2074 gtk_cmclist_select_row(clist
, row
, column
);
2078 if (event
->button
!= 3) return FALSE
;
2080 folderview_set_sens_and_popup_menu(folderview
, row
, event
);
2084 static gboolean
folderview_button_released(GtkWidget
*ctree
, GdkEventButton
*event
,
2085 FolderView
*folderview
)
2087 int row
= -1, column
= -1;
2089 if (!event
) return FALSE
;
2091 if (!gtk_cmclist_get_selection_info(GTK_CMCLIST(ctree
), event
->x
, event
->y
,
2094 if (event
->button
== 1 && folderview
->open_folder
== FALSE
&&
2095 folderview
->opened
!= NULL
) {
2096 gtkut_ctree_set_focus_row(GTK_CMCTREE(ctree
),
2097 folderview
->opened
);
2098 gtk_cmctree_select(GTK_CMCTREE(ctree
), folderview
->opened
);
2104 #define BREAK_ON_MODIFIER_KEY() \
2105 if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0) break
2107 static gboolean
folderview_key_pressed(GtkWidget
*widget
, GdkEventKey
*event
,
2108 FolderView
*folderview
)
2110 GtkCMCTreeNode
*node
;
2113 if (!event
) return FALSE
;
2115 if (quicksearch_has_focus(folderview
->summaryview
->quicksearch
))
2118 switch (event
->keyval
) {
2120 if (folderview
->selected
) {
2121 if (GTK_CMCTREE_ROW(folderview
->selected
)->children
!= NULL
2122 && !GTK_CMCTREE_ROW(folderview
->selected
)->expanded
)
2123 gtk_cmctree_expand(GTK_CMCTREE(folderview
->ctree
),
2124 folderview
->selected
);
2126 folderview_select_node(folderview
,
2127 folderview
->selected
);
2131 case GDK_KEY_Return
:
2132 if (folderview
->selected
&& GTK_CMCTREE_ROW(folderview
->selected
)->children
) {
2133 gtk_cmctree_toggle_expansion(
2134 GTK_CMCTREE(folderview
->ctree
),
2135 folderview
->selected
);
2139 case GDK_KEY_Return
:
2140 case GDK_KEY_KP_Enter
:
2141 if (folderview
->selected
)
2142 folderview_select_node(folderview
, folderview
->selected
);
2146 BREAK_ON_MODIFIER_KEY();
2147 if (folderview
->selected
) {
2148 if (folderview
->opened
== folderview
->selected
&&
2149 (!folderview
->summaryview
->folder_item
||
2150 folderview
->summaryview
->folder_item
->total_msgs
== 0))
2151 folderview_select_next_with_flag(folderview
, MSG_UNREAD
);
2153 folderview_select_node(folderview
,
2154 folderview
->selected
);
2158 if (folderview
->selected
) {
2159 /* If the folder is expanded and can be collapsed, do that... */
2160 if (GTK_CMCTREE_ROW(folderview
->selected
)->expanded
&&
2161 GTK_CMCTREE_ROW(folderview
->selected
)->children
!= NULL
) {
2162 gtk_cmctree_collapse(GTK_CMCTREE(folderview
->ctree
),
2163 folderview
->selected
);
2165 /* ...otherwise, move cursor to its parent node. */
2166 if ((item
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(folderview
->ctree
),
2167 folderview
->selected
))) {
2168 if ((node
= gtk_cmctree_find_by_row_data(GTK_CMCTREE(folderview
->ctree
),
2169 NULL
, folder_item_parent(item
)))) {
2170 gtk_sctree_select(GTK_SCTREE(folderview
->ctree
), node
);
2171 if (!gtk_cmctree_node_is_visible(GTK_CMCTREE(folderview
->ctree
), node
))
2172 gtk_cmctree_node_moveto(GTK_CMCTREE(folderview
->ctree
),
2181 if (event
->keyval
== GDK_KEY_Home
)
2182 node
= gtk_cmctree_node_nth(GTK_CMCTREE(folderview
->ctree
), 0);
2184 node
= gtk_cmctree_last(GTK_CMCTREE(folderview
->ctree
),
2185 gtk_cmctree_node_nth(GTK_CMCTREE(folderview
->ctree
), 0));
2187 gtk_sctree_select(GTK_SCTREE(folderview
->ctree
), node
);
2189 if (!gtk_cmctree_node_is_visible(GTK_CMCTREE(folderview
->ctree
), node
))
2190 gtk_cmctree_node_moveto(GTK_CMCTREE(folderview
->ctree
),
2200 typedef struct _PostponedSelectData
2203 GtkCMCTreeNode
*row
;
2205 FolderView
*folderview
;
2206 } PostponedSelectData
;
2208 static gboolean
postpone_select(void *data
)
2210 PostponedSelectData
*psdata
= (PostponedSelectData
*)data
;
2211 debug_print("trying again\n");
2213 psdata
->folderview
->postpone_select_id
= 0;
2214 psdata
->folderview
->open_folder
= TRUE
;
2215 main_window_cursor_normal(psdata
->folderview
->mainwin
);
2216 STATUSBAR_POP(psdata
->folderview
->mainwin
);
2217 folderview_selected(psdata
->ctree
, psdata
->row
,
2218 psdata
->column
, psdata
->folderview
);
2223 void folderview_close_opened(FolderView
*folderview
, gboolean dirty
)
2225 if (folderview
->opened
) {
2227 folderview
->opened
= NULL
;
2231 FolderItem
*olditem
=
2232 gtk_cmctree_node_get_row_data(GTK_CMCTREE(folderview
->ctree
),
2233 folderview
->opened
);
2235 gchar
*buf
= g_strdup_printf(_("Closing folder %s..."),
2236 olditem
->path
? olditem
->path
:olditem
->name
);
2237 /* will be null if we just moved the previously opened folder */
2238 STATUSBAR_PUSH(folderview
->mainwin
, buf
);
2239 main_window_cursor_wait(folderview
->mainwin
);
2241 summary_save_prefs_to_folderitem(folderview
->summaryview
, olditem
);
2242 summary_show(folderview
->summaryview
, NULL
, FALSE
);
2243 folder_item_close(olditem
);
2244 main_window_cursor_normal(folderview
->mainwin
);
2245 STATUSBAR_POP(folderview
->mainwin
);
2246 if (olditem
->folder
->klass
->item_closed
)
2247 olditem
->folder
->klass
->item_closed(olditem
);
2252 if (folderview
->opened
&&
2253 !GTK_CMCTREE_ROW(folderview
->opened
)->children
)
2254 gtk_cmctree_collapse(GTK_CMCTREE(folderview
->ctree
), folderview
->opened
);
2256 folderview
->opened
= NULL
;
2258 static void folderview_selected(GtkCMCTree
*ctree
, GtkCMCTreeNode
*row
,
2259 gint column
, FolderView
*folderview
)
2261 GdkDisplay
*display
;
2264 static gboolean can_select
= TRUE
; /* exclusive lock */
2269 GtkCMCTreeNode
*old_opened
= folderview
->opened
;
2271 folderview
->selected
= row
;
2273 display
= gdk_display_get_default();
2274 seat
= gdk_display_get_default_seat(display
);
2275 device
= gdk_seat_get_pointer(seat
);
2277 debug_print("newly selected %p, opened %p\n", folderview
->selected
,
2278 folderview
->opened
);
2279 if (folderview
->opened
== row
) {
2280 folderview
->open_folder
= FALSE
;
2285 item
= gtk_cmctree_node_get_row_data(ctree
, row
);
2288 folderview
->open_folder
= FALSE
;
2292 if (!can_select
|| summary_is_locked(folderview
->summaryview
)) {
2293 if (folderview
->opened
) {
2294 gtkut_ctree_set_focus_row(ctree
, folderview
->opened
);
2295 gtk_cmctree_select(ctree
, folderview
->opened
);
2297 folderview
->open_folder
= FALSE
;
2302 if (!folderview
->open_folder
) {
2309 /* Save cache for old folder */
2310 /* We don't want to lose all caches if app crashes */
2311 /* Resets folderview->opened to NULL */
2312 folderview_close_opened(folderview
, FALSE
);
2314 /* CLAWS: set compose button type: news folder items
2315 * always have a news folder as parent */
2317 toolbar_set_compose_button
2318 (folderview
->mainwin
->toolbar
,
2319 FOLDER_TYPE(item
->folder
) == F_NEWS
?
2320 COMPOSEBUTTON_NEWS
: COMPOSEBUTTON_MAIL
);
2323 debug_print("Folder %s is selected\n", item
->path
);
2325 if (!GTK_CMCTREE_ROW(row
)->children
)
2326 gtk_cmctree_expand(ctree
, row
);
2328 /* ungrab the mouse event */
2329 if (gtk_widget_has_grab(GTK_WIDGET(ctree
))) {
2330 gtk_grab_remove(GTK_WIDGET(ctree
));
2331 if (gdk_display_device_is_grabbed(display
, device
))
2332 gdk_seat_ungrab(seat
);
2336 /* TODO: wwp: avoid displaying (null) in the status bar */
2337 buf
= g_strdup_printf(_("Opening folder %s..."), item
->path
?
2338 item
->path
: "(null)");
2339 debug_print("%s\n", buf
);
2340 STATUSBAR_PUSH(folderview
->mainwin
, buf
);
2343 main_window_cursor_wait(folderview
->mainwin
);
2345 if (folderview
->scanning_folder
== item
->folder
) {
2348 res
= folder_item_open(item
);
2351 if (res
== -1 && item
->no_select
== FALSE
) {
2352 main_window_cursor_normal(folderview
->mainwin
);
2353 STATUSBAR_POP(folderview
->mainwin
);
2355 alertpanel_error(_("Folder could not be opened."));
2357 folderview
->open_folder
= FALSE
;
2361 } else if (res
== -2 && item
->no_select
== FALSE
) {
2362 PostponedSelectData
*data
= g_new0(PostponedSelectData
, 1);
2363 data
->ctree
= ctree
;
2365 data
->column
= column
;
2366 data
->folderview
= folderview
;
2367 debug_print("postponing open of %s till end of scan\n",
2368 item
->path
? item
->path
:item
->name
);
2369 folderview
->open_folder
= FALSE
;
2371 if (folderview
->postpone_select_id
!= 0)
2372 g_source_remove(folderview
->postpone_select_id
);
2373 folderview
->postpone_select_id
= g_timeout_add(500, postpone_select
, data
);
2378 main_window_cursor_normal(folderview
->mainwin
);
2381 summary_set_prefs_from_folderitem(folderview
->summaryview
, item
);
2382 opened
= summary_show(folderview
->summaryview
, item
, FALSE
);
2384 folder_clean_cache_memory(item
);
2387 gtkut_ctree_set_focus_row(ctree
, old_opened
);
2388 gtk_cmctree_select(ctree
, old_opened
);
2389 folderview
->opened
= old_opened
;
2391 folderview
->opened
= row
;
2392 if (gtk_cmctree_node_is_visible(ctree
, row
)
2393 != GTK_VISIBILITY_FULL
)
2394 gtk_cmctree_node_moveto(ctree
, row
, -1, 0.5, 0);
2397 STATUSBAR_POP(folderview
->mainwin
);
2399 folderview
->open_folder
= FALSE
;
2404 static void folderview_tree_expanded(GtkCMCTree
*ctree
, GtkCMCTreeNode
*node
,
2405 FolderView
*folderview
)
2409 item
= gtk_cmctree_node_get_row_data(ctree
, node
);
2410 cm_return_if_fail(item
!= NULL
);
2411 item
->collapsed
= FALSE
;
2412 folderview_update_node(folderview
, node
);
2415 static void folderview_tree_collapsed(GtkCMCTree
*ctree
, GtkCMCTreeNode
*node
,
2416 FolderView
*folderview
)
2420 item
= gtk_cmctree_node_get_row_data(ctree
, node
);
2421 cm_return_if_fail(item
!= NULL
);
2422 item
->collapsed
= TRUE
;
2423 folderview_update_node(folderview
, node
);
2426 static void folderview_popup_close(GtkMenuShell
*menu_shell
,
2427 FolderView
*folderview
)
2429 if (!folderview
->opened
) return;
2431 gtk_cmctree_select(GTK_CMCTREE(folderview
->ctree
), folderview
->opened
);
2434 static void folderview_col_resized(GtkCMCList
*clist
, gint column
, gint width
,
2435 FolderView
*folderview
)
2437 FolderColumnType type
= folderview
->col_state
[column
].type
;
2439 prefs_common
.folder_col_size
[type
] = width
;
2442 static void folderview_create_folder_node(FolderView
*folderview
, FolderItem
*item
)
2444 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
2445 gchar
*text
[N_FOLDER_COLS
] = {NULL
, "0", "0", "0"};
2446 GtkCMCTreeNode
*node
, *parent_node
;
2447 gint
*col_pos
= folderview
->col_pos
;
2448 FolderItemUpdateData hookdata
;
2450 parent_node
= gtk_cmctree_find_by_row_data(ctree
, NULL
, folder_item_parent(item
));
2451 if (parent_node
== NULL
)
2454 gtk_cmclist_freeze(GTK_CMCLIST(ctree
));
2456 text
[col_pos
[F_COL_FOLDER
]] = item
->name
;
2457 node
= gtk_sctree_insert_node(ctree
, parent_node
, NULL
, text
,
2462 gtk_cmctree_expand(ctree
, parent_node
);
2463 gtk_cmctree_node_set_row_data(ctree
, node
, item
);
2464 folderview_sort_folders(folderview
, parent_node
, item
->folder
);
2466 hookdata
.item
= item
;
2467 hookdata
.update_flags
= F_ITEM_UPDATE_NAME
;
2468 hookdata
.msg
= NULL
;
2469 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST
, &hookdata
);
2471 gtk_cmclist_thaw(GTK_CMCLIST(ctree
));
2474 static void folderview_empty_trash_cb(GtkAction
*action
, gpointer data
)
2476 FolderView
*folderview
= (FolderView
*)data
;
2478 GSList
*mlist
= NULL
;
2480 FolderItem
*special_trash
= NULL
;
2483 if (!folderview
->selected
) return;
2484 item
= folderview_get_selected_item(folderview
);
2485 cm_return_if_fail(item
!= NULL
);
2486 cm_return_if_fail(item
->folder
!= NULL
);
2488 if (NULL
!= (ac
= account_find_from_item(item
)))
2489 special_trash
= account_get_special_folder(ac
, F_TRASH
);
2491 if (item
!= item
->folder
->trash
&& item
!= special_trash
2492 && !folder_has_parent_of_type(item
, F_TRASH
)) return;
2494 if (prefs_common
.ask_on_clean
) {
2495 if (alertpanel(_("Empty trash"),
2496 _("Delete all messages in trash?"),
2497 NULL
, _("_Cancel"), NULL
, _("_Empty trash"), NULL
, NULL
,
2498 ALERTFOCUS_SECOND
) != G_ALERTALTERNATE
)
2502 mlist
= folder_item_get_msg_list(item
);
2504 for (cur
= mlist
; cur
!= NULL
; cur
= cur
->next
) {
2505 MsgInfo
* msginfo
= (MsgInfo
*) cur
->data
;
2506 if (MSG_IS_LOCKED(msginfo
->flags
))
2508 /* is it partially received? (partial_recv isn't cached) */
2509 if (msginfo
->total_size
!= 0 &&
2510 msginfo
->size
!= (off_t
)msginfo
->total_size
)
2511 partial_mark_for_delete(msginfo
);
2513 procmsg_msg_list_free(mlist
);
2515 folder_item_remove_all_msg(item
);
2518 static void folderview_send_queue_cb(GtkAction
*action
, gpointer data
)
2520 FolderView
*folderview
= (FolderView
*)data
;
2522 FolderItem
*special_queue
= NULL
;
2524 gchar
*errstr
= NULL
;
2526 if (!folderview
->selected
) return;
2527 item
= folderview_get_selected_item(folderview
);
2528 cm_return_if_fail(item
!= NULL
);
2529 cm_return_if_fail(item
->folder
!= NULL
);
2531 if (NULL
!= (ac
= account_find_from_item(item
)))
2532 special_queue
= account_get_special_folder(ac
, F_QUEUE
);
2534 if (item
!= item
->folder
->queue
&& item
!= special_queue
2535 && !folder_has_parent_of_type(item
, F_QUEUE
)) return;
2537 if (procmsg_queue_is_empty(item
))
2540 if (prefs_common
.work_offline
)
2541 if (alertpanel(_("Offline warning"),
2542 _("You're working offline. Override?"),
2543 NULL
, _("_No"), NULL
, _("_Yes"),
2544 NULL
, NULL
, ALERTFOCUS_FIRST
) != G_ALERTALTERNATE
)
2547 /* ask for confirmation before sending queued messages only
2548 in online mode and if there is at least one message queued
2549 in any of the folder queue
2551 if (prefs_common
.confirm_send_queued_messages
) {
2552 if (!prefs_common
.work_offline
) {
2553 if (alertpanel(_("Send queued messages"),
2554 _("Send all queued messages?"),
2555 NULL
, _("_Cancel"), NULL
, _("_Send"),
2556 NULL
, NULL
, ALERTFOCUS_FIRST
) != G_ALERTALTERNATE
)
2561 if (procmsg_send_queue(item
, prefs_common
.savemsg
, &errstr
) < 0) {
2563 alertpanel_error_log(_("Some errors occurred while "
2564 "sending queued messages."));
2566 alertpanel_error_log(_("Some errors occurred "
2567 "while sending queued messages:\n%s"), errstr
);
2573 static void folderview_search_cb(GtkAction
*action
, gpointer data
)
2575 FolderView
*folderview
= (FolderView
*)data
;
2576 summary_search(folderview
->summaryview
);
2579 static void folderview_run_processing_cb(GtkAction
*action
, gpointer data
)
2581 FolderView
*folderview
= (FolderView
*)data
;
2584 if (!folderview
->selected
) return;
2586 item
= folderview_get_selected_item(folderview
);
2588 folderview_run_processing(item
);
2591 void folderview_run_processing(FolderItem
*item
)
2593 cm_return_if_fail(item
!= NULL
);
2594 cm_return_if_fail(item
->folder
!= NULL
);
2596 item
->processing_pending
= TRUE
;
2597 folder_item_apply_processing(item
);
2598 item
->processing_pending
= FALSE
;
2601 static void folderview_property_cb(GtkAction
*action
, gpointer data
)
2603 FolderView
*folderview
= (FolderView
*)data
;
2606 if (!folderview
->selected
) return;
2608 item
= folderview_get_selected_item(folderview
);
2609 cm_return_if_fail(item
!= NULL
);
2610 cm_return_if_fail(item
->folder
!= NULL
);
2612 prefs_folder_item_open(item
);
2615 static void folderview_recollapse_nodes(FolderView
*folderview
, GtkCMCTreeNode
*node
)
2617 GSList
*list
= NULL
;
2618 GSList
*done
= NULL
;
2619 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
2621 for (list
= folderview
->nodes_to_recollapse
; list
!= NULL
; list
= g_slist_next(list
)) {
2622 if (!gtkut_ctree_node_is_parent(GTK_CMCTREE_NODE(list
->data
), node
)
2623 && list
->data
!= node
) {
2624 gtk_cmctree_collapse(ctree
, GTK_CMCTREE_NODE(list
->data
));
2625 done
= g_slist_append(done
, GTK_CMCTREE_NODE(list
->data
));
2628 for (list
= done
; list
!= NULL
; list
= g_slist_next(list
)) {
2629 folderview
->nodes_to_recollapse
= g_slist_remove(folderview
->nodes_to_recollapse
,
2635 void folderview_move_folder(FolderView
*folderview
, FolderItem
*from_folder
,
2636 FolderItem
*to_folder
, gboolean copy
)
2638 FolderItem
*new_folder
= NULL
;
2642 cm_return_if_fail(folderview
!= NULL
);
2643 cm_return_if_fail(from_folder
!= NULL
);
2644 cm_return_if_fail(to_folder
!= NULL
);
2646 if (prefs_common
.warn_dnd
) {
2647 buf
= g_strdup_printf(copy
? _("Do you really want to copy folder '%s' in '%s'?"):
2648 _("Do you really want to make folder '%s' a subfolder of '%s'?"),
2649 from_folder
->name
, to_folder
->name
);
2650 status
= alertpanel_full(copy
? _("Copy folder"):_("Move folder"), buf
,
2651 NULL
, _("_No"), NULL
, _("_Yes"), NULL
, NULL
,
2652 ALERTFOCUS_FIRST
, TRUE
, NULL
, ALERT_QUESTION
);
2655 if ((status
& ~G_ALERTDISABLE
) != G_ALERTALTERNATE
)
2657 else if (status
& G_ALERTDISABLE
)
2658 prefs_common
.warn_dnd
= FALSE
;
2661 buf
= g_strdup_printf(copy
? _("Copying %s to %s..."):_("Moving %s to %s..."),
2662 from_folder
->name
, to_folder
->name
);
2663 STATUSBAR_PUSH(folderview
->mainwin
, buf
);
2665 summary_clear_all(folderview
->summaryview
);
2666 folderview
->opened
= NULL
;
2667 folderview
->selected
= NULL
;
2668 gtk_widget_set_sensitive(GTK_WIDGET(folderview
->ctree
), FALSE
);
2670 main_window_cursor_wait(folderview
->mainwin
);
2672 statusbar_verbosity_set(FALSE
);
2673 folder_item_update_freeze();
2674 gtk_cmclist_freeze(GTK_CMCLIST(folderview
->ctree
));
2675 if ((status
= folder_item_move_to(from_folder
, to_folder
, &new_folder
, copy
)) == F_MOVE_OK
) {
2676 statusbar_verbosity_set(FALSE
);
2677 main_window_cursor_normal(folderview
->mainwin
);
2678 STATUSBAR_POP(folderview
->mainwin
);
2679 folder_item_update_thaw();
2680 folder_item_update_recursive(new_folder
, F_ITEM_UPDATE_MSGCNT
);
2682 folderview_sort_folders(folderview
,
2683 gtk_cmctree_find_by_row_data(GTK_CMCTREE(folderview
->ctree
),
2684 NULL
, to_folder
), new_folder
->folder
);
2685 folderview_select(folderview
, new_folder
);
2686 gtk_cmclist_thaw(GTK_CMCLIST(folderview
->ctree
));
2688 statusbar_verbosity_set(FALSE
);
2689 main_window_cursor_normal(folderview
->mainwin
);
2690 STATUSBAR_POP(folderview
->mainwin
);
2691 gtk_cmclist_thaw(GTK_CMCLIST(folderview
->ctree
));
2692 folder_item_update_thaw();
2694 case F_MOVE_FAILED_DEST_IS_PARENT
:
2695 alertpanel_error(_("Source and destination are the same."));
2697 case F_MOVE_FAILED_DEST_IS_CHILD
:
2698 alertpanel_error(copy
? _("Can't copy a folder to one of its children."):
2699 _("Can't move a folder to one of its children."));
2701 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX
:
2702 alertpanel_error(_("A folder cannot be moved between different mailboxes."));
2705 alertpanel_error(copy
? _("Copy failed!"):_("Move failed!"));
2710 gtk_widget_set_sensitive(GTK_WIDGET(folderview
->ctree
), TRUE
);
2713 static gint
folderview_clist_compare(GtkCMCList
*clist
,
2714 gconstpointer ptr1
, gconstpointer ptr2
)
2716 FolderItem
*item1
= ((GtkCMCListRow
*)ptr1
)->data
;
2717 FolderItem
*item2
= ((GtkCMCListRow
*)ptr2
)->data
;
2719 if (item1
->order
> 0 && item2
->order
> 0) // if we have an order item, use it
2721 return item1
->order
- item2
->order
;
2724 // if only one folder has an order it comes first
2725 if (item1
->order
> 0)
2729 if (item2
->order
> 0)
2735 return (item2
->name
!= NULL
);
2739 return g_utf8_collate(item1
->name
, item2
->name
);
2742 static void folderview_processing_cb(GtkAction
*action
, gpointer data
)
2744 FolderView
*folderview
= (FolderView
*)data
;
2748 if (!folderview
->selected
) return;
2750 item
= folderview_get_selected_item(folderview
);
2751 cm_return_if_fail(item
!= NULL
);
2752 cm_return_if_fail(item
->folder
!= NULL
);
2754 id
= folder_item_get_identifier(item
);
2755 title
= g_strdup_printf (_("Processing configuration for folder %s"), id
);
2758 prefs_filtering_open(&item
->prefs
->processing
, title
,
2759 MANUAL_ANCHOR_PROCESSING
, NULL
, NULL
, FALSE
);
2763 void folderview_set_target_folder_color(GdkRGBA color_op
)
2766 FolderView
*folderview
;
2768 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
) {
2769 folderview
= (FolderView
*)list
->data
;
2770 folderview
->color_op
= color_op
;
2774 static gchar
*last_smallfont
= NULL
;
2775 static gchar
*last_normalfont
= NULL
;
2776 static gchar
*last_boldfont
= NULL
;
2777 static gboolean last_derive
= 0;
2779 void folderview_reinit_fonts(FolderView
*folderview
)
2782 g_free(last_smallfont
);
2783 last_smallfont
= NULL
;
2784 g_free(last_normalfont
);
2785 last_normalfont
= NULL
;
2786 g_free(last_boldfont
);
2787 last_boldfont
= NULL
;
2790 void folderview_reflect_prefs(void)
2792 gboolean update_font
= FALSE
;
2793 FolderView
*folderview
= mainwindow_get_mainwindow()->folderview
;
2794 FolderItem
*item
= folderview_get_selected_item(folderview
);
2795 GtkAdjustment
*pos
= gtk_scrolled_window_get_vadjustment(
2796 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
2797 gint height
= gtk_adjustment_get_value(pos
);
2799 folderview
->color_new
= prefs_common
.color
[COL_NEW
];
2800 folderview
->color_op
= prefs_common
.color
[COL_TGT_FOLDER
];
2802 if (!last_smallfont
|| strcmp(last_smallfont
, SMALL_FONT
) ||
2803 !last_normalfont
|| strcmp(last_normalfont
, NORMAL_FONT
) ||
2804 !last_boldfont
|| strcmp(last_boldfont
, BOLD_FONT
) ||
2805 last_derive
!= prefs_common
.derive_from_normal_font
)
2811 g_free(last_smallfont
);
2812 last_smallfont
= g_strdup(SMALL_FONT
);
2813 g_free(last_normalfont
);
2814 last_normalfont
= g_strdup(NORMAL_FONT
);
2815 g_free(last_boldfont
);
2816 last_boldfont
= g_strdup(BOLD_FONT
);
2817 last_derive
= prefs_common
.derive_from_normal_font
;
2819 folderview_set_fonts(folderview
);
2821 gtk_cmclist_freeze(GTK_CMCLIST(folderview
->ctree
));
2822 folderview_column_set_titles(folderview
);
2823 folderview_set_all();
2825 g_signal_handlers_block_by_func
2826 (G_OBJECT(folderview
->ctree
),
2827 G_CALLBACK(folderview_selected
), folderview
);
2830 GtkCMCTreeNode
*node
= gtk_cmctree_find_by_row_data(
2831 GTK_CMCTREE(folderview
->ctree
), NULL
, item
);
2833 folderview_select(folderview
, item
);
2834 folderview
->open_folder
= FALSE
;
2835 folderview
->selected
= node
;
2838 g_signal_handlers_unblock_by_func
2839 (G_OBJECT(folderview
->ctree
),
2840 G_CALLBACK(folderview_selected
), folderview
);
2842 pos
= gtk_scrolled_window_get_vadjustment(
2843 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
2844 gtk_adjustment_set_value(pos
, height
);
2845 gtk_cmclist_thaw(GTK_CMCLIST(folderview
->ctree
));
2848 static void drag_state_stop(FolderView
*folderview
)
2850 if (folderview
->drag_timer_id
)
2851 g_source_remove(folderview
->drag_timer_id
);
2852 folderview
->drag_timer_id
= 0;
2853 folderview
->drag_node
= NULL
;
2856 static gboolean
folderview_defer_expand(FolderView
*folderview
)
2858 if (folderview
->drag_node
) {
2859 folderview_recollapse_nodes(folderview
, folderview
->drag_node
);
2860 if (folderview
->drag_item
->collapsed
) {
2861 gtk_cmctree_expand(GTK_CMCTREE(folderview
->ctree
), folderview
->drag_node
);
2862 folderview
->nodes_to_recollapse
= g_slist_append
2863 (folderview
->nodes_to_recollapse
, folderview
->drag_node
);
2866 folderview
->drag_item
= NULL
;
2867 folderview
->drag_timer_id
= 0;
2871 static void drag_state_start(FolderView
*folderview
, GtkCMCTreeNode
*node
, FolderItem
*item
)
2873 /* the idea is that we call drag_state_start() whenever we want expansion to
2874 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2875 * we need to call drag_state_stop() */
2876 drag_state_stop(folderview
);
2877 /* request expansion */
2878 if (0 != (folderview
->drag_timer_id
= g_timeout_add
2879 (prefs_common
.hover_timeout
,
2880 (GSourceFunc
)folderview_defer_expand
,
2882 folderview
->drag_node
= node
;
2883 folderview
->drag_item
= item
;
2886 #ifndef GENERIC_UMPC
2887 static void folderview_start_drag(GtkWidget
*widget
, gint button
, GdkEvent
*event
,
2888 FolderView
*folderview
)
2890 GdkDragContext
*context
;
2892 cm_return_if_fail(folderview
!= NULL
);
2893 if (folderview
->selected
== NULL
) return;
2894 if (folderview
->nodes_to_recollapse
)
2895 g_slist_free(folderview
->nodes_to_recollapse
);
2896 folderview
->nodes_to_recollapse
= NULL
;
2897 context
= gtk_drag_begin_with_coordinates(widget
, folderview
->target_list
,
2898 GDK_ACTION_MOVE
|GDK_ACTION_COPY
|GDK_ACTION_DEFAULT
, button
, event
,
2900 gtk_drag_set_icon_default(context
);
2903 static void folderview_drag_data_get(GtkWidget
*widget
,
2904 GdkDragContext
*drag_context
,
2905 GtkSelectionData
*selection_data
,
2908 FolderView
*folderview
)
2912 if (info
== TARGET_DUMMY
) {
2913 sel
= GTK_CMCLIST(folderview
->ctree
)->selection
;
2917 item
= gtk_cmctree_node_get_row_data
2918 (GTK_CMCTREE(folderview
->ctree
),
2919 GTK_CMCTREE_NODE(sel
->data
));
2921 gchar
*source
= NULL
;
2922 gchar
*name
= folder_item_get_identifier(item
);
2923 source
= g_strdup_printf ("FROM_OTHER_FOLDER%s", name
);
2925 gtk_selection_data_set(selection_data
,
2926 gtk_selection_data_get_target(selection_data
), 8,
2927 source
, strlen(source
));
2930 g_warning("unknown info %d", info
);
2934 static gboolean
folderview_update_folder(gpointer source
, gpointer userdata
)
2936 FolderUpdateData
*hookdata
;
2937 FolderView
*folderview
;
2941 folderview
= (FolderView
*) userdata
;
2942 cm_return_val_if_fail(hookdata
!= NULL
, FALSE
);
2943 cm_return_val_if_fail(folderview
!= NULL
, FALSE
);
2945 ctree
= folderview
->ctree
;
2946 cm_return_val_if_fail(ctree
!= NULL
, FALSE
);
2948 if (hookdata
->update_flags
& FOLDER_ADD_FOLDERITEM
)
2949 folderview_create_folder_node(folderview
, hookdata
->item
);
2950 else if (hookdata
->update_flags
& FOLDER_RENAME_FOLDERITEM
) {
2951 GtkCMCTreeNode
*node
= gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree
),
2952 NULL
, folder_item_parent(hookdata
->item
));
2953 folderview_sort_folders(folderview
, node
, hookdata
->folder
);
2954 } else if (hookdata
->update_flags
& FOLDER_REMOVE_FOLDERITEM
) {
2955 GtkCMCTreeNode
*node
;
2957 node
= gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree
), NULL
, hookdata
->item
);
2959 gtk_cmctree_remove_node(GTK_CMCTREE(ctree
), node
);
2960 if (folderview
->selected
== node
)
2961 folderview
->selected
= NULL
;
2962 if (folderview
->opened
== node
)
2963 folderview
->opened
= NULL
;
2965 } else if (hookdata
->update_flags
& FOLDER_MOVE_FOLDERITEM
) {
2966 /* do nothing, it's done by the ADD and REMOVE) */
2967 } else if (hookdata
->update_flags
& (FOLDER_TREE_CHANGED
| FOLDER_ADD_FOLDER
| FOLDER_REMOVE_FOLDER
))
2968 folderview_set(folderview
);
2973 static gboolean
folderview_dnd_scroll_cb(gpointer data
)
2975 FolderView
*folderview
= (FolderView
*)data
;
2976 GtkAdjustment
*pos
= gtk_scrolled_window_get_vadjustment(
2977 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
2978 gint new_val
= (int)gtk_adjustment_get_value(pos
) + folderview
->scroll_value
;
2979 gint max
= (int)gtk_adjustment_get_upper(pos
) -
2980 (int)gtk_adjustment_get_page_size(pos
);
2982 if (folderview
->scroll_value
== 0) {
2983 folderview
->scroll_timeout_id
= 0;
2987 if (folderview
->scroll_value
> 0 && new_val
> max
) {
2989 } else if (folderview
->scroll_value
< 0 && new_val
< 0) {
2992 gtk_adjustment_set_value(pos
, new_val
);
2997 static gboolean
folderview_drag_motion_cb(GtkWidget
*widget
,
2998 GdkDragContext
*context
,
3002 FolderView
*folderview
)
3005 FolderItem
*item
= NULL
, *src_item
= NULL
;
3006 GtkCMCTreeNode
*node
= NULL
;
3007 gboolean acceptable
= FALSE
;
3008 GtkAdjustment
*pos
= gtk_scrolled_window_get_vadjustment(
3009 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
3010 int height
= (int)gtk_adjustment_get_page_size(pos
);
3011 int total_height
= (int)gtk_adjustment_get_upper(pos
);
3012 int vpos
= (int)gtk_adjustment_get_value(pos
);
3013 int offset
= prefs_common
.show_col_headers
? 24:0;
3016 if (gtk_cmclist_get_selection_info
3017 (GTK_CMCLIST(widget
), x
- offset
, y
- offset
, &row
, &column
)) {
3018 GtkWidget
*srcwidget
;
3020 if (y
> height
- (48 - offset
) && height
+ vpos
< total_height
) {
3021 dist
= -(height
- (48 - offset
) - y
);
3022 folderview
->scroll_value
= 1.41f
* (1+(dist
/ 6));
3023 } else if (y
< 72 - (24 - offset
) && y
>= 0) {
3024 dist
= 72 - (24 - offset
) - y
;
3025 folderview
->scroll_value
= -1.41f
* (1+(dist
/ 6));
3027 folderview
->scroll_value
= 0;
3029 if (folderview
->scroll_value
!= 0 && folderview
->scroll_timeout_id
== 0) {
3030 folderview
->scroll_timeout_id
=
3031 g_timeout_add(30, folderview_dnd_scroll_cb
,
3035 node
= gtk_cmctree_node_nth(GTK_CMCTREE(widget
), row
);
3036 item
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget
), node
);
3037 src_item
= folderview
->summaryview
->folder_item
;
3039 srcwidget
= gtk_drag_get_source_widget(context
);
3040 if (srcwidget
== summary_get_main_widget(folderview
->summaryview
)) {
3041 /* comes from summaryview */
3042 /* we are copying messages, so only accept folder items that are not
3043 the source item, are no root items and can copy messages */
3044 if (item
&& item
->folder
&& folder_item_parent(item
) != NULL
&& src_item
&&
3045 src_item
!= item
&& FOLDER_CLASS(item
->folder
)->copy_msg
!= NULL
&&
3046 FOLDER_TYPE(item
->folder
) != F_UNKNOWN
)
3048 } else if (srcwidget
== folderview
->ctree
) {
3049 /* comes from folderview */
3050 /* we are moving folder items, only accept folders that are not
3051 the source items and can copy messages and create folder items */
3052 if (item
&& item
->folder
&& src_item
&& src_item
!= item
&&
3053 FOLDER_CLASS(item
->folder
)->copy_msg
!= NULL
&&
3054 FOLDER_CLASS(item
->folder
)->create_folder
!= NULL
&&
3055 ((FOLDER_TYPE(item
->folder
) != F_UNKNOWN
&& FOLDER_TYPE(src_item
->folder
) != F_UNKNOWN
)
3056 || item
->folder
== src_item
->folder
))
3059 /* comes from another app */
3060 /* we are adding messages, so only accept folder items that are
3061 no root items and can copy messages */
3062 if (item
&& item
->folder
&& folder_item_parent(item
) != NULL
3063 && FOLDER_CLASS(item
->folder
)->add_msg
!= NULL
&&
3064 FOLDER_TYPE(item
->folder
) != F_UNKNOWN
)
3069 if (acceptable
|| (src_item
&& src_item
== item
))
3070 drag_state_start(folderview
, node
, item
);
3073 g_signal_handlers_block_by_func
3075 G_CALLBACK(folderview_selected
), folderview
);
3076 gtk_cmctree_select(GTK_CMCTREE(widget
), node
);
3077 g_signal_handlers_unblock_by_func
3079 G_CALLBACK(folderview_selected
), folderview
);
3080 gdk_drag_status(context
,
3081 (gdk_drag_context_get_actions(context
) == GDK_ACTION_COPY
?
3082 GDK_ACTION_COPY
: GDK_ACTION_MOVE
) , time
);
3084 if (folderview
->opened
)
3085 gtk_cmctree_select(GTK_CMCTREE(widget
), folderview
->opened
);
3086 gdk_drag_status(context
, 0, time
);
3092 static void folderview_drag_leave_cb(GtkWidget
*widget
,
3093 GdkDragContext
*context
,
3095 FolderView
*folderview
)
3097 drag_state_stop(folderview
);
3098 folderview
->scroll_value
= 0;
3099 gtk_cmctree_select(GTK_CMCTREE(widget
), folderview
->opened
);
3102 static void free_info (gpointer stuff
, gpointer data
)
3107 void folderview_finish_dnd(const gchar
*data
, GdkDragContext
*drag_context
,
3108 guint time
, FolderItem
*item
)
3111 GSList
*msglist
= NULL
;
3112 list
= uri_list_extract_filenames(data
);
3113 if (!(item
&& item
->folder
&& folder_item_parent(item
) != NULL
3114 && FOLDER_CLASS(item
->folder
)->add_msg
!= NULL
))
3116 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3117 debug_print("item doesn't fit\n");
3121 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3122 debug_print("list is empty\n");
3125 for (tmp
= list
; tmp
!= NULL
; tmp
= tmp
->next
) {
3126 MsgFileInfo
*info
= NULL
;
3128 if (file_is_email((gchar
*)tmp
->data
)) {
3129 info
= g_new0(MsgFileInfo
, 1);
3130 info
->msginfo
= NULL
;
3131 info
->file
= (gchar
*)tmp
->data
;
3132 msglist
= g_slist_prepend(msglist
, info
);
3133 debug_print("file is a mail\n");
3135 debug_print("file isn't a mail\n");
3139 msglist
= g_slist_reverse(msglist
);
3140 folder_item_add_msgs(item
, msglist
, FALSE
);
3141 g_slist_foreach(msglist
, free_info
, NULL
);
3142 g_slist_free(msglist
);
3143 gtk_drag_finish(drag_context
, TRUE
, FALSE
, time
);
3145 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3147 list_free_strings_full(list
);
3150 static void folderview_drag_received_cb(GtkWidget
*widget
,
3151 GdkDragContext
*drag_context
,
3154 GtkSelectionData
*data
,
3157 FolderView
*folderview
)
3160 FolderItem
*item
= NULL
, *src_item
;
3161 GtkCMCTreeNode
*node
;
3162 int offset
= prefs_common
.show_col_headers
? 24:0;
3164 folderview
->scroll_value
= 0;
3166 if (info
== TARGET_DUMMY
) {
3167 drag_state_stop(folderview
);
3168 const gchar
*ddata
= (const gchar
*)gtk_selection_data_get_data(data
);
3169 if ((gchar
*)strstr(ddata
, "FROM_OTHER_FOLDER") != ddata
) {
3170 /* comes from summaryview */
3171 if (gtk_cmclist_get_selection_info
3172 (GTK_CMCLIST(widget
), x
- offset
, y
- offset
, &row
, &column
) == 0)
3175 node
= gtk_cmctree_node_nth(GTK_CMCTREE(widget
), row
);
3176 item
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget
), node
);
3177 src_item
= folderview
->summaryview
->folder_item
;
3179 if (item
&& item
->no_select
) {
3180 alertpanel_error(_("The destination folder can only be used to "
3181 "store subfolders."));
3184 /* re-check (due to acceptable possibly set for folder moves */
3185 if (!(item
&& item
->folder
&& item
->path
&& !item
->no_select
&&
3186 src_item
&& src_item
!= item
&& FOLDER_CLASS(item
->folder
)->copy_msg
!= NULL
)) {
3190 switch (gdk_drag_context_get_selected_action(drag_context
)) {
3191 case GDK_ACTION_COPY
:
3192 summary_copy_selected_to(folderview
->summaryview
, item
);
3193 gtk_drag_finish(drag_context
, TRUE
, FALSE
, time
);
3195 case GDK_ACTION_MOVE
:
3196 case GDK_ACTION_DEFAULT
:
3198 if (FOLDER_CLASS(src_item
->folder
)->remove_msg
== NULL
)
3199 summary_copy_selected_to(folderview
->summaryview
, item
);
3201 summary_move_selected_to(folderview
->summaryview
, item
);
3202 gtk_drag_finish(drag_context
, TRUE
, TRUE
, time
);
3205 /* comes from folderview */
3207 gboolean folder_is_normal
= TRUE
;
3208 gboolean copy
= (GDK_ACTION_COPY
==
3209 gdk_drag_context_get_selected_action(drag_context
));
3211 source
= (char *)gtk_selection_data_get_data(data
) + 17;
3212 if (gtk_cmclist_get_selection_info
3213 (GTK_CMCLIST(widget
), x
- offset
, y
- offset
, &row
, &column
) == 0
3215 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3218 node
= gtk_cmctree_node_nth(GTK_CMCTREE(widget
), row
);
3219 item
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget
), node
);
3220 src_item
= folder_find_item_from_identifier(source
);
3224 src_item
->stype
== F_NORMAL
&&
3225 !folder_has_parent_of_type(src_item
, F_OUTBOX
) &&
3226 !folder_has_parent_of_type(src_item
, F_DRAFT
) &&
3227 !folder_has_parent_of_type(src_item
, F_QUEUE
) &&
3228 !folder_has_parent_of_type(src_item
, F_TRASH
);
3229 if (!item
|| !src_item
|| !folder_is_normal
) {
3230 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3234 folderview_move_folder(folderview
, src_item
, item
, copy
);
3235 gtk_drag_finish(drag_context
, TRUE
, TRUE
, time
);
3237 folderview
->nodes_to_recollapse
= NULL
;
3238 } else if (info
== TARGET_MAIL_URI_LIST
) {
3239 if (gtk_cmclist_get_selection_info
3240 (GTK_CMCLIST(widget
), x
- offset
, y
- offset
, &row
, &column
) == 0)
3243 node
= gtk_cmctree_node_nth(GTK_CMCTREE(widget
), row
);
3245 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3246 debug_print("no node\n");
3249 item
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget
), node
);
3251 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3252 debug_print("no item\n");
3255 folderview_finish_dnd(gtk_selection_data_get_data(data
),
3256 drag_context
, time
, item
);
3260 static void folderview_drag_end_cb(GtkWidget
*widget
,
3261 GdkDragContext
*drag_context
,
3262 FolderView
*folderview
)
3264 drag_state_stop(folderview
);
3265 folderview
->scroll_value
= 0;
3266 g_slist_free(folderview
->nodes_to_recollapse
);
3267 folderview
->nodes_to_recollapse
= NULL
;
3270 void folderview_register_popup(FolderViewPopup
*fpopup
)
3274 for (folderviews
= folderview_list
; folderviews
!= NULL
; folderviews
= g_list_next(folderviews
)) {
3275 FolderView
*folderview
= folderviews
->data
;
3276 GtkActionGroup
*factory
;
3278 factory
= create_action_group(folderview
, fpopup
);
3279 g_hash_table_insert(folderview
->popups
, fpopup
->klass
, factory
);
3281 g_hash_table_insert(folderview_popups
, fpopup
->klass
, fpopup
);
3284 void folderview_unregister_popup(FolderViewPopup
*fpopup
)
3289 for (folderviews
= folderview_list
; folderviews
!= NULL
; folderviews
= g_list_next(folderviews
)) {
3290 FolderView
*folderview
= folderviews
->data
;
3292 g_hash_table_remove(folderview
->popups
, fpopup
->klass
);
3294 g_hash_table_remove(folderview_popups
, fpopup
->klass
);
3297 void folderview_remove_item(FolderView
*folderview
, FolderItem
*item
)
3299 g_return_if_fail(folderview
!= NULL
);
3300 g_return_if_fail(item
!= NULL
);
3302 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
3303 g_return_if_fail(ctree
!= NULL
);
3305 GtkCMCTreeNode
*node
=
3306 gtk_cmctree_find_by_row_data(ctree
, NULL
, item
);
3307 g_return_if_fail(node
!= NULL
);
3309 gtk_cmctree_remove_node(ctree
, node
);
3312 void folderview_freeze(FolderView
*folderview
)
3315 gtk_cmclist_freeze(GTK_CMCLIST(folderview
->ctree
));
3318 void folderview_thaw(FolderView
*folderview
)
3321 gtk_cmclist_thaw(GTK_CMCLIST(folderview
->ctree
));
3324 void folderview_grab_focus(FolderView
*folderview
)
3327 gtk_widget_grab_focus(folderview
->ctree
);
3330 static void folderview_header_set_displayed_columns_cb(GtkAction
*gaction
,
3333 prefs_folder_column_open();
3336 static gboolean
folderview_header_button_pressed(GtkWidget
*widget
,
3340 GdkEventButton
*event
= (GdkEventButton
*)_event
;
3341 FolderView
*folderview
= (FolderView
*)user_data
;
3343 cm_return_val_if_fail(folderview
!= NULL
, FALSE
);
3345 /* Only handle single button presses. */
3346 if (event
->type
== GDK_2BUTTON_PRESS
||
3347 event
->type
== GDK_3BUTTON_PRESS
)
3350 /* Handle right-click for context menu */
3351 if (event
->button
== 3) {
3352 gtk_menu_popup_at_pointer(GTK_MENU(folderview
->headerpopupmenu
), NULL
);