2 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2019 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/>.
22 #include <glib/gi18n.h>
23 #include <gdk/gdkkeysyms.h>
30 #include "mainwindow.h"
31 #include "folderview.h"
32 #include "summaryview.h"
33 #include "summary_search.h"
34 #include "inputdialog.h"
35 #include "manage_window.h"
36 #include "alertpanel.h"
38 #include "stock_pixmap.h"
42 #include "prefs_common.h"
43 #include "prefs_account.h"
44 #include "prefs_filtering.h"
45 #include "prefs_folder_item.h"
48 #include "foldersel.h"
50 #include "statusbar.h"
52 #include "folderutils.h"
53 #include "partial_download.h"
54 #include "prefs_folder_column.h"
55 #include "filtering.h"
56 #include "quicksearch.h"
60 #include "gtkcmctree.h"
62 #define COL_FOLDER_WIDTH 150
63 #define COL_NUM_WIDTH 32
65 static GList
*folderview_list
= NULL
;
67 static GtkStyle
*bold_style
;
69 static GdkPixbuf
*inboxxpm
;
70 static GdkPixbuf
*inboxhrmxpm
;
71 static GdkPixbuf
*inboxopenxpm
;
72 static GdkPixbuf
*inboxopenhrmxpm
;
73 static GdkPixbuf
*outboxxpm
;
74 static GdkPixbuf
*outboxhrmxpm
;
75 static GdkPixbuf
*outboxopenxpm
;
76 static GdkPixbuf
*outboxopenhrmxpm
;
77 static GdkPixbuf
*folderxpm
;
78 static GdkPixbuf
*folderhrmxpm
;
79 static GdkPixbuf
*folderopenxpm
;
80 static GdkPixbuf
*folderopenhrmxpm
;
81 static GdkPixbuf
*trashopenxpm
;
82 static GdkPixbuf
*trashopenhrmxpm
;
83 static GdkPixbuf
*trashxpm
;
84 static GdkPixbuf
*trashhrmxpm
;
85 static GdkPixbuf
*queuexpm
;
86 static GdkPixbuf
*queuehrmxpm
;
87 static GdkPixbuf
*queueopenxpm
;
88 static GdkPixbuf
*queueopenhrmxpm
;
89 static GdkPixbuf
*draftsxpm
;
90 static GdkPixbuf
*draftsopenxpm
;
91 static GdkPixbuf
*foldersubsxpm
;
92 static GdkPixbuf
*foldersubsopenxpm
;
93 static GdkPixbuf
*foldernoselectxpm
;
94 static GdkPixbuf
*foldernoselectopenxpm
;
96 static GdkPixbuf
*m_inboxxpm
;
97 static GdkPixbuf
*m_inboxhrmxpm
;
98 static GdkPixbuf
*m_inboxopenxpm
;
99 static GdkPixbuf
*m_inboxopenhrmxpm
;
100 static GdkPixbuf
*m_outboxxpm
;
101 static GdkPixbuf
*m_outboxhrmxpm
;
102 static GdkPixbuf
*m_outboxopenxpm
;
103 static GdkPixbuf
*m_outboxopenhrmxpm
;
104 static GdkPixbuf
*m_folderxpm
;
105 static GdkPixbuf
*m_folderhrmxpm
;
106 static GdkPixbuf
*m_folderopenxpm
;
107 static GdkPixbuf
*m_folderopenhrmxpm
;
108 static GdkPixbuf
*m_trashopenxpm
;
109 static GdkPixbuf
*m_trashopenhrmxpm
;
110 static GdkPixbuf
*m_trashxpm
;
111 static GdkPixbuf
*m_trashhrmxpm
;
112 static GdkPixbuf
*m_queuexpm
;
113 static GdkPixbuf
*m_queuehrmxpm
;
114 static GdkPixbuf
*m_queueopenxpm
;
115 static GdkPixbuf
*m_queueopenhrmxpm
;
116 static GdkPixbuf
*m_draftsxpm
;
117 static GdkPixbuf
*m_draftsopenxpm
;
118 static GdkPixbuf
*m_foldersubsxpm
;
119 static GdkPixbuf
*m_foldernoselectxpm
;
121 static GdkPixbuf
*newxpm
;
122 static GdkPixbuf
*unreadxpm
;
123 static GdkPixbuf
*readxpm
;
125 static void folderview_select_node (FolderView
*folderview
,
126 GtkCMCTreeNode
*node
);
127 static void folderview_set_folders (FolderView
*folderview
);
128 static void folderview_sort_folders (FolderView
*folderview
,
129 GtkCMCTreeNode
*root
,
131 static void folderview_append_folder (FolderView
*folderview
,
133 static void folderview_update_node (FolderView
*folderview
,
134 GtkCMCTreeNode
*node
);
136 static gint
folderview_clist_compare (GtkCMCList
*clist
,
140 /* callback functions */
141 static gboolean
folderview_button_pressed (GtkWidget
*ctree
,
142 GdkEventButton
*event
,
143 FolderView
*folderview
);
144 static gboolean
folderview_button_released (GtkWidget
*ctree
,
145 GdkEventButton
*event
,
146 FolderView
*folderview
);
147 static gboolean
folderview_key_pressed (GtkWidget
*widget
,
149 FolderView
*folderview
);
150 static void folderview_selected (GtkCMCTree
*ctree
,
153 FolderView
*folderview
);
154 static void folderview_tree_expanded (GtkCMCTree
*ctree
,
155 GtkCMCTreeNode
*node
,
156 FolderView
*folderview
);
157 static void folderview_tree_collapsed (GtkCMCTree
*ctree
,
158 GtkCMCTreeNode
*node
,
159 FolderView
*folderview
);
160 static void folderview_popup_close (GtkMenuShell
*menu_shell
,
161 FolderView
*folderview
);
162 static void folderview_col_resized (GtkCMCList
*clist
,
165 FolderView
*folderview
);
167 static void mark_all_read_unread_handler (GtkAction
*action
,
172 static void mark_all_read_cb (GtkAction
*action
,
174 static void mark_all_unread_cb (GtkAction
*action
,
176 static void mark_all_read_recursive_cb (GtkAction
*action
,
178 static void mark_all_unread_recursive_cb (GtkAction
*action
,
181 static void folderview_empty_trash_cb (GtkAction
*action
,
184 static void folderview_send_queue_cb (GtkAction
*action
,
187 static void folderview_search_cb (GtkAction
*action
,
189 static void folderview_run_processing_cb(GtkAction
*action
,
192 static void folderview_property_cb (GtkAction
*action
,
195 static gboolean
folderview_drag_motion_cb(GtkWidget
*widget
,
196 GdkDragContext
*context
,
200 FolderView
*folderview
);
201 static void folderview_drag_leave_cb (GtkWidget
*widget
,
202 GdkDragContext
*context
,
204 FolderView
*folderview
);
205 static void folderview_drag_received_cb (GtkWidget
*widget
,
206 GdkDragContext
*drag_context
,
209 GtkSelectionData
*data
,
212 FolderView
*folderview
);
214 static void folderview_start_drag (GtkWidget
*widget
, gint button
, GdkEvent
*event
,
215 FolderView
*folderview
);
217 static void folderview_drag_data_get (GtkWidget
*widget
,
218 GdkDragContext
*drag_context
,
219 GtkSelectionData
*selection_data
,
222 FolderView
*folderview
);
223 static void folderview_drag_end_cb (GtkWidget
*widget
,
224 GdkDragContext
*drag_context
,
225 FolderView
*folderview
);
227 static void folderview_create_folder_node (FolderView
*folderview
,
229 static gboolean
folderview_update_folder (gpointer source
,
231 static gboolean
folderview_update_item_claws (gpointer source
,
233 static void folderview_processing_cb(GtkAction
*action
, gpointer data
);
234 static void folderview_set_sens_and_popup_menu(FolderView
*folderview
, gint row
,
235 GdkEventButton
*event
);
236 static void folderview_header_set_displayed_columns_cb(GtkAction
*gaction
,
238 static gboolean
folderview_header_button_pressed(GtkWidget
*widget
,
242 GHashTable
*folderview_popups
;
244 static GtkActionEntry folderview_common_popup_entries
[] =
246 {"FolderViewPopup", NULL
, "FolderViewPopup", NULL
, NULL
, NULL
},
247 {"FolderViewPopup/MarkAllRead", NULL
, N_("Mark all re_ad"), NULL
, NULL
, G_CALLBACK(mark_all_read_cb
) },
248 {"FolderViewPopup/MarkAllUnread", NULL
, N_("Mark all u_nread"), NULL
, NULL
, G_CALLBACK(mark_all_unread_cb
) },
249 {"FolderViewPopup/MarkAllReadRec", NULL
, N_("Mark all read recursi_vely"), NULL
, NULL
, G_CALLBACK(mark_all_read_recursive_cb
) },
250 {"FolderViewPopup/MarkAllUnreadRec", NULL
, N_("Mark all unread recursi_vely"), NULL
, NULL
, G_CALLBACK(mark_all_unread_recursive_cb
) },
251 {"FolderViewPopup/---", NULL
, "---", NULL
, NULL
, NULL
},
252 {"FolderViewPopup/RunProcessing", NULL
, N_("R_un processing rules"), NULL
, NULL
, G_CALLBACK(folderview_run_processing_cb
) },
253 {"FolderViewPopup/SearchFolder", NULL
, N_("_Search folder..."), NULL
, NULL
, G_CALLBACK(folderview_search_cb
) },
254 {"FolderViewPopup/Properties", NULL
, N_("_Properties..."), NULL
, NULL
, G_CALLBACK(folderview_property_cb
) },
255 {"FolderViewPopup/Processing", NULL
, N_("Process_ing..."), NULL
, NULL
, G_CALLBACK(folderview_processing_cb
) },
256 {"FolderViewPopup/EmptyTrash", NULL
, N_("Empty _trash..."), NULL
, NULL
, G_CALLBACK(folderview_empty_trash_cb
) },
257 {"FolderViewPopup/SendQueue", NULL
, N_("Send _queue..."), NULL
, NULL
, G_CALLBACK(folderview_send_queue_cb
) },
261 static GtkActionEntry folderview_header_popup_entries
[] =
263 {"FolderViewHeaderPopup", NULL
, "FolderViewHeaderPopup", NULL
, NULL
, NULL
},
264 {"FolderViewHeaderPopup/SetDisplayedColumns", NULL
, N_("Set Displayed columns"), NULL
, NULL
, G_CALLBACK(folderview_header_set_displayed_columns_cb
) }
267 GtkTargetEntry folderview_drag_types
[] =
269 {"claws-mail/internal", GTK_TARGET_SAME_APP
, TARGET_DUMMY
},
270 {"text/uri-list", 0, TARGET_MAIL_URI_LIST
}
273 void folderview_initialize(void)
275 FolderViewPopup
*fpopup
;
277 fpopup
= g_new0(FolderViewPopup
, 1);
279 fpopup
->klass
= "common";
280 fpopup
->path
= "<CommonFolder>";
281 fpopup
->entries
= folderview_common_popup_entries
;
282 fpopup
->n_entries
= G_N_ELEMENTS(folderview_common_popup_entries
);
283 fpopup
->set_sensitivity
= NULL
;
285 folderview_popups
= g_hash_table_new(g_str_hash
, g_str_equal
);
286 g_hash_table_insert(folderview_popups
, "common", fpopup
);
289 static GtkActionGroup
*create_action_group(FolderView
*folderview
, FolderViewPopup
*fpopup
)
291 FolderViewPopup
*fpopup_common
;
292 GtkActionGroup
*action_group
;
294 action_group
= cm_menu_create_action_group(
296 fpopup
->entries
, fpopup
->n_entries
,
297 (gpointer
)folderview
);
299 if (fpopup
->toggle_entries
)
300 gtk_action_group_add_toggle_actions(action_group
, fpopup
->toggle_entries
,
301 fpopup
->n_toggle_entries
,
302 (gpointer
)folderview
);
303 if (fpopup
->radio_entries
)
304 gtk_action_group_add_radio_actions(action_group
, fpopup
->radio_entries
,
305 fpopup
->n_radio_entries
, fpopup
->radio_default
,
306 G_CALLBACK(fpopup
->radio_callback
),
307 (gpointer
)folderview
);
309 fpopup_common
= g_hash_table_lookup(folderview_popups
, "common");
310 if (fpopup_common
!= fpopup
) {
311 gtk_action_group_add_actions(action_group
, fpopup_common
->entries
,
312 fpopup_common
->n_entries
,
313 (gpointer
)folderview
);
314 if (fpopup_common
->toggle_entries
)
315 gtk_action_group_add_toggle_actions(action_group
, fpopup_common
->toggle_entries
,
316 fpopup_common
->n_toggle_entries
,
317 (gpointer
)folderview
);
318 if (fpopup_common
->radio_entries
)
319 gtk_action_group_add_radio_actions(action_group
, fpopup_common
->radio_entries
,
320 fpopup_common
->n_radio_entries
, fpopup_common
->radio_default
,
321 G_CALLBACK(fpopup_common
->radio_callback
),
322 (gpointer
)folderview
);
328 static void create_action_groups(gpointer key
, gpointer value
, gpointer data
)
330 FolderView
*folderview
= data
;
331 FolderViewPopup
*fpopup
= value
;
332 GtkActionGroup
*group
;
334 group
= create_action_group(folderview
, fpopup
);
335 g_hash_table_insert(folderview
->popups
, fpopup
->klass
, group
);
338 static void folderview_column_set_titles(FolderView
*folderview
)
340 GtkWidget
*ctree
= folderview
->ctree
;
341 GtkWidget
*label_folder
;
342 GtkWidget
*label_new
;
343 GtkWidget
*label_unread
;
344 GtkWidget
*label_total
;
345 GtkWidget
*hbox_folder
;
347 GtkWidget
*hbox_unread
;
348 GtkWidget
*hbox_total
;
349 gint
*col_pos
= folderview
->col_pos
;
351 debug_print("setting titles...\n");
352 gtk_widget_realize(folderview
->ctree
);
353 gtk_widget_show_all(folderview
->scrolledwin
);
355 /* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
356 * instead text (text overflows making them unreadable and ugly) */
357 stock_pixbuf_gdk(STOCK_PIXMAP_NEW
, &newxpm
);
358 stock_pixbuf_gdk(STOCK_PIXMAP_UNREAD
, &unreadxpm
);
359 stock_pixbuf_gdk(STOCK_PIXMAP_READ
, &readxpm
);
361 label_folder
= gtk_label_new(_("Folder"));
362 label_new
= gtk_image_new_from_pixbuf(newxpm
);
363 label_unread
= gtk_image_new_from_pixbuf(unreadxpm
);
364 label_total
= gtk_image_new_from_pixbuf(readxpm
);
366 gtk_cmclist_column_titles_active(GTK_CMCLIST(ctree
));
368 hbox_folder
= gtk_hbox_new(FALSE
, 4);
369 hbox_new
= gtk_hbox_new(FALSE
, 4);
370 hbox_unread
= gtk_hbox_new(FALSE
, 4);
371 hbox_total
= gtk_hbox_new(FALSE
, 4);
374 gtk_box_pack_start(GTK_BOX(hbox_folder
), label_folder
, TRUE
, TRUE
, 0);
375 gtk_misc_set_alignment (GTK_MISC (label_folder
), 0, 0.5);
376 gtk_box_pack_start(GTK_BOX(hbox_new
), label_new
, TRUE
, TRUE
, 0);
377 gtk_misc_set_alignment (GTK_MISC (label_new
), 1, 0.5);
378 gtk_box_pack_start(GTK_BOX(hbox_unread
), label_unread
, TRUE
, TRUE
, 0);
379 gtk_misc_set_alignment (GTK_MISC (label_unread
), 1, 0.5);
380 gtk_box_pack_start(GTK_BOX(hbox_total
), label_total
, TRUE
, TRUE
, 0);
381 gtk_misc_set_alignment (GTK_MISC (label_total
), 1, 0.5);
383 gtk_widget_show_all(hbox_folder
);
384 gtk_widget_show_all(hbox_new
);
385 gtk_widget_show_all(hbox_unread
);
386 gtk_widget_show_all(hbox_total
);
389 gtk_widget_set_size_request(hbox_new
, -1, 20);
390 gtk_widget_set_size_request(hbox_unread
, -1, 20);
391 gtk_widget_set_size_request(hbox_total
, -1, 20);
394 gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree
),col_pos
[F_COL_FOLDER
],hbox_folder
);
395 gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree
),col_pos
[F_COL_NEW
],hbox_new
);
396 gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree
),col_pos
[F_COL_UNREAD
],hbox_unread
);
397 gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree
),col_pos
[F_COL_TOTAL
],hbox_total
);
403 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree
), col_pos
[F_COL_NEW
], _("New"));
404 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree
), col_pos
[F_COL_UNREAD
], _("Unread"));
405 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree
), col_pos
[F_COL_TOTAL
], _("Total"));
408 static gboolean
folderview_popup_menu(GtkWidget
*widget
, gpointer data
)
410 FolderView
*folderview
= (FolderView
*)data
;
411 GdkEventButton event
;
412 if (folderview_get_selected_item(folderview
) == NULL
)
416 event
.time
= gtk_get_current_event_time();
418 folderview_set_sens_and_popup_menu(folderview
, -1,
425 static GtkWidget
*folderview_ctree_create(FolderView
*folderview
)
429 FolderColumnState
*col_state
;
430 FolderColumnType type
;
431 gchar
*titles
[N_FOLDER_COLS
];
433 GtkWidget
*scrolledwin
= folderview
->scrolledwin
;
435 debug_print("creating tree...\n");
436 memset(titles
, 0, sizeof(titles
));
438 col_state
= prefs_folder_column_get_config();
439 memset(titles
, 0, sizeof(titles
));
441 col_pos
= folderview
->col_pos
;
443 for (i
= 0; i
< N_FOLDER_COLS
; i
++) {
444 folderview
->col_state
[i
] = col_state
[i
];
445 type
= col_state
[i
].type
;
449 titles
[col_pos
[F_COL_FOLDER
]] = _("Folder");
450 titles
[col_pos
[F_COL_NEW
]] = _("New");
451 titles
[col_pos
[F_COL_UNREAD
]] = _("Unread");
452 /* TRANSLATORS: This in Number sign in American style */
453 titles
[col_pos
[F_COL_TOTAL
]] = _("#");
455 ctree
= gtk_sctree_new_with_titles(N_FOLDER_COLS
, col_pos
[F_COL_FOLDER
],
458 if (prefs_common
.show_col_headers
== FALSE
)
459 gtk_cmclist_column_titles_hide(GTK_CMCLIST(ctree
));
462 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree
), GTK_SELECTION_BROWSE
);
463 gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree
), col_pos
[F_COL_NEW
],
465 gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree
),
466 col_pos
[F_COL_UNREAD
],
468 gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree
),
469 col_pos
[F_COL_TOTAL
],
471 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree
),
472 GTK_CMCTREE_EXPANDER_TRIANGLE
);
474 gtk_sctree_set_stripes(GTK_SCTREE(ctree
), prefs_common
.use_stripes_in_summaries
);
475 gtk_sctree_set_recursive_expand(GTK_SCTREE(ctree
), FALSE
);
477 gtk_cmctree_set_indent(GTK_CMCTREE(ctree
), CTREE_INDENT
);
478 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree
), folderview_clist_compare
);
480 /* don't let title buttons take key focus */
481 for (i
= 0; i
< N_FOLDER_COLS
; i
++) {
482 gtk_widget_set_can_focus(GTK_CMCLIST(ctree
)->column
[i
].button
, FALSE
);
483 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree
), col_pos
[i
],
484 prefs_common
.folder_col_size
[i
]);
485 gtk_cmclist_set_column_visibility
486 (GTK_CMCLIST(ctree
), i
, col_state
[i
].visible
);
488 g_signal_connect(G_OBJECT(GTK_CMCLIST(ctree
)->column
[i
].button
),
489 "button-press-event",
490 G_CALLBACK(folderview_header_button_pressed
),
494 g_signal_connect(G_OBJECT(ctree
), "key_press_event",
495 G_CALLBACK(folderview_key_pressed
),
497 g_signal_connect(G_OBJECT(ctree
), "button_press_event",
498 G_CALLBACK(folderview_button_pressed
),
500 g_signal_connect(G_OBJECT(ctree
), "popup-menu",
501 G_CALLBACK(folderview_popup_menu
), folderview
);
502 g_signal_connect(G_OBJECT(ctree
), "button_release_event",
503 G_CALLBACK(folderview_button_released
),
505 g_signal_connect(G_OBJECT(ctree
), "tree_select_row",
506 G_CALLBACK(folderview_selected
), folderview
);
508 /* drag-n-dropping folders on maemo is impractical as this
509 * opens the folder almost everytime */
510 g_signal_connect(G_OBJECT(ctree
), "start_drag",
511 G_CALLBACK(folderview_start_drag
), folderview
);
513 g_signal_connect(G_OBJECT(ctree
), "drag_data_get",
514 G_CALLBACK(folderview_drag_data_get
),
517 g_signal_connect_after(G_OBJECT(ctree
), "tree_expand",
518 G_CALLBACK(folderview_tree_expanded
),
520 g_signal_connect_after(G_OBJECT(ctree
), "tree_collapse",
521 G_CALLBACK(folderview_tree_collapsed
),
524 g_signal_connect(G_OBJECT(ctree
), "resize_column",
525 G_CALLBACK(folderview_col_resized
),
529 gtk_drag_dest_set(ctree
, GTK_DEST_DEFAULT_ALL
& ~GTK_DEST_DEFAULT_HIGHLIGHT
,
530 folderview_drag_types
, 2,
531 GDK_ACTION_MOVE
| GDK_ACTION_COPY
| GDK_ACTION_DEFAULT
);
532 g_signal_connect(G_OBJECT(ctree
), "drag_motion",
533 G_CALLBACK(folderview_drag_motion_cb
),
535 g_signal_connect(G_OBJECT(ctree
), "drag_leave",
536 G_CALLBACK(folderview_drag_leave_cb
),
538 g_signal_connect(G_OBJECT(ctree
), "drag_data_received",
539 G_CALLBACK(folderview_drag_received_cb
),
541 g_signal_connect(G_OBJECT(ctree
), "drag_end",
542 G_CALLBACK(folderview_drag_end_cb
),
545 gtk_container_add(GTK_CONTAINER(scrolledwin
), ctree
);
550 void folderview_set_column_order(FolderView
*folderview
)
552 GtkWidget
*ctree
= folderview
->ctree
;
553 FolderItem
*item
= folderview_get_selected_item(folderview
);
554 FolderItem
*sel_item
= NULL
, *op_item
= NULL
;
555 GtkWidget
*scrolledwin
= folderview
->scrolledwin
;
557 if (folderview
->drag_timer_id
!= 0) {
558 g_source_remove(folderview
->drag_timer_id
);
559 folderview
->drag_timer_id
= 0;
561 if (folderview
->deferred_refresh_id
!= 0) {
562 g_source_remove(folderview
->deferred_refresh_id
);
563 folderview
->deferred_refresh_id
= 0;
565 if (folderview
->scroll_timeout_id
!= 0) {
566 g_source_remove(folderview
->scroll_timeout_id
);
567 folderview
->scroll_timeout_id
= 0;
569 if (folderview
->postpone_select_id
!= 0) {
570 g_source_remove(folderview
->postpone_select_id
);
571 folderview
->postpone_select_id
= 0;
574 if (folderview
->selected
)
575 sel_item
= folderview_get_selected_item(folderview
);
576 if (folderview
->opened
)
577 op_item
= folderview_get_opened_item(folderview
);
579 debug_print("recreating tree...\n");
580 gtk_widget_destroy(folderview
->ctree
);
583 folderview
->ctree
= ctree
= folderview_ctree_create(folderview
);
584 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin
),
585 GTK_CMCLIST(ctree
)->hadjustment
);
586 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin
),
587 GTK_CMCLIST(ctree
)->vadjustment
);
588 gtk_widget_show(ctree
);
591 folderview
->selected
= gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree
), NULL
, sel_item
);
593 folderview
->opened
= gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree
), NULL
, op_item
);
595 folderview_set(folderview
);
596 folderview_column_set_titles(folderview
);
598 folderview_select(folderview
,item
);
601 FolderView
*folderview_create(MainWindow
*mainwin
)
603 FolderView
*folderview
;
604 GtkWidget
*scrolledwin
;
607 debug_print("Creating folder view...\n");
608 folderview
= g_new0(FolderView
, 1);
610 scrolledwin
= gtk_scrolled_window_new(NULL
, NULL
);
611 gtk_scrolled_window_set_policy
612 (GTK_SCROLLED_WINDOW(scrolledwin
),
613 GTK_POLICY_AUTOMATIC
,
614 prefs_common
.folderview_vscrollbar_policy
);
615 gtk_widget_set_size_request(scrolledwin
,
616 prefs_common
.folderview_width
,
617 prefs_common
.folderview_height
);
619 folderview
->scrolledwin
= scrolledwin
;
620 ctree
= folderview_ctree_create(folderview
);
622 /* create popup factories */
623 folderview
->popups
= g_hash_table_new(g_str_hash
, g_str_equal
);
624 g_hash_table_foreach(folderview_popups
, create_action_groups
, folderview
);
626 gtk_action_group_add_actions(mainwin
->action_group
,
627 folderview_header_popup_entries
,
628 G_N_ELEMENTS(folderview_header_popup_entries
),
629 (gpointer
)folderview
);
631 MENUITEM_ADDUI_MANAGER(mainwin
->ui_manager
, "/Menus", "FolderViewHeaderPopup", "FolderViewHeaderPopup", GTK_UI_MANAGER_MENU
)
632 MENUITEM_ADDUI_MANAGER(mainwin
->ui_manager
, "/Menus/FolderViewHeaderPopup", "SetDisplayedColumns", "FolderViewHeaderPopup/SetDisplayedColumns", GTK_UI_MANAGER_MENUITEM
)
634 folderview
->headerpopupmenu
= gtk_menu_item_get_submenu(GTK_MENU_ITEM(
635 gtk_ui_manager_get_widget(mainwin
->ui_manager
,
636 "/Menus/FolderViewHeaderPopup") ));
638 folderview
->ctree
= ctree
;
640 folderview
->folder_update_callback_id
=
641 hooks_register_hook(FOLDER_UPDATE_HOOKLIST
, folderview_update_folder
, (gpointer
) folderview
);
642 folderview
->folder_item_update_callback_id
=
643 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST
, folderview_update_item_claws
, (gpointer
) folderview
);
645 gtk_widget_show_all(scrolledwin
);
647 folderview
->target_list
= gtk_target_list_new(folderview_drag_types
, 2);
648 folderview_list
= g_list_append(folderview_list
, folderview
);
650 folderview
->drag_timer_id
= 0;
651 folderview
->deferred_refresh_id
= 0;
652 folderview
->scroll_timeout_id
= 0;
653 folderview
->postpone_select_id
= 0;
658 static void folderview_set_fonts(FolderView
*folderview
)
660 PangoFontDescription
*font_desc
;
661 GtkWidget
*ctree
= folderview
->ctree
;
663 font_desc
= pango_font_description_from_string(NORMAL_FONT
);
665 gtk_widget_modify_font(ctree
, font_desc
);
666 pango_font_description_free(font_desc
);
670 bold_style
= gtk_style_copy(gtk_widget_get_style(ctree
));
672 if (prefs_common
.derive_from_normal_font
|| !BOLD_FONT
) {
673 font_desc
= pango_font_description_from_string(NORMAL_FONT
);
675 pango_font_description_free(bold_style
->font_desc
);
676 bold_style
->font_desc
= font_desc
;
678 pango_font_description_set_weight
679 (bold_style
->font_desc
, PANGO_WEIGHT_BOLD
);
681 font_desc
= pango_font_description_from_string(BOLD_FONT
);
683 pango_font_description_free(bold_style
->font_desc
);
684 bold_style
->font_desc
= font_desc
;
690 void folderview_init(FolderView
*folderview
)
692 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE
, &inboxxpm
);
693 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE_HRM
, &inboxhrmxpm
);
694 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN
, &inboxopenxpm
);
695 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN_HRM
, &inboxopenhrmxpm
);
696 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE
, &outboxxpm
);
697 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE_HRM
, &outboxhrmxpm
);
698 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN
, &outboxopenxpm
);
699 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN_HRM
, &outboxopenhrmxpm
);
700 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE
, &folderxpm
);
701 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE_HRM
, &folderhrmxpm
);
702 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN
, &folderopenxpm
);
703 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN_HRM
, &folderopenhrmxpm
);
704 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN
, &trashopenxpm
);
705 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN_HRM
, &trashopenhrmxpm
);
706 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE
, &trashxpm
);
707 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE_HRM
, &trashhrmxpm
);
708 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE
, &queuexpm
);
709 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE_HRM
, &queuehrmxpm
);
710 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN
, &queueopenxpm
);
711 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN_HRM
, &queueopenhrmxpm
);
712 stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_CLOSE
, &draftsxpm
);
713 stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_OPEN
, &draftsopenxpm
);
714 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_SUBS_OPEN
, &foldersubsopenxpm
);
715 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_SUBS_CLOSE
, &foldersubsxpm
);
716 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_NOSELECT_OPEN
, &foldernoselectopenxpm
);
717 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_NOSELECT_CLOSE
, &foldernoselectxpm
);
719 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE_MARK
, &m_inboxxpm
);
720 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK
, &m_inboxhrmxpm
);
721 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN_MARK
, &m_inboxopenxpm
);
722 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN_HRM_MARK
, &m_inboxopenhrmxpm
);
723 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE_MARK
, &m_outboxxpm
);
724 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK
, &m_outboxhrmxpm
);
725 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN_MARK
, &m_outboxopenxpm
);
726 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK
, &m_outboxopenhrmxpm
);
727 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE_MARK
, &m_folderxpm
);
728 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE_HRM_MARK
, &m_folderhrmxpm
);
729 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN_MARK
, &m_folderopenxpm
);
730 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN_HRM_MARK
, &m_folderopenhrmxpm
);
731 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN_MARK
, &m_trashopenxpm
);
732 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN_HRM_MARK
, &m_trashopenhrmxpm
);
733 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE_MARK
, &m_trashxpm
);
734 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK
, &m_trashhrmxpm
);
735 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE_MARK
, &m_queuexpm
);
736 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK
, &m_queuehrmxpm
);
737 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN_MARK
, &m_queueopenxpm
);
738 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK
, &m_queueopenhrmxpm
);
739 stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_CLOSE_MARK
, &m_draftsxpm
);
740 stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_OPEN_MARK
, &m_draftsopenxpm
);
741 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_SUBS_CLOSE_MARK
, &m_foldersubsxpm
);
742 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_NOSELECT_CLOSE_MARK
, &m_foldernoselectxpm
);
744 folderview_set_fonts(folderview
);
747 static gboolean
folderview_defer_set(gpointer data
)
749 FolderView
*folderview
= (FolderView
*)data
;
750 MainWindow
*mainwin
= folderview
->mainwin
;
754 if (mainwin
->lock_count
)
757 debug_print("doing deferred folderview_set now\n");
758 folderview_set(folderview
);
760 folderview
->deferred_refresh_id
= 0;
764 void folderview_set(FolderView
*folderview
)
766 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
767 MainWindow
*mainwin
= folderview
->mainwin
;
768 FolderItem
*sel_item
= NULL
, *op_item
= NULL
;
773 if (mainwin
->lock_count
) {
774 if (folderview
->deferred_refresh_id
== 0)
775 folderview
->deferred_refresh_id
=
776 g_timeout_add(500, folderview_defer_set
, folderview
);
777 debug_print("deferred folderview_set\n");
782 debug_print("Setting folder info...\n");
783 STATUSBAR_PUSH(mainwin
, _("Setting folder info..."));
785 main_window_cursor_wait(mainwin
);
787 if (folderview
->selected
)
788 sel_item
= folderview_get_selected_item(folderview
);
789 if (folderview
->opened
)
790 op_item
= folderview_get_opened_item(folderview
);
792 folderview
->selected
= NULL
;
793 folderview
->opened
= NULL
;
795 gtk_cmclist_freeze(GTK_CMCLIST(ctree
));
796 gtk_cmclist_clear(GTK_CMCLIST(ctree
));
798 folderview_set_folders(folderview
);
801 folderview
->selected
= gtk_cmctree_find_by_row_data(ctree
, NULL
, sel_item
);
803 folderview
->opened
= gtk_cmctree_find_by_row_data(ctree
, NULL
, op_item
);
805 gtk_cmclist_thaw(GTK_CMCLIST(ctree
));
806 main_window_cursor_normal(mainwin
);
807 STATUSBAR_POP(mainwin
);
811 void folderview_set_all(void)
815 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
)
816 folderview_set((FolderView
*)list
->data
);
819 void folderview_select(FolderView
*folderview
, FolderItem
*item
)
821 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
822 GtkCMCTreeNode
*node
;
823 GtkCMCTreeNode
*old_selected
= folderview
->selected
;
827 node
= gtk_cmctree_find_by_row_data(ctree
, NULL
, item
);
828 if (node
) folderview_select_node(folderview
, node
);
830 if (old_selected
!= node
)
831 folder_update_op_count();
834 static void mark_all_read_cb(GtkAction
*action
, gpointer data
)
836 mark_all_read_unread_handler(action
, data
, FALSE
, TRUE
);
839 static void mark_all_unread_cb(GtkAction
*action
, gpointer data
)
841 mark_all_read_unread_handler(action
, data
, FALSE
, FALSE
);
844 static void mark_all_read_recursive_cb(GtkAction
*action
, gpointer data
)
846 mark_all_read_unread_handler(action
, data
, TRUE
, TRUE
);
849 static void mark_all_unread_recursive_cb(GtkAction
*action
, gpointer data
)
851 mark_all_read_unread_handler(action
, data
, TRUE
, FALSE
);
854 static void mark_all_read_unread_handler(GtkAction
*action
, gpointer data
,
855 gboolean recursive
, gboolean read
)
857 FolderView
*folderview
= (FolderView
*)data
;
863 item
= folderview_get_selected_item(folderview
);
868 title
= _("Mark all as read");
869 message
= recursive
? _("Do you really want to mark all mails in this "
870 "folder and its sub-folders as read?") :
871 _("Do you really want to mark all mails in this "
874 title
= _("Mark all as unread");
875 message
= recursive
? _("Do you really want to mark all mails in this "
876 "folder and its sub-folders as unread?") :
877 _("Do you really want to mark all mails in this "
878 "folder as unread?");
880 if (prefs_common
.ask_mark_all_read
) {
881 val
= alertpanel_full(title
, message
,
882 GTK_STOCK_NO
, GTK_STOCK_YES
, NULL
, ALERTFOCUS_FIRST
,
883 TRUE
, NULL
, ALERT_QUESTION
);
885 if ((val
& ~G_ALERTDISABLE
) != G_ALERTALTERNATE
)
887 else if (val
& G_ALERTDISABLE
)
888 prefs_common
.ask_mark_all_read
= FALSE
;
891 folder_item_update_freeze();
892 if (folderview
->summaryview
->folder_item
!= item
&& !recursive
)
893 summary_lock(folderview
->summaryview
);
895 summary_freeze(folderview
->summaryview
);
899 folderutils_mark_all_read_recursive(item
, TRUE
);
901 folderutils_mark_all_read(item
, TRUE
);
904 folderutils_mark_all_read_recursive(item
, FALSE
);
906 folderutils_mark_all_read(item
, FALSE
);
908 if (folderview
->summaryview
->folder_item
!= item
&& !recursive
)
909 summary_unlock(folderview
->summaryview
);
911 summary_thaw(folderview
->summaryview
);
912 folder_item_update_thaw();
915 static void folderview_select_node(FolderView
*folderview
, GtkCMCTreeNode
*node
)
917 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
919 cm_return_if_fail(node
!= NULL
);
921 if (folderview
->open_folder
) {
925 gtk_cmclist_freeze(GTK_CMCLIST(ctree
));
926 gtkut_ctree_expand_parent_all(ctree
, node
);
928 folderview
->open_folder
= TRUE
;
929 gtkut_ctree_set_focus_row(ctree
, node
);
930 gtk_cmctree_select(ctree
, node
);
931 gtk_cmclist_thaw(GTK_CMCLIST(ctree
));
932 if ((folderview
->summaryview
->folder_item
&&
933 folderview
->summaryview
->folder_item
->total_msgs
> 0) ||
934 prefs_common
.layout_mode
== SMALL_LAYOUT
)
935 summary_select_node(folderview
->summaryview
,
936 folderview
->summaryview
->selected
, OPEN_SELECTED_ON_FOLDER_OPEN
);
938 gtk_widget_grab_focus(folderview
->ctree
);
941 void folderview_unselect(FolderView
*folderview
)
943 if (folderview
->opened
&& !GTK_CMCTREE_ROW(folderview
->opened
)->children
)
945 (GTK_CMCTREE(folderview
->ctree
), folderview
->opened
);
947 folderview
->selected
= folderview
->opened
= NULL
;
950 static GtkCMCTreeNode
*folderview_find_next_with_flag(GtkCMCTree
*ctree
,
951 GtkCMCTreeNode
*node
,
957 node
= gtkut_ctree_node_next(ctree
, node
);
959 node
= GTK_CMCTREE_NODE(GTK_CMCLIST(ctree
)->row_list
);
961 for (; node
!= NULL
; node
= gtkut_ctree_node_next(ctree
, node
)) {
962 item
= gtk_cmctree_node_get_row_data(ctree
, node
);
965 if (item
->stype
== F_TRASH
|| item
->stype
== F_DRAFT
)
969 if(item
->unread_msgs
> 0)
973 if(item
->new_msgs
> 0)
977 if(item
->marked_msgs
> 0)
981 if(item
->total_msgs
> 0)
990 void folderview_select_next_with_flag(FolderView
*folderview
,
993 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
994 GtkCMCTreeNode
*node
= NULL
;
995 EntryAction last_summary_select_prio
= prefs_common
.summary_select_prio
[0];
999 prefs_common
.summary_select_prio
[0] = ACTION_OLDEST_UNREAD
;
1002 prefs_common
.summary_select_prio
[0] = ACTION_OLDEST_NEW
;
1005 prefs_common
.summary_select_prio
[0] = ACTION_OLDEST_MARKED
;
1008 prefs_common
.summary_select_prio
[0] = ACTION_OLDEST_LIST
;
1012 node
= folderview_find_next_with_flag(ctree
, folderview
->opened
, flag
);
1014 folderview_select_node(folderview
, node
);
1018 if (!folderview
->opened
||
1019 folderview
->opened
== GTK_CMCTREE_NODE(GTK_CMCLIST(ctree
)->row_list
)) {
1023 /* search again from the first node */
1024 node
= folderview_find_next_with_flag(ctree
, NULL
, flag
);
1026 folderview_select_node(folderview
, node
);
1029 prefs_common
.summary_select_prio
[0] = last_summary_select_prio
;
1032 FolderItem
*folderview_get_selected_item(FolderView
*folderview
)
1034 g_return_val_if_fail(folderview
!= NULL
, NULL
);
1035 g_return_val_if_fail(folderview
->ctree
!= NULL
, NULL
);
1037 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
1039 if (!folderview
->selected
) return NULL
;
1040 return gtk_cmctree_node_get_row_data(ctree
, folderview
->selected
);
1043 FolderItem
*folderview_get_opened_item(FolderView
*folderview
)
1045 g_return_val_if_fail(folderview
!= NULL
, NULL
);
1046 g_return_val_if_fail(folderview
->ctree
!= NULL
, NULL
);
1048 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
1050 if (!folderview
->opened
) return NULL
;
1051 return gtk_cmctree_node_get_row_data(ctree
, folderview
->opened
);
1054 static void folderview_set_folders(FolderView
*folderview
)
1057 list
= folder_get_list();
1059 for (; list
!= NULL
; list
= list
->next
) {
1060 folderview_append_folder(folderview
, FOLDER(list
->data
));
1064 static gchar
*get_scan_str(FolderItem
*item
)
1067 return g_strdup_printf(_("Scanning folder %s/%s..."),
1068 item
->folder
->name
, item
->path
);
1070 return g_strdup_printf(_("Scanning folder %s..."),
1071 item
->folder
->name
);
1073 static void folderview_scan_tree_func(Folder
*folder
, FolderItem
*item
,
1077 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
) {
1078 FolderView
*folderview
= (FolderView
*)list
->data
;
1079 MainWindow
*mainwin
= folderview
->mainwin
;
1080 gchar
*str
= get_scan_str(item
);
1082 STATUSBAR_PUSH(mainwin
, str
);
1083 STATUSBAR_POP(mainwin
);
1088 void folderview_rescan_tree(Folder
*folder
, gboolean rebuild
)
1091 MainWindow
*mainwin
= mainwindow_get_mainwindow();
1092 FolderView
*folderview
= NULL
;
1093 GtkAdjustment
*pos
= NULL
;
1096 cm_return_if_fail(folder
!= NULL
);
1098 if (!folder
->klass
->scan_tree
) return;
1101 alertpanel_full(_("Rebuild folder tree"),
1102 _("Rebuilding the folder tree will remove "
1103 "local caches. Do you want to continue?"),
1104 GTK_STOCK_NO
, GTK_STOCK_YES
, NULL
, ALERTFOCUS_FIRST
,
1105 FALSE
, NULL
, ALERT_WARNING
)
1106 != G_ALERTALTERNATE
) {
1112 window
= label_window_create(_("Rebuilding folder tree..."));
1114 window
= label_window_create(_("Scanning folder tree..."));
1117 folderview
= mainwin
->folderview
;
1120 pos
= gtk_scrolled_window_get_vadjustment(
1121 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
1122 height
= gtk_adjustment_get_value(pos
);
1125 folder_set_ui_func(folder
, folderview_scan_tree_func
, NULL
);
1126 folder_scan_tree(folder
, rebuild
);
1127 folder_set_ui_func(folder
, NULL
, NULL
);
1129 folderview_set_all();
1132 pos
= gtk_scrolled_window_get_vadjustment(
1133 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
1134 gtk_adjustment_set_value(pos
, height
);
1135 gtk_adjustment_changed(pos
);
1137 label_window_destroy(window
);
1141 /** folderview_check_new()
1142 * Scan and update the folder and return the
1143 * count the number of new messages since last check.
1144 * \param folder the folder to check for new messages
1145 * \return the number of new messages since last check
1147 gint
folderview_check_new(Folder
*folder
)
1151 FolderView
*folderview
;
1153 GtkCMCTreeNode
*node
;
1155 gint former_new_msgs
= 0;
1156 gint former_new
= 0, former_unread
= 0, former_total
;
1158 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
) {
1159 folderview
= (FolderView
*)list
->data
;
1160 ctree
= GTK_CMCTREE(folderview
->ctree
);
1161 folderview
->scanning_folder
= folder
;
1163 main_window_lock(folderview
->mainwin
);
1165 for (node
= GTK_CMCTREE_NODE(GTK_CMCLIST(ctree
)->row_list
);
1166 node
!= NULL
; node
= gtkut_ctree_node_next(ctree
, node
)) {
1168 item
= gtk_cmctree_node_get_row_data(ctree
, node
);
1169 if (!item
|| !item
->path
|| !item
->folder
) continue;
1170 if (item
->no_select
) continue;
1171 if (folder
&& folder
!= item
->folder
) continue;
1172 if (!folder
&& !FOLDER_IS_LOCAL(item
->folder
)) continue;
1173 if (!item
->prefs
->newmailcheck
) continue;
1174 if (item
->processing_pending
== TRUE
) {
1175 debug_print("skipping %s, processing pending\n",
1176 item
->path
? item
->path
: item
->name
);
1179 if (item
->scanning
!= ITEM_NOT_SCANNING
) {
1180 debug_print("skipping %s, scanning\n",
1181 item
->path
? item
->path
: item
->name
);
1185 str
= get_scan_str(item
);
1187 STATUSBAR_PUSH(folderview
->mainwin
, str
);
1191 folderview_scan_tree_func(item
->folder
, item
, NULL
);
1192 former_new
= item
->new_msgs
;
1193 former_unread
= item
->unread_msgs
;
1194 former_total
= item
->total_msgs
;
1196 if (item
->folder
->klass
->scan_required
&&
1197 (item
->folder
->klass
->scan_required(item
->folder
, item
) ||
1198 item
->folder
->inbox
== item
||
1199 item
->opened
== TRUE
||
1200 item
->processing_pending
== TRUE
)) {
1201 if (folder_item_scan(item
) < 0) {
1203 summaryview_unlock(folderview
->summaryview
, item
);
1204 if (FOLDER_TYPE(item
->folder
) == F_NEWS
|| FOLDER_IS_LOCAL(folder
)) {
1205 log_error(LOG_PROTOCOL
, _("Couldn't scan folder %s\n"),
1206 item
->path
? item
->path
:item
->name
);
1207 STATUSBAR_POP(folderview
->mainwin
);
1209 } else if (!FOLDER_IS_LOCAL(folder
)) {
1210 STATUSBAR_POP(folderview
->mainwin
);
1215 } else if (!item
->folder
->klass
->scan_required
) {
1216 if (folder_item_scan(item
) < 0) {
1217 summaryview_unlock(folderview
->summaryview
, item
);
1218 if (folder
&& !FOLDER_IS_LOCAL(folder
)) {
1219 STATUSBAR_POP(folderview
->mainwin
);
1224 if (former_new
!= item
->new_msgs
||
1225 former_unread
!= item
->unread_msgs
||
1226 former_total
!= item
->total_msgs
)
1227 folderview_update_node(folderview
, node
);
1229 new_msgs
+= item
->new_msgs
;
1230 former_new_msgs
+= former_new
;
1231 STATUSBAR_POP(folderview
->mainwin
);
1233 folderview
->scanning_folder
= NULL
;
1234 main_window_unlock(folderview
->mainwin
);
1238 folder_write_list();
1239 /* Number of new messages since last check is the just the difference
1240 * between former_new_msgs and new_msgs. If new_msgs is less than
1241 * former_new_msgs, that would mean another session accessed the folder
1242 * and the result is not well defined.
1244 new_msgs
= (former_new_msgs
< new_msgs
? new_msgs
- former_new_msgs
: 0);
1248 void folderview_check_new_all(void)
1252 FolderView
*folderview
;
1254 folderview
= (FolderView
*)folderview_list
->data
;
1257 main_window_lock(folderview
->mainwin
);
1258 window
= label_window_create
1259 (_("Checking for new messages in all folders..."));
1261 list
= folder_get_list();
1262 for (; list
!= NULL
; list
= list
->next
) {
1263 Folder
*folder
= list
->data
;
1265 folderview_check_new(folder
);
1268 folder_write_list();
1269 folderview_set_all();
1271 label_window_destroy(window
);
1272 main_window_unlock(folderview
->mainwin
);
1276 static gboolean
folderview_have_children_sub(FolderView
*folderview
,
1282 if (!item
|| !item
->folder
|| !item
->folder
->node
)
1285 node
= item
->folder
->node
;
1287 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1288 node
= node
->children
;
1290 if (in_sub
&& item
->total_msgs
> 0) {
1294 while (node
!= NULL
) {
1295 if (node
&& node
->data
) {
1296 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1298 if (folderview_have_children_sub(folderview
,
1307 static gboolean
folderview_have_children(FolderView
*folderview
,
1310 return folderview_have_children_sub(folderview
, item
, FALSE
);
1313 static gboolean
folderview_have_new_children_sub(FolderView
*folderview
,
1319 if (!item
|| !item
->folder
|| !item
->folder
->node
)
1322 node
= item
->folder
->node
;
1324 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1325 node
= node
->children
;
1328 (item
->new_msgs
> 0 ||
1329 (folder_has_parent_of_type(item
, F_QUEUE
) && item
->total_msgs
> 0))) {
1333 while (node
!= NULL
) {
1334 if (node
&& node
->data
) {
1335 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1337 if (folderview_have_new_children_sub(folderview
,
1346 static gboolean
folderview_have_new_children(FolderView
*folderview
,
1349 return folderview_have_new_children_sub(folderview
, item
, FALSE
);
1352 static gboolean
folderview_have_unread_children_sub(FolderView
*folderview
,
1358 if (!item
|| !item
->folder
|| !item
->folder
->node
)
1361 node
= item
->folder
->node
;
1363 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1364 node
= node
->children
;
1367 (item
->unread_msgs
> 0 ||
1368 (folder_has_parent_of_type(item
, F_QUEUE
) && item
->total_msgs
> 0))) {
1372 while (node
!= NULL
) {
1373 if (node
&& node
->data
) {
1374 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1376 if (folderview_have_unread_children_sub(folderview
,
1386 static gboolean
folderview_have_unread_children(FolderView
*folderview
,
1389 return folderview_have_unread_children_sub(folderview
, item
, FALSE
);
1392 static gboolean
folderview_have_read_children_sub(FolderView
*folderview
,
1398 if (!item
|| !item
->folder
|| !item
->folder
->node
) {
1402 node
= item
->folder
->node
;
1404 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1405 node
= node
->children
;
1408 (((item
->total_msgs
> 0) &&
1409 (item
->unread_msgs
!= (item
->total_msgs
- item
->ignored_msgs
))))) {
1413 while (node
!= NULL
) {
1414 if (node
&& node
->data
) {
1415 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1417 if (folderview_have_read_children_sub(folderview
,
1428 static gboolean
folderview_have_read_children(FolderView
*folderview
,
1431 return folderview_have_read_children_sub(folderview
, item
, FALSE
);
1434 static gboolean
folderview_have_matching_children_sub(FolderView
*folderview
,
1440 if (!item
|| !item
->folder
|| !item
->folder
->node
)
1443 node
= item
->folder
->node
;
1445 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1446 node
= node
->children
;
1448 if (in_sub
&& item
->search_match
){
1452 while (node
!= NULL
) {
1453 if (node
&& node
->data
) {
1454 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1456 if (folderview_have_matching_children_sub(folderview
,
1466 static gboolean
folderview_have_matching_children(FolderView
*folderview
,
1469 return folderview_have_matching_children_sub(folderview
, item
, FALSE
);
1472 static gboolean
folderview_have_marked_children_sub(FolderView
*folderview
,
1478 if (!item
|| !item
->folder
|| !item
->folder
->node
)
1481 node
= item
->folder
->node
;
1483 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1484 node
= node
->children
;
1486 if (item
->marked_msgs
!= 0) {
1490 while (node
!= NULL
) {
1491 if (node
&& node
->data
) {
1492 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1494 if (folderview_have_marked_children_sub(folderview
,
1503 static gboolean
folderview_have_marked_children(FolderView
*folderview
,
1506 return folderview_have_marked_children_sub(folderview
, item
, FALSE
);
1509 static void folderview_update_node(FolderView
*folderview
, GtkCMCTreeNode
*node
)
1511 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
1512 GtkStyle
*style
= NULL
, *prev_style
;
1514 GdkPixbuf
*xpm
, *openxpm
;
1515 static GdkPixbuf
*searchicon
;
1516 gboolean mark
= FALSE
;
1519 gboolean add_unread_mark
;
1520 gboolean add_sub_match_mark
;
1521 gboolean use_bold
, use_color
;
1522 gint
*col_pos
= folderview
->col_pos
;
1523 SpecialFolderItemType stype
;
1526 item
= gtk_cmctree_node_get_row_data(ctree
, node
);
1527 cm_return_if_fail(item
!= NULL
);
1529 if (!GTK_CMCTREE_ROW(node
)->expanded
)
1530 mark
= folderview_have_marked_children(folderview
, item
);
1532 mark
= (item
->marked_msgs
!= 0);
1534 stype
= item
->stype
;
1535 if (stype
== F_NORMAL
) {
1536 if (folder_has_parent_of_type(item
, F_TRASH
))
1538 else if (folder_has_parent_of_type(item
, F_DRAFT
))
1540 else if (folder_has_parent_of_type(item
, F_OUTBOX
))
1542 else if (folder_has_parent_of_type(item
, F_QUEUE
))
1547 if (item
->hide_read_msgs
|| item
->hide_read_threads
) {
1548 xpm
= mark
?m_inboxhrmxpm
:inboxhrmxpm
;
1549 openxpm
= mark
?m_inboxopenhrmxpm
:inboxopenhrmxpm
;
1551 xpm
= mark
?m_inboxxpm
:inboxxpm
;
1552 openxpm
= mark
?m_inboxopenxpm
:inboxopenxpm
;
1556 if (item
->hide_read_msgs
|| item
->hide_read_threads
) {
1557 xpm
= mark
?m_outboxhrmxpm
:outboxhrmxpm
;
1558 openxpm
= mark
?m_outboxopenhrmxpm
:outboxopenhrmxpm
;
1560 xpm
= mark
?m_outboxxpm
:outboxxpm
;
1561 openxpm
= mark
?m_outboxopenxpm
:outboxopenxpm
;
1565 if (item
->hide_read_msgs
|| item
->hide_read_threads
) {
1566 xpm
= mark
?m_queuehrmxpm
:queuehrmxpm
;
1567 openxpm
= mark
?m_queueopenhrmxpm
:queueopenhrmxpm
;
1569 xpm
= mark
?m_queuexpm
:queuexpm
;
1570 openxpm
= mark
?m_queueopenxpm
:queueopenxpm
;
1574 if (item
->hide_read_msgs
|| item
->hide_read_threads
) {
1575 xpm
= mark
?m_trashhrmxpm
:trashhrmxpm
;
1576 openxpm
= mark
?m_trashopenhrmxpm
:trashopenhrmxpm
;
1578 xpm
= mark
?m_trashxpm
:trashxpm
;
1579 openxpm
= mark
?m_trashopenxpm
:trashopenxpm
;
1583 xpm
= mark
?m_draftsxpm
:draftsxpm
;
1584 openxpm
= mark
?m_draftsopenxpm
:draftsopenxpm
;
1588 FOLDER_TYPE(item
->folder
) == F_IMAP
&&
1589 item
->folder
->account
->imap_subsonly
) {
1590 xpm
= mark
?m_foldersubsxpm
:foldersubsxpm
;
1591 openxpm
= foldersubsopenxpm
;
1592 } else if (item
->no_select
) {
1593 xpm
= mark
?m_foldernoselectxpm
:foldernoselectxpm
;
1594 openxpm
= foldernoselectopenxpm
;
1595 } else if (item
->hide_read_msgs
|| item
->hide_read_threads
) {
1596 xpm
= mark
?m_folderhrmxpm
:folderhrmxpm
;
1597 openxpm
= mark
?m_folderopenhrmxpm
:folderopenhrmxpm
;
1599 xpm
= mark
?m_folderxpm
:folderxpm
;
1600 openxpm
= mark
?m_folderopenxpm
:folderopenxpm
;
1604 name
= folder_item_get_name(item
);
1606 if (!GTK_CMCTREE_ROW(node
)->expanded
) {
1607 add_unread_mark
= folderview_have_unread_children(
1609 add_sub_match_mark
= folderview_have_matching_children(
1612 add_unread_mark
= FALSE
;
1613 add_sub_match_mark
= FALSE
;
1616 if (item
->search_match
) {
1618 stock_pixbuf_gdk(STOCK_PIXMAP_QUICKSEARCH
,
1621 xpm
= openxpm
= searchicon
;
1625 if (prefs_common
.display_folder_unread
) {
1626 if (folder_has_parent_of_type(item
, F_QUEUE
)) {
1627 /* only total_msgs matters here */
1628 if (item
->total_msgs
> 0) {
1629 /* show total number (should be equal to the unread number)
1631 str
= g_strdup_printf("%s (%d%s%s)",
1632 name
, item
->total_msgs
,
1633 (add_unread_mark
|| add_sub_match_mark
) ? "+" : "",
1634 (item
->unreadmarked_msgs
> 0) ? "!" : "");
1637 if (prefs_common
.display_folder_unread
== 1) {
1638 if (item
->unread_msgs
> 0) {
1639 /* show unread number and signs */
1640 str
= g_strdup_printf("%s (%d%s%s)",
1641 name
, item
->unread_msgs
,
1642 (add_unread_mark
|| add_sub_match_mark
) ? "+" : "",
1643 (item
->unreadmarked_msgs
> 0) ? "!" : "");
1646 if (item
->total_msgs
> 0) {
1647 /* show unread number, total number and signs if any */
1648 str
= g_strdup_printf("%s (%d/%d%s%s)",
1649 name
, item
->unread_msgs
, item
->total_msgs
,
1650 (add_unread_mark
|| add_sub_match_mark
) ? "+" : "",
1651 (item
->unreadmarked_msgs
> 0) ? "!" : "");
1655 if ((str
== NULL
) &&
1656 (add_unread_mark
|| add_sub_match_mark
|| (item
->unreadmarked_msgs
> 0))) {
1657 /* no unread/total numbers, but at least one sign */
1658 str
= g_strdup_printf("%s (%s%s)",
1660 (add_unread_mark
|| add_sub_match_mark
) ? "+" : "",
1661 (item
->unreadmarked_msgs
> 0) ? "!" : "");
1665 /* last fallback, folder name only or with +! sign */
1666 if (item
->unreadmarked_msgs
> 0 && add_sub_match_mark
) {
1667 str
= g_strdup_printf("%s%s",
1669 } else if (item
->unreadmarked_msgs
> 0) {
1670 str
= g_strdup_printf("%s%s",
1672 } else if (add_sub_match_mark
) {
1673 str
= g_strdup_printf("%s%s",
1676 str
= g_strdup_printf("%s", name
);
1679 gtk_cmctree_set_node_info(ctree
, node
, str
, FOLDER_SPACING
,
1681 FALSE
, GTK_CMCTREE_ROW(node
)->expanded
);
1685 if (!folder_item_parent(item
)) {
1686 gtk_cmctree_node_set_text(ctree
, node
, col_pos
[F_COL_NEW
], "-");
1687 gtk_cmctree_node_set_text(ctree
, node
, col_pos
[F_COL_UNREAD
], "-");
1688 gtk_cmctree_node_set_text(ctree
, node
, col_pos
[F_COL_TOTAL
], "-");
1690 gtk_cmctree_node_set_text(ctree
, node
, col_pos
[F_COL_NEW
], item
->new_msgs
> 0 ? itos(item
->new_msgs
) : prefs_common
.zero_replacement
);
1691 gtk_cmctree_node_set_text(ctree
, node
, col_pos
[F_COL_UNREAD
], item
->unread_msgs
> 0 ? itos(item
->unread_msgs
) : prefs_common
.zero_replacement
);
1692 gtk_cmctree_node_set_text(ctree
, node
, col_pos
[F_COL_TOTAL
], item
->total_msgs
> 0 ? itos(item
->total_msgs
) : prefs_common
.zero_replacement
);
1695 if (folder_has_parent_of_type(item
, F_OUTBOX
) ||
1696 folder_has_parent_of_type(item
, F_TRASH
)) {
1697 use_bold
= use_color
= FALSE
;
1698 } else if (folder_has_parent_of_type(item
, F_QUEUE
)) {
1699 GSList
*list
= folder_item_get_msg_list(item
);
1701 use_bold
= use_color
= FALSE
;
1702 for (cur
= list
; cur
; cur
= cur
->next
) {
1703 MsgInfo
*msginfo
= (MsgInfo
*)cur
->data
;
1704 if (!MSG_IS_DELETED(msginfo
->flags
)) {
1705 /* highlight queue folder if there are any messages */
1706 use_bold
= use_color
= TRUE
;
1710 if (!GTK_CMCTREE_ROW(node
)->expanded
&&
1711 use_bold
== FALSE
&&
1712 folderview_have_children(folderview
, item
))
1713 use_bold
= use_color
= TRUE
;
1714 procmsg_msg_list_free(list
);
1716 /* if unread messages exist or target folder is set, print with bold font */
1717 use_bold
= (item
->unread_msgs
> 0 || item
->new_msgs
> 0 || item
->op_count
> 0)
1719 /* if new messages exist, print with colored letter */
1721 (item
->new_msgs
> 0) ||
1723 folderview_have_new_children(folderview
, item
));
1726 gtk_cmctree_node_set_foreground(ctree
, node
, NULL
);
1730 if (item
->op_count
> 0) {
1731 gtk_cmctree_node_set_foreground(ctree
, node
, &folderview
->color_op
);
1732 } else if (use_color
) {
1733 gtk_cmctree_node_set_foreground(ctree
, node
, &folderview
->color_new
);
1734 } else if (item
->prefs
->color
!= 0) {
1735 gtkut_convert_int_to_gdk_color(item
->prefs
->color
, &gdk_color
);
1736 gtk_cmctree_node_set_foreground(ctree
, node
, &gdk_color
);
1738 } else if (use_color
)
1739 gtk_cmctree_node_set_foreground(ctree
, node
, &folderview
->color_new
);
1740 else if (item
->op_count
> 0)
1741 gtk_cmctree_node_set_foreground(ctree
, node
, &folderview
->color_op
);
1742 else if (item
->prefs
->color
!= 0) {
1743 gtkut_convert_int_to_gdk_color(item
->prefs
->color
, &gdk_color
);
1744 gtk_cmctree_node_set_foreground(ctree
, node
, &gdk_color
);
1747 gtk_cmctree_node_set_row_style(ctree
, node
, style
);
1749 prev_style
= gtk_cmctree_node_get_row_style(ctree
, node
);
1751 GtkStyle
*ctree_style
= gtk_widget_get_style(GTK_WIDGET(ctree
));
1753 style
= gtk_style_copy(prev_style
);
1754 style
->text
[GTK_STATE_NORMAL
] = ctree_style
->text
[GTK_STATE_NORMAL
];
1755 style
->text
[GTK_STATE_SELECTED
] = ctree_style
->text
[GTK_STATE_SELECTED
];
1756 gtk_cmctree_node_set_row_style(ctree
, node
, style
);
1757 g_object_unref(style
);
1760 if ((node
= gtkut_ctree_find_collapsed_parent(ctree
, node
)) != NULL
)
1761 folderview_update_node(folderview
, node
);
1764 void folderview_update_search_icon(FolderItem
*item
, gboolean matches
)
1767 FolderView
*folderview
;
1769 GtkCMCTreeNode
*node
;
1771 cm_return_if_fail(item
!= NULL
);
1773 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
) {
1774 folderview
= (FolderView
*)list
->data
;
1775 ctree
= GTK_CMCTREE(folderview
->ctree
);
1777 node
= gtk_cmctree_find_by_row_data(ctree
, NULL
, item
);
1778 if (node
&& item
->search_match
!= matches
) {
1779 item
->search_match
= matches
;
1780 folderview_update_node(folderview
, node
);
1785 static gboolean
folderview_update_item_claws(gpointer source
, gpointer data
)
1787 FolderItemUpdateData
*update_info
= (FolderItemUpdateData
*)source
;
1788 FolderView
*folderview
= (FolderView
*)data
;
1790 GtkCMCTreeNode
*node
;
1791 cm_return_val_if_fail(update_info
!= NULL
, TRUE
);
1792 cm_return_val_if_fail(update_info
->item
!= NULL
, TRUE
);
1793 cm_return_val_if_fail(folderview
!= NULL
, FALSE
);
1795 ctree
= GTK_CMCTREE(folderview
->ctree
);
1797 node
= gtk_cmctree_find_by_row_data(ctree
, NULL
, update_info
->item
);
1800 if (update_info
->update_flags
& (F_ITEM_UPDATE_MSGCNT
| F_ITEM_UPDATE_NAME
))
1801 folderview_update_node(folderview
, node
);
1803 if ((update_info
->update_flags
& F_ITEM_UPDATE_CONTENT
) &&
1804 update_info
->item
== folderview
->summaryview
->folder_item
&&
1805 update_info
->item
!= NULL
)
1806 if (!quicksearch_has_sat_predicate(folderview
->summaryview
->quicksearch
))
1807 summary_show(folderview
->summaryview
, update_info
->item
, FALSE
);
1813 static gboolean
folderview_gnode_func(GtkCMCTree
*ctree
, guint depth
,
1814 GNode
*gnode
, GtkCMCTreeNode
*cnode
,
1817 FolderView
*folderview
= (FolderView
*)data
;
1818 FolderItem
*item
= FOLDER_ITEM(gnode
->data
);
1820 cm_return_val_if_fail(item
!= NULL
, FALSE
);
1822 gtk_cmctree_node_set_row_data(ctree
, cnode
, item
);
1823 folderview_update_node(folderview
, cnode
);
1828 static void folderview_expand_func(GtkCMCTree
*ctree
, GtkCMCTreeNode
*node
,
1831 FolderView
*folderview
= (FolderView
*)data
;
1834 if (GTK_CMCTREE_ROW(node
)->children
) {
1835 item
= gtk_cmctree_node_get_row_data(ctree
, node
);
1836 cm_return_if_fail(item
!= NULL
);
1838 if (!item
->collapsed
)
1839 gtk_cmctree_expand(ctree
, node
);
1841 folderview_update_node(folderview
, node
);
1845 static void set_special_folder(GtkCMCTree
*ctree
, FolderItem
*item
,
1846 GtkCMCTreeNode
*root
, GtkCMCTreeNode
**prev
)
1849 GtkCMCTreeNode
*node
, *parent
, *sibling
;
1851 node
= gtk_cmctree_find_by_row_data(ctree
, root
, item
);
1853 g_warning("%s not found.", item
->path
);
1855 parent
= GTK_CMCTREE_ROW(node
)->parent
;
1856 if (*prev
&& parent
== GTK_CMCTREE_ROW(*prev
)->parent
)
1857 sibling
= GTK_CMCTREE_ROW(*prev
)->sibling
;
1859 sibling
= GTK_CMCTREE_ROW(parent
)->children
;
1863 tmp
= gtk_cmctree_node_get_row_data
1865 if (tmp
&& tmp
->stype
!= F_NORMAL
)
1866 sibling
= GTK_CMCTREE_ROW(sibling
)->sibling
;
1870 if (node
!= sibling
)
1871 gtk_cmctree_move(ctree
, node
, parent
, sibling
);
1878 static void folderview_sort_folders(FolderView
*folderview
, GtkCMCTreeNode
*root
,
1881 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
1882 GtkCMCTreeNode
*prev
= NULL
;
1884 gtk_cmclist_freeze(GTK_CMCLIST(ctree
));
1885 gtk_sctree_sort_recursive(ctree
, root
);
1886 if (root
&& GTK_CMCTREE_ROW(root
)->parent
) {
1887 gtk_cmclist_thaw(GTK_CMCLIST(ctree
));
1890 set_special_folder(ctree
, folder
->inbox
, root
, &prev
);
1891 set_special_folder(ctree
, folder
->outbox
, root
, &prev
);
1892 set_special_folder(ctree
, folder
->draft
, root
, &prev
);
1893 set_special_folder(ctree
, folder
->queue
, root
, &prev
);
1894 set_special_folder(ctree
, folder
->trash
, root
, &prev
);
1895 gtk_cmclist_thaw(GTK_CMCLIST(ctree
));
1898 static void folderview_append_folder(FolderView
*folderview
, Folder
*folder
)
1900 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
1901 GtkCMCTreeNode
*root
;
1903 cm_return_if_fail(folder
!= NULL
);
1905 root
= gtk_sctree_insert_gnode(ctree
, NULL
, NULL
, folder
->node
,
1906 folderview_gnode_func
, folderview
);
1907 gtk_cmctree_pre_recursive(ctree
, root
, folderview_expand_func
,
1909 folderview_sort_folders(folderview
, root
, folder
);
1912 /* callback functions */
1913 static void folderview_set_sens_and_popup_menu(FolderView
*folderview
, gint row
,
1914 GdkEventButton
*event
)
1918 FolderViewPopup
*fpopup
;
1919 GtkActionGroup
*action_group
;
1921 FolderItem
*special_trash
= NULL
, *special_queue
= NULL
;
1923 GtkUIManager
*ui_manager
= gtk_ui_manager_new();
1925 if (folderview
->ui_manager
)
1926 g_object_unref(folderview
->ui_manager
);
1928 folderview
->ui_manager
= ui_manager
;
1929 item
= folderview_get_selected_item(folderview
);
1931 cm_return_if_fail(item
!= NULL
);
1932 cm_return_if_fail(item
->folder
!= NULL
);
1933 folder
= item
->folder
;
1935 fpopup
= g_hash_table_lookup(folderview_popups
, folder
->klass
->idstr
);
1938 action_group
= g_hash_table_lookup(folderview
->popups
, folder
->klass
->idstr
);
1940 fpopup
= g_hash_table_lookup(folderview_popups
, "common");
1941 action_group
= g_hash_table_lookup(folderview
->popups
, "common");
1944 gtk_ui_manager_insert_action_group(ui_manager
, action_group
, 0);
1945 MENUITEM_ADDUI_MANAGER(ui_manager
, "/", "Popup", "Popup", GTK_UI_MANAGER_MENUBAR
)
1946 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup", "FolderViewPopup", "FolderViewPopup", GTK_UI_MANAGER_MENU
)
1948 if (fpopup
->add_menuitems
)
1949 fpopup
->add_menuitems(ui_manager
, item
);
1951 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "MarkAllRead", "FolderViewPopup/MarkAllRead", GTK_UI_MANAGER_MENUITEM
)
1952 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "MarkAllUnread", "FolderViewPopup/MarkAllUnread", GTK_UI_MANAGER_MENUITEM
)
1953 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "MarkAllReadRec", "FolderViewPopup/MarkAllReadRec", GTK_UI_MANAGER_MENUITEM
)
1954 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "MarkAllUnreadRec", "FolderViewPopup/MarkAllUnreadRec", GTK_UI_MANAGER_MENUITEM
)
1955 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "Separator1", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR
)
1956 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "RunProcessing", "FolderViewPopup/RunProcessing", GTK_UI_MANAGER_MENUITEM
)
1957 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "SearchFolder", "FolderViewPopup/SearchFolder", GTK_UI_MANAGER_MENUITEM
)
1958 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "Properties", "FolderViewPopup/Properties", GTK_UI_MANAGER_MENUITEM
)
1959 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "Processing", "FolderViewPopup/Processing", GTK_UI_MANAGER_MENUITEM
)
1961 if (fpopup
->set_sensitivity
!= NULL
)
1962 fpopup
->set_sensitivity(ui_manager
, item
);
1964 if (NULL
!= (ac
= account_find_from_item(item
))) {
1965 special_trash
= account_get_special_folder(ac
, F_TRASH
);
1966 special_queue
= account_get_special_folder(ac
, F_QUEUE
);
1969 if ((item
== folder
->trash
|| item
== special_trash
1970 || folder_has_parent_of_type(item
, F_TRASH
))) {
1971 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "SeparatorTrash", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR
)
1972 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "EmptyTrash", "FolderViewPopup/EmptyTrash", GTK_UI_MANAGER_MENUITEM
)
1975 if ((item
== folder
->queue
|| item
== special_queue
1976 || folder_has_parent_of_type(item
, F_QUEUE
))) {
1977 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "SeparatorQueue", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR
)
1978 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "SendQueue", "FolderViewPopup/SendQueue", GTK_UI_MANAGER_MENUITEM
)
1981 #define SET_SENS(name, sens) \
1982 cm_menu_set_sensitive_full(ui_manager, "Popup/"name, sens)
1984 SET_SENS("FolderViewPopup/MarkAllRead", item
->unread_msgs
> 0);
1985 SET_SENS("FolderViewPopup/MarkAllUnread", (item
->total_msgs
> 0) &&
1986 (item
->unread_msgs
!= (item
->total_msgs
- item
->ignored_msgs
)));
1987 SET_SENS("FolderViewPopup/MarkAllReadRec", folderview_have_unread_children(folderview
,item
));
1988 SET_SENS("FolderViewPopup/MarkAllUnreadRec", folderview_have_read_children(folderview
,item
));
1989 SET_SENS("FolderViewPopup/SearchFolder", item
->total_msgs
> 0 &&
1990 folderview
->selected
== folderview
->opened
);
1991 SET_SENS("FolderViewPopup/Properties", TRUE
);
1993 SET_SENS("FolderViewPopup/RunProcessing", item
->prefs
->processing
&&
1994 item
->total_msgs
>= 1 && !item
->processing_pending
);
1995 SET_SENS("FolderViewPopup/Processing", item
->node
->parent
!= NULL
&&
1996 !item
->no_select
&& !item
->processing_pending
);
1998 if (item
== folder
->trash
|| item
== special_trash
1999 || folder_has_parent_of_type(item
, F_TRASH
)) {
2000 GSList
*msglist
= folder_item_get_msg_list(item
);
2001 SET_SENS("FolderViewPopup/EmptyTrash", msglist
!= NULL
);
2002 procmsg_msg_list_free(msglist
);
2004 if (item
== folder
->queue
|| item
== special_queue
2005 || folder_has_parent_of_type(item
, F_QUEUE
)) {
2006 GSList
*msglist
= folder_item_get_msg_list(item
);
2007 SET_SENS("FolderViewPopup/SendQueue", msglist
!= NULL
);
2008 procmsg_msg_list_free(msglist
);
2012 popup
= gtk_menu_item_get_submenu(GTK_MENU_ITEM(
2013 gtk_ui_manager_get_widget(ui_manager
, "/Popup/FolderViewPopup")) );
2014 g_signal_connect(G_OBJECT(popup
), "selection_done",
2015 G_CALLBACK(folderview_popup_close
),
2017 gtk_menu_popup(GTK_MENU(popup
), NULL
, NULL
, NULL
, NULL
,
2018 event
->button
, event
->time
);
2021 static gboolean
folderview_button_pressed(GtkWidget
*ctree
, GdkEventButton
*event
,
2022 FolderView
*folderview
)
2024 GtkCMCList
*clist
= GTK_CMCLIST(ctree
);
2025 gint prev_row
= -1, row
= -1, column
= -1;
2027 if (!event
) return FALSE
;
2028 if (event
->window
!= clist
->clist_window
) return FALSE
;
2030 if (event
->button
== 1 || event
->button
== 2) {
2031 if (!gtk_sctree_is_hot_spot (GTK_SCTREE(clist
), event
->x
, event
->y
))
2032 folderview
->open_folder
= TRUE
;
2034 if (event
->type
== GDK_2BUTTON_PRESS
) {
2035 if (clist
->selection
) {
2036 GtkCMCTreeNode
*node
;
2038 node
= GTK_CMCTREE_NODE(clist
->selection
->data
);
2040 gtk_cmctree_toggle_expansion(
2043 folderview
->open_folder
= FALSE
;
2050 if (event
->button
== 2 || event
->button
== 3) {
2052 if (clist
->selection
) {
2053 GtkCMCTreeNode
*node
;
2055 node
= GTK_CMCTREE_NODE(clist
->selection
->data
);
2057 prev_row
= gtkut_ctree_get_nth_from_node
2058 (GTK_CMCTREE(ctree
), node
);
2061 if (!gtk_cmclist_get_selection_info(clist
, event
->x
, event
->y
,
2064 if (prev_row
!= row
) {
2065 gtk_cmclist_unselect_all(clist
);
2066 if (event
->button
== 2)
2067 folderview_select_node
2069 gtk_cmctree_node_nth(GTK_CMCTREE(ctree
),
2072 gtk_cmclist_select_row(clist
, row
, column
);
2076 if (event
->button
!= 3) return FALSE
;
2078 folderview_set_sens_and_popup_menu(folderview
, row
, event
);
2082 static gboolean
folderview_button_released(GtkWidget
*ctree
, GdkEventButton
*event
,
2083 FolderView
*folderview
)
2085 int row
= -1, column
= -1;
2087 if (!event
) return FALSE
;
2089 if (!gtk_cmclist_get_selection_info(GTK_CMCLIST(ctree
), event
->x
, event
->y
,
2092 if (event
->button
== 1 && folderview
->open_folder
== FALSE
&&
2093 folderview
->opened
!= NULL
) {
2094 gtkut_ctree_set_focus_row(GTK_CMCTREE(ctree
),
2095 folderview
->opened
);
2096 gtk_cmctree_select(GTK_CMCTREE(ctree
), folderview
->opened
);
2102 #define BREAK_ON_MODIFIER_KEY() \
2103 if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0) break
2105 static gboolean
folderview_key_pressed(GtkWidget
*widget
, GdkEventKey
*event
,
2106 FolderView
*folderview
)
2108 GtkCMCTreeNode
*node
;
2111 if (!event
) return FALSE
;
2113 if (quicksearch_has_focus(folderview
->summaryview
->quicksearch
))
2116 switch (event
->keyval
) {
2118 if (folderview
->selected
) {
2119 if (GTK_CMCTREE_ROW(folderview
->selected
)->children
!= NULL
2120 && !GTK_CMCTREE_ROW(folderview
->selected
)->expanded
)
2121 gtk_cmctree_expand(GTK_CMCTREE(folderview
->ctree
),
2122 folderview
->selected
);
2124 folderview_select_node(folderview
,
2125 folderview
->selected
);
2129 case GDK_KEY_Return
:
2130 if (folderview
->selected
&& GTK_CMCTREE_ROW(folderview
->selected
)->children
) {
2131 gtk_cmctree_toggle_expansion(
2132 GTK_CMCTREE(folderview
->ctree
),
2133 folderview
->selected
);
2137 case GDK_KEY_Return
:
2138 case GDK_KEY_KP_Enter
:
2139 if (folderview
->selected
)
2140 folderview_select_node(folderview
, folderview
->selected
);
2144 BREAK_ON_MODIFIER_KEY();
2145 if (folderview
->selected
) {
2146 if (folderview
->opened
== folderview
->selected
&&
2147 (!folderview
->summaryview
->folder_item
||
2148 folderview
->summaryview
->folder_item
->total_msgs
== 0))
2149 folderview_select_next_with_flag(folderview
, MSG_UNREAD
);
2151 folderview_select_node(folderview
,
2152 folderview
->selected
);
2156 if (folderview
->selected
) {
2157 /* If the folder is expanded and can be collapsed, do that... */
2158 if (GTK_CMCTREE_ROW(folderview
->selected
)->expanded
&&
2159 GTK_CMCTREE_ROW(folderview
->selected
)->children
!= NULL
) {
2160 gtk_cmctree_collapse(GTK_CMCTREE(folderview
->ctree
),
2161 folderview
->selected
);
2163 /* ...otherwise, move cursor to its parent node. */
2164 if ((item
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(folderview
->ctree
),
2165 folderview
->selected
))) {
2166 if ((node
= gtk_cmctree_find_by_row_data(GTK_CMCTREE(folderview
->ctree
),
2167 NULL
, folder_item_parent(item
)))) {
2168 gtk_sctree_select(GTK_SCTREE(folderview
->ctree
), node
);
2169 if (!gtk_cmctree_node_is_visible(GTK_CMCTREE(folderview
->ctree
), node
))
2170 gtk_cmctree_node_moveto(GTK_CMCTREE(folderview
->ctree
),
2179 if (event
->keyval
== GDK_KEY_Home
)
2180 node
= gtk_cmctree_node_nth(GTK_CMCTREE(folderview
->ctree
), 0);
2182 node
= gtk_cmctree_last(GTK_CMCTREE(folderview
->ctree
),
2183 gtk_cmctree_node_nth(GTK_CMCTREE(folderview
->ctree
), 0));
2185 gtk_sctree_select(GTK_SCTREE(folderview
->ctree
), node
);
2187 if (!gtk_cmctree_node_is_visible(GTK_CMCTREE(folderview
->ctree
), node
))
2188 gtk_cmctree_node_moveto(GTK_CMCTREE(folderview
->ctree
),
2198 typedef struct _PostponedSelectData
2201 GtkCMCTreeNode
*row
;
2203 FolderView
*folderview
;
2204 } PostponedSelectData
;
2206 static gboolean
postpone_select(void *data
)
2208 PostponedSelectData
*psdata
= (PostponedSelectData
*)data
;
2209 debug_print("trying again\n");
2211 psdata
->folderview
->postpone_select_id
= 0;
2212 psdata
->folderview
->open_folder
= TRUE
;
2213 main_window_cursor_normal(psdata
->folderview
->mainwin
);
2214 STATUSBAR_POP(psdata
->folderview
->mainwin
);
2215 folderview_selected(psdata
->ctree
, psdata
->row
,
2216 psdata
->column
, psdata
->folderview
);
2221 void folderview_close_opened(FolderView
*folderview
, gboolean dirty
)
2223 if (folderview
->opened
) {
2225 folderview
->opened
= NULL
;
2229 FolderItem
*olditem
=
2230 gtk_cmctree_node_get_row_data(GTK_CMCTREE(folderview
->ctree
),
2231 folderview
->opened
);
2233 gchar
*buf
= g_strdup_printf(_("Closing folder %s..."),
2234 olditem
->path
? olditem
->path
:olditem
->name
);
2235 /* will be null if we just moved the previously opened folder */
2236 STATUSBAR_PUSH(folderview
->mainwin
, buf
);
2237 main_window_cursor_wait(folderview
->mainwin
);
2239 summary_save_prefs_to_folderitem(folderview
->summaryview
, olditem
);
2240 summary_show(folderview
->summaryview
, NULL
, FALSE
);
2241 folder_item_close(olditem
);
2242 main_window_cursor_normal(folderview
->mainwin
);
2243 STATUSBAR_POP(folderview
->mainwin
);
2244 if (olditem
->folder
->klass
->item_closed
)
2245 olditem
->folder
->klass
->item_closed(olditem
);
2250 if (folderview
->opened
&&
2251 !GTK_CMCTREE_ROW(folderview
->opened
)->children
)
2252 gtk_cmctree_collapse(GTK_CMCTREE(folderview
->ctree
), folderview
->opened
);
2254 folderview
->opened
= NULL
;
2256 static void folderview_selected(GtkCMCTree
*ctree
, GtkCMCTreeNode
*row
,
2257 gint column
, FolderView
*folderview
)
2259 static gboolean can_select
= TRUE
; /* exclusive lock */
2264 GtkCMCTreeNode
*old_opened
= folderview
->opened
;
2266 folderview
->selected
= row
;
2268 debug_print("newly selected %p, opened %p\n", folderview
->selected
,
2269 folderview
->opened
);
2270 if (folderview
->opened
== row
) {
2271 folderview
->open_folder
= FALSE
;
2276 item
= gtk_cmctree_node_get_row_data(ctree
, row
);
2279 folderview
->open_folder
= FALSE
;
2283 if (!can_select
|| summary_is_locked(folderview
->summaryview
)) {
2284 if (folderview
->opened
) {
2285 gtkut_ctree_set_focus_row(ctree
, folderview
->opened
);
2286 gtk_cmctree_select(ctree
, folderview
->opened
);
2288 folderview
->open_folder
= FALSE
;
2293 if (!folderview
->open_folder
) {
2300 /* Save cache for old folder */
2301 /* We don't want to lose all caches if app crashes */
2302 /* Resets folderview->opened to NULL */
2303 folderview_close_opened(folderview
, FALSE
);
2305 /* CLAWS: set compose button type: news folder items
2306 * always have a news folder as parent */
2308 toolbar_set_compose_button
2309 (folderview
->mainwin
->toolbar
,
2310 FOLDER_TYPE(item
->folder
) == F_NEWS
?
2311 COMPOSEBUTTON_NEWS
: COMPOSEBUTTON_MAIL
);
2314 debug_print("Folder %s is selected\n", item
->path
);
2316 if (!GTK_CMCTREE_ROW(row
)->children
)
2317 gtk_cmctree_expand(ctree
, row
);
2319 /* ungrab the mouse event */
2320 if (gtk_widget_has_grab(GTK_WIDGET(ctree
))) {
2321 gtk_grab_remove(GTK_WIDGET(ctree
));
2322 if (gdk_pointer_is_grabbed())
2323 gdk_pointer_ungrab(GDK_CURRENT_TIME
);
2327 /* TODO: wwp: avoid displaying (null) in the status bar */
2328 buf
= g_strdup_printf(_("Opening folder %s..."), item
->path
?
2329 item
->path
: "(null)");
2330 debug_print("%s\n", buf
);
2331 STATUSBAR_PUSH(folderview
->mainwin
, buf
);
2334 main_window_cursor_wait(folderview
->mainwin
);
2336 if (folderview
->scanning_folder
== item
->folder
) {
2339 res
= folder_item_open(item
);
2342 if (res
== -1 && item
->no_select
== FALSE
) {
2343 main_window_cursor_normal(folderview
->mainwin
);
2344 STATUSBAR_POP(folderview
->mainwin
);
2346 alertpanel_error(_("Folder could not be opened."));
2348 folderview
->open_folder
= FALSE
;
2352 } else if (res
== -2 && item
->no_select
== FALSE
) {
2353 PostponedSelectData
*data
= g_new0(PostponedSelectData
, 1);
2354 data
->ctree
= ctree
;
2356 data
->column
= column
;
2357 data
->folderview
= folderview
;
2358 debug_print("postponing open of %s till end of scan\n",
2359 item
->path
? item
->path
:item
->name
);
2360 folderview
->open_folder
= FALSE
;
2362 if (folderview
->postpone_select_id
!= 0)
2363 g_source_remove(folderview
->postpone_select_id
);
2364 folderview
->postpone_select_id
= g_timeout_add(500, postpone_select
, data
);
2369 main_window_cursor_normal(folderview
->mainwin
);
2372 summary_set_prefs_from_folderitem(folderview
->summaryview
, item
);
2373 opened
= summary_show(folderview
->summaryview
, item
, FALSE
);
2375 folder_clean_cache_memory(item
);
2378 gtkut_ctree_set_focus_row(ctree
, old_opened
);
2379 gtk_cmctree_select(ctree
, old_opened
);
2380 folderview
->opened
= old_opened
;
2382 folderview
->opened
= row
;
2383 if (gtk_cmctree_node_is_visible(ctree
, row
)
2384 != GTK_VISIBILITY_FULL
)
2385 gtk_cmctree_node_moveto(ctree
, row
, -1, 0.5, 0);
2388 STATUSBAR_POP(folderview
->mainwin
);
2390 folderview
->open_folder
= FALSE
;
2395 static void folderview_tree_expanded(GtkCMCTree
*ctree
, GtkCMCTreeNode
*node
,
2396 FolderView
*folderview
)
2400 item
= gtk_cmctree_node_get_row_data(ctree
, node
);
2401 cm_return_if_fail(item
!= NULL
);
2402 item
->collapsed
= FALSE
;
2403 folderview_update_node(folderview
, node
);
2406 static void folderview_tree_collapsed(GtkCMCTree
*ctree
, GtkCMCTreeNode
*node
,
2407 FolderView
*folderview
)
2411 item
= gtk_cmctree_node_get_row_data(ctree
, node
);
2412 cm_return_if_fail(item
!= NULL
);
2413 item
->collapsed
= TRUE
;
2414 folderview_update_node(folderview
, node
);
2417 static void folderview_popup_close(GtkMenuShell
*menu_shell
,
2418 FolderView
*folderview
)
2420 if (!folderview
->opened
) return;
2422 gtk_cmctree_select(GTK_CMCTREE(folderview
->ctree
), folderview
->opened
);
2425 static void folderview_col_resized(GtkCMCList
*clist
, gint column
, gint width
,
2426 FolderView
*folderview
)
2428 FolderColumnType type
= folderview
->col_state
[column
].type
;
2430 prefs_common
.folder_col_size
[type
] = width
;
2433 static void folderview_create_folder_node(FolderView
*folderview
, FolderItem
*item
)
2435 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
2436 gchar
*text
[N_FOLDER_COLS
] = {NULL
, "0", "0", "0"};
2437 GtkCMCTreeNode
*node
, *parent_node
;
2438 gint
*col_pos
= folderview
->col_pos
;
2439 FolderItemUpdateData hookdata
;
2441 parent_node
= gtk_cmctree_find_by_row_data(ctree
, NULL
, folder_item_parent(item
));
2442 if (parent_node
== NULL
)
2445 gtk_cmclist_freeze(GTK_CMCLIST(ctree
));
2447 text
[col_pos
[F_COL_FOLDER
]] = item
->name
;
2448 node
= gtk_sctree_insert_node(ctree
, parent_node
, NULL
, text
,
2453 gtk_cmctree_expand(ctree
, parent_node
);
2454 gtk_cmctree_node_set_row_data(ctree
, node
, item
);
2455 folderview_sort_folders(folderview
, parent_node
, item
->folder
);
2457 hookdata
.item
= item
;
2458 hookdata
.update_flags
= F_ITEM_UPDATE_NAME
;
2459 hookdata
.msg
= NULL
;
2460 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST
, &hookdata
);
2462 gtk_cmclist_thaw(GTK_CMCLIST(ctree
));
2465 static void folderview_empty_trash_cb(GtkAction
*action
, gpointer data
)
2467 FolderView
*folderview
= (FolderView
*)data
;
2469 GSList
*mlist
= NULL
;
2471 FolderItem
*special_trash
= NULL
;
2474 if (!folderview
->selected
) return;
2475 item
= folderview_get_selected_item(folderview
);
2476 cm_return_if_fail(item
!= NULL
);
2477 cm_return_if_fail(item
->folder
!= NULL
);
2479 if (NULL
!= (ac
= account_find_from_item(item
)))
2480 special_trash
= account_get_special_folder(ac
, F_TRASH
);
2482 if (item
!= item
->folder
->trash
&& item
!= special_trash
2483 && !folder_has_parent_of_type(item
, F_TRASH
)) return;
2485 if (prefs_common
.ask_on_clean
) {
2486 if (alertpanel(_("Empty trash"),
2487 _("Delete all messages in trash?"),
2488 GTK_STOCK_CANCEL
, _("_Empty trash"), NULL
,
2489 ALERTFOCUS_SECOND
) != G_ALERTALTERNATE
)
2493 mlist
= folder_item_get_msg_list(item
);
2495 for (cur
= mlist
; cur
!= NULL
; cur
= cur
->next
) {
2496 MsgInfo
* msginfo
= (MsgInfo
*) cur
->data
;
2497 if (MSG_IS_LOCKED(msginfo
->flags
))
2499 /* is it partially received? (partial_recv isn't cached) */
2500 if (msginfo
->total_size
!= 0 &&
2501 msginfo
->size
!= (off_t
)msginfo
->total_size
)
2502 partial_mark_for_delete(msginfo
);
2504 procmsg_msg_list_free(mlist
);
2506 folder_item_remove_all_msg(item
);
2509 static void folderview_send_queue_cb(GtkAction
*action
, gpointer data
)
2511 FolderView
*folderview
= (FolderView
*)data
;
2513 FolderItem
*special_queue
= NULL
;
2515 gchar
*errstr
= NULL
;
2517 if (!folderview
->selected
) return;
2518 item
= folderview_get_selected_item(folderview
);
2519 cm_return_if_fail(item
!= NULL
);
2520 cm_return_if_fail(item
->folder
!= NULL
);
2522 if (NULL
!= (ac
= account_find_from_item(item
)))
2523 special_queue
= account_get_special_folder(ac
, F_QUEUE
);
2525 if (item
!= item
->folder
->queue
&& item
!= special_queue
2526 && !folder_has_parent_of_type(item
, F_QUEUE
)) return;
2528 if (procmsg_queue_is_empty(item
))
2531 if (prefs_common
.work_offline
)
2532 if (alertpanel(_("Offline warning"),
2533 _("You're working offline. Override?"),
2534 GTK_STOCK_NO
, GTK_STOCK_YES
,
2535 NULL
, ALERTFOCUS_FIRST
) != G_ALERTALTERNATE
)
2538 /* ask for confirmation before sending queued messages only
2539 in online mode and if there is at least one message queued
2540 in any of the folder queue
2542 if (prefs_common
.confirm_send_queued_messages
) {
2543 if (!prefs_common
.work_offline
) {
2544 if (alertpanel(_("Send queued messages"),
2545 _("Send all queued messages?"),
2546 GTK_STOCK_CANCEL
, _("_Send"),
2547 NULL
, ALERTFOCUS_FIRST
) != G_ALERTALTERNATE
)
2552 if (procmsg_send_queue(item
, prefs_common
.savemsg
, &errstr
) < 0) {
2554 alertpanel_error_log(_("Some errors occurred while "
2555 "sending queued messages."));
2557 alertpanel_error_log(_("Some errors occurred "
2558 "while sending queued messages:\n%s"), errstr
);
2564 static void folderview_search_cb(GtkAction
*action
, gpointer data
)
2566 FolderView
*folderview
= (FolderView
*)data
;
2567 summary_search(folderview
->summaryview
);
2570 static void folderview_run_processing_cb(GtkAction
*action
, gpointer data
)
2572 FolderView
*folderview
= (FolderView
*)data
;
2575 if (!folderview
->selected
) return;
2577 item
= folderview_get_selected_item(folderview
);
2578 cm_return_if_fail(item
!= NULL
);
2579 cm_return_if_fail(item
->folder
!= NULL
);
2581 item
->processing_pending
= TRUE
;
2582 folder_item_apply_processing(item
);
2583 item
->processing_pending
= FALSE
;
2586 static void folderview_property_cb(GtkAction
*action
, gpointer data
)
2588 FolderView
*folderview
= (FolderView
*)data
;
2591 if (!folderview
->selected
) return;
2593 item
= folderview_get_selected_item(folderview
);
2594 cm_return_if_fail(item
!= NULL
);
2595 cm_return_if_fail(item
->folder
!= NULL
);
2597 prefs_folder_item_open(item
);
2600 static void folderview_recollapse_nodes(FolderView
*folderview
, GtkCMCTreeNode
*node
)
2602 GSList
*list
= NULL
;
2603 GSList
*done
= NULL
;
2604 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
2606 for (list
= folderview
->nodes_to_recollapse
; list
!= NULL
; list
= g_slist_next(list
)) {
2607 if (!gtkut_ctree_node_is_parent(GTK_CMCTREE_NODE(list
->data
), node
)
2608 && list
->data
!= node
) {
2609 gtk_cmctree_collapse(ctree
, GTK_CMCTREE_NODE(list
->data
));
2610 done
= g_slist_append(done
, GTK_CMCTREE_NODE(list
->data
));
2613 for (list
= done
; list
!= NULL
; list
= g_slist_next(list
)) {
2614 folderview
->nodes_to_recollapse
= g_slist_remove(folderview
->nodes_to_recollapse
,
2620 void folderview_move_folder(FolderView
*folderview
, FolderItem
*from_folder
,
2621 FolderItem
*to_folder
, gboolean copy
)
2623 FolderItem
*new_folder
= NULL
;
2627 cm_return_if_fail(folderview
!= NULL
);
2628 cm_return_if_fail(from_folder
!= NULL
);
2629 cm_return_if_fail(to_folder
!= NULL
);
2631 if (prefs_common
.warn_dnd
) {
2632 buf
= g_strdup_printf(copy
? _("Do you really want to copy folder '%s' in '%s'?"):
2633 _("Do you really want to make folder '%s' a subfolder of '%s'?"),
2634 from_folder
->name
, to_folder
->name
);
2635 status
= alertpanel_full(copy
? _("Copy folder"):_("Move folder"), buf
,
2636 GTK_STOCK_NO
, GTK_STOCK_YES
, NULL
, ALERTFOCUS_FIRST
,
2637 TRUE
, NULL
, ALERT_QUESTION
);
2640 if ((status
& ~G_ALERTDISABLE
) != G_ALERTALTERNATE
)
2642 else if (status
& G_ALERTDISABLE
)
2643 prefs_common
.warn_dnd
= FALSE
;
2646 buf
= g_strdup_printf(copy
? _("Copying %s to %s..."):_("Moving %s to %s..."),
2647 from_folder
->name
, to_folder
->name
);
2648 STATUSBAR_PUSH(folderview
->mainwin
, buf
);
2650 summary_clear_all(folderview
->summaryview
);
2651 folderview
->opened
= NULL
;
2652 folderview
->selected
= NULL
;
2653 gtk_widget_set_sensitive(GTK_WIDGET(folderview
->ctree
), FALSE
);
2655 main_window_cursor_wait(folderview
->mainwin
);
2657 statusbar_verbosity_set(FALSE
);
2658 folder_item_update_freeze();
2659 gtk_cmclist_freeze(GTK_CMCLIST(folderview
->ctree
));
2660 if ((status
= folder_item_move_to(from_folder
, to_folder
, &new_folder
, copy
)) == F_MOVE_OK
) {
2661 statusbar_verbosity_set(FALSE
);
2662 main_window_cursor_normal(folderview
->mainwin
);
2663 STATUSBAR_POP(folderview
->mainwin
);
2664 folder_item_update_thaw();
2665 folder_item_update_recursive(new_folder
, F_ITEM_UPDATE_MSGCNT
);
2667 folderview_sort_folders(folderview
,
2668 gtk_cmctree_find_by_row_data(GTK_CMCTREE(folderview
->ctree
),
2669 NULL
, to_folder
), new_folder
->folder
);
2670 folderview_select(folderview
, new_folder
);
2671 gtk_cmclist_thaw(GTK_CMCLIST(folderview
->ctree
));
2673 statusbar_verbosity_set(FALSE
);
2674 main_window_cursor_normal(folderview
->mainwin
);
2675 STATUSBAR_POP(folderview
->mainwin
);
2676 gtk_cmclist_thaw(GTK_CMCLIST(folderview
->ctree
));
2677 folder_item_update_thaw();
2679 case F_MOVE_FAILED_DEST_IS_PARENT
:
2680 alertpanel_error(_("Source and destination are the same."));
2682 case F_MOVE_FAILED_DEST_IS_CHILD
:
2683 alertpanel_error(copy
? _("Can't copy a folder to one of its children."):
2684 _("Can't move a folder to one of its children."));
2686 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX
:
2687 alertpanel_error(_("A folder cannot be moved between different mailboxes."));
2690 alertpanel_error(copy
? _("Copy failed!"):_("Move failed!"));
2695 gtk_widget_set_sensitive(GTK_WIDGET(folderview
->ctree
), TRUE
);
2698 static gint
folderview_clist_compare(GtkCMCList
*clist
,
2699 gconstpointer ptr1
, gconstpointer ptr2
)
2701 FolderItem
*item1
= ((GtkCMCListRow
*)ptr1
)->data
;
2702 FolderItem
*item2
= ((GtkCMCListRow
*)ptr2
)->data
;
2704 if (item1
->order
> 0 && item2
->order
> 0) // if we have an order item, use it
2706 return item1
->order
- item2
->order
;
2709 // if only one folder has an order it comes first
2710 if (item1
->order
> 0)
2714 if (item2
->order
> 0)
2720 return (item2
->name
!= NULL
);
2724 return g_utf8_collate(item1
->name
, item2
->name
);
2727 static void folderview_processing_cb(GtkAction
*action
, gpointer data
)
2729 FolderView
*folderview
= (FolderView
*)data
;
2733 if (!folderview
->selected
) return;
2735 item
= folderview_get_selected_item(folderview
);
2736 cm_return_if_fail(item
!= NULL
);
2737 cm_return_if_fail(item
->folder
!= NULL
);
2739 id
= folder_item_get_identifier(item
);
2740 title
= g_strdup_printf (_("Processing configuration for folder %s"), id
);
2743 prefs_filtering_open(&item
->prefs
->processing
, title
,
2744 MANUAL_ANCHOR_PROCESSING
, NULL
, NULL
, FALSE
);
2748 void folderview_set_target_folder_color(gint color_op
)
2751 FolderView
*folderview
;
2753 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
) {
2754 folderview
= (FolderView
*)list
->data
;
2755 gtkut_convert_int_to_gdk_color(color_op
, &folderview
->color_op
);
2759 static gchar
*last_smallfont
= NULL
;
2760 static gchar
*last_normalfont
= NULL
;
2761 static gchar
*last_boldfont
= NULL
;
2762 static gboolean last_derive
= 0;
2764 void folderview_reinit_fonts(FolderView
*folderview
)
2767 g_free(last_smallfont
);
2768 last_smallfont
= NULL
;
2769 g_free(last_normalfont
);
2770 last_normalfont
= NULL
;
2771 g_free(last_boldfont
);
2772 last_boldfont
= NULL
;
2775 void folderview_reflect_prefs(void)
2777 gboolean update_font
= FALSE
;
2778 FolderView
*folderview
= mainwindow_get_mainwindow()->folderview
;
2779 FolderItem
*item
= folderview_get_selected_item(folderview
);
2780 GtkAdjustment
*pos
= gtk_scrolled_window_get_vadjustment(
2781 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
2782 gint height
= gtk_adjustment_get_value(pos
);
2784 gtkut_convert_int_to_gdk_color(prefs_common
.color
[COL_NEW
],
2785 &folderview
->color_new
);
2786 gtkut_convert_int_to_gdk_color(prefs_common
.color
[COL_TGT_FOLDER
],
2787 &folderview
->color_op
);
2789 if (!last_smallfont
|| strcmp(last_smallfont
, SMALL_FONT
) ||
2790 !last_normalfont
|| strcmp(last_normalfont
, NORMAL_FONT
) ||
2791 !last_boldfont
|| strcmp(last_boldfont
, BOLD_FONT
) ||
2792 last_derive
!= prefs_common
.derive_from_normal_font
)
2798 g_free(last_smallfont
);
2799 last_smallfont
= g_strdup(SMALL_FONT
);
2800 g_free(last_normalfont
);
2801 last_normalfont
= g_strdup(NORMAL_FONT
);
2802 g_free(last_boldfont
);
2803 last_boldfont
= g_strdup(BOLD_FONT
);
2804 last_derive
= prefs_common
.derive_from_normal_font
;
2806 #define STYLE_FREE(s) \
2808 g_object_unref(s); \
2812 STYLE_FREE(bold_style
);
2816 folderview_set_fonts(folderview
);
2818 gtk_cmclist_freeze(GTK_CMCLIST(folderview
->ctree
));
2819 folderview_column_set_titles(folderview
);
2820 folderview_set_all();
2822 g_signal_handlers_block_by_func
2823 (G_OBJECT(folderview
->ctree
),
2824 G_CALLBACK(folderview_selected
), folderview
);
2827 GtkCMCTreeNode
*node
= gtk_cmctree_find_by_row_data(
2828 GTK_CMCTREE(folderview
->ctree
), NULL
, item
);
2830 folderview_select(folderview
, item
);
2831 folderview
->open_folder
= FALSE
;
2832 folderview
->selected
= node
;
2835 g_signal_handlers_unblock_by_func
2836 (G_OBJECT(folderview
->ctree
),
2837 G_CALLBACK(folderview_selected
), folderview
);
2839 pos
= gtk_scrolled_window_get_vadjustment(
2840 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
2841 gtk_adjustment_set_value(pos
, height
);
2842 gtk_adjustment_changed(pos
);
2843 gtk_cmclist_thaw(GTK_CMCLIST(folderview
->ctree
));
2846 static void drag_state_stop(FolderView
*folderview
)
2848 if (folderview
->drag_timer_id
)
2849 g_source_remove(folderview
->drag_timer_id
);
2850 folderview
->drag_timer_id
= 0;
2851 folderview
->drag_node
= NULL
;
2854 static gboolean
folderview_defer_expand(FolderView
*folderview
)
2856 if (folderview
->drag_node
) {
2857 folderview_recollapse_nodes(folderview
, folderview
->drag_node
);
2858 if (folderview
->drag_item
->collapsed
) {
2859 gtk_cmctree_expand(GTK_CMCTREE(folderview
->ctree
), folderview
->drag_node
);
2860 folderview
->nodes_to_recollapse
= g_slist_append
2861 (folderview
->nodes_to_recollapse
, folderview
->drag_node
);
2864 folderview
->drag_item
= NULL
;
2865 folderview
->drag_timer_id
= 0;
2869 static void drag_state_start(FolderView
*folderview
, GtkCMCTreeNode
*node
, FolderItem
*item
)
2871 /* the idea is that we call drag_state_start() whenever we want expansion to
2872 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2873 * we need to call drag_state_stop() */
2874 drag_state_stop(folderview
);
2875 /* request expansion */
2876 if (0 != (folderview
->drag_timer_id
= g_timeout_add
2877 (prefs_common
.hover_timeout
,
2878 (GSourceFunc
)folderview_defer_expand
,
2880 folderview
->drag_node
= node
;
2881 folderview
->drag_item
= item
;
2884 #ifndef GENERIC_UMPC
2885 static void folderview_start_drag(GtkWidget
*widget
, gint button
, GdkEvent
*event
,
2886 FolderView
*folderview
)
2888 GdkDragContext
*context
;
2890 cm_return_if_fail(folderview
!= NULL
);
2891 if (folderview
->selected
== NULL
) return;
2892 if (folderview
->nodes_to_recollapse
)
2893 g_slist_free(folderview
->nodes_to_recollapse
);
2894 folderview
->nodes_to_recollapse
= NULL
;
2895 context
= gtk_drag_begin(widget
, folderview
->target_list
,
2896 GDK_ACTION_MOVE
|GDK_ACTION_COPY
|GDK_ACTION_DEFAULT
, button
, event
);
2897 gtk_drag_set_icon_default(context
);
2900 static void folderview_drag_data_get(GtkWidget
*widget
,
2901 GdkDragContext
*drag_context
,
2902 GtkSelectionData
*selection_data
,
2905 FolderView
*folderview
)
2909 gchar
*source
= NULL
;
2910 if (info
== TARGET_DUMMY
) {
2911 sel
= GTK_CMCLIST(folderview
->ctree
)->selection
;
2915 item
= gtk_cmctree_node_get_row_data
2916 (GTK_CMCTREE(folderview
->ctree
),
2917 GTK_CMCTREE_NODE(sel
->data
));
2919 source
= g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item
));
2920 gtk_selection_data_set(selection_data
,
2921 gtk_selection_data_get_target(selection_data
), 8,
2922 source
, strlen(source
));
2925 g_warning("unknown info %d", info
);
2929 static gboolean
folderview_update_folder(gpointer source
, gpointer userdata
)
2931 FolderUpdateData
*hookdata
;
2932 FolderView
*folderview
;
2936 folderview
= (FolderView
*) userdata
;
2937 cm_return_val_if_fail(hookdata
!= NULL
, FALSE
);
2938 cm_return_val_if_fail(folderview
!= NULL
, FALSE
);
2940 ctree
= folderview
->ctree
;
2941 cm_return_val_if_fail(ctree
!= NULL
, FALSE
);
2943 if (hookdata
->update_flags
& FOLDER_ADD_FOLDERITEM
)
2944 folderview_create_folder_node(folderview
, hookdata
->item
);
2945 else if (hookdata
->update_flags
& FOLDER_RENAME_FOLDERITEM
) {
2946 GtkCMCTreeNode
*node
= gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree
),
2947 NULL
, folder_item_parent(hookdata
->item
));
2948 folderview_sort_folders(folderview
, node
, hookdata
->folder
);
2949 } else if (hookdata
->update_flags
& FOLDER_REMOVE_FOLDERITEM
) {
2950 GtkCMCTreeNode
*node
;
2952 node
= gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree
), NULL
, hookdata
->item
);
2954 gtk_cmctree_remove_node(GTK_CMCTREE(ctree
), node
);
2955 if (folderview
->selected
== node
)
2956 folderview
->selected
= NULL
;
2957 if (folderview
->opened
== node
)
2958 folderview
->opened
= NULL
;
2960 } else if (hookdata
->update_flags
& FOLDER_MOVE_FOLDERITEM
) {
2961 /* do nothing, it's done by the ADD and REMOVE) */
2962 } else if (hookdata
->update_flags
& (FOLDER_TREE_CHANGED
| FOLDER_ADD_FOLDER
| FOLDER_REMOVE_FOLDER
))
2963 folderview_set(folderview
);
2968 static gboolean
folderview_dnd_scroll_cb(gpointer data
)
2970 FolderView
*folderview
= (FolderView
*)data
;
2971 GtkAdjustment
*pos
= gtk_scrolled_window_get_vadjustment(
2972 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
2973 gint new_val
= (int)gtk_adjustment_get_value(pos
) + folderview
->scroll_value
;
2974 gint max
= (int)gtk_adjustment_get_upper(pos
) -
2975 (int)gtk_adjustment_get_page_size(pos
);
2977 if (folderview
->scroll_value
== 0) {
2978 folderview
->scroll_timeout_id
= 0;
2982 if (folderview
->scroll_value
> 0 && new_val
> max
) {
2984 } else if (folderview
->scroll_value
< 0 && new_val
< 0) {
2987 gtk_adjustment_set_value(pos
, new_val
);
2992 static gboolean
folderview_drag_motion_cb(GtkWidget
*widget
,
2993 GdkDragContext
*context
,
2997 FolderView
*folderview
)
3000 FolderItem
*item
= NULL
, *src_item
= NULL
;
3001 GtkCMCTreeNode
*node
= NULL
;
3002 gboolean acceptable
= FALSE
;
3003 GtkAdjustment
*pos
= gtk_scrolled_window_get_vadjustment(
3004 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
3005 int height
= (int)gtk_adjustment_get_page_size(pos
);
3006 int total_height
= (int)gtk_adjustment_get_upper(pos
);
3007 int vpos
= (int)gtk_adjustment_get_value(pos
);
3008 int offset
= prefs_common
.show_col_headers
? 24:0;
3011 if (gtk_cmclist_get_selection_info
3012 (GTK_CMCLIST(widget
), x
- offset
, y
- offset
, &row
, &column
)) {
3013 GtkWidget
*srcwidget
;
3015 if (y
> height
- (48 - offset
) && height
+ vpos
< total_height
) {
3016 dist
= -(height
- (48 - offset
) - y
);
3017 folderview
->scroll_value
= 1.41f
* (1+(dist
/ 6));
3018 } else if (y
< 72 - (24 - offset
) && y
>= 0) {
3019 dist
= 72 - (24 - offset
) - y
;
3020 folderview
->scroll_value
= -1.41f
* (1+(dist
/ 6));
3022 folderview
->scroll_value
= 0;
3024 if (folderview
->scroll_value
!= 0 && folderview
->scroll_timeout_id
== 0) {
3025 folderview
->scroll_timeout_id
=
3026 g_timeout_add(30, folderview_dnd_scroll_cb
,
3030 node
= gtk_cmctree_node_nth(GTK_CMCTREE(widget
), row
);
3031 item
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget
), node
);
3032 src_item
= folderview
->summaryview
->folder_item
;
3034 srcwidget
= gtk_drag_get_source_widget(context
);
3035 if (srcwidget
== summary_get_main_widget(folderview
->summaryview
)) {
3036 /* comes from summaryview */
3037 /* we are copying messages, so only accept folder items that are not
3038 the source item, are no root items and can copy messages */
3039 if (item
&& item
->folder
&& folder_item_parent(item
) != NULL
&& src_item
&&
3040 src_item
!= item
&& FOLDER_CLASS(item
->folder
)->copy_msg
!= NULL
&&
3041 FOLDER_TYPE(item
->folder
) != F_UNKNOWN
)
3043 } else if (srcwidget
== folderview
->ctree
) {
3044 /* comes from folderview */
3045 /* we are moving folder items, only accept folders that are not
3046 the source items and can copy messages and create folder items */
3047 if (item
&& item
->folder
&& src_item
&& src_item
!= item
&&
3048 FOLDER_CLASS(item
->folder
)->copy_msg
!= NULL
&&
3049 FOLDER_CLASS(item
->folder
)->create_folder
!= NULL
&&
3050 ((FOLDER_TYPE(item
->folder
) != F_UNKNOWN
&& FOLDER_TYPE(src_item
->folder
) != F_UNKNOWN
)
3051 || item
->folder
== src_item
->folder
))
3054 /* comes from another app */
3055 /* we are adding messages, so only accept folder items that are
3056 no root items and can copy messages */
3057 if (item
&& item
->folder
&& folder_item_parent(item
) != NULL
3058 && FOLDER_CLASS(item
->folder
)->add_msg
!= NULL
&&
3059 FOLDER_TYPE(item
->folder
) != F_UNKNOWN
)
3064 if (acceptable
|| (src_item
&& src_item
== item
))
3065 drag_state_start(folderview
, node
, item
);
3068 g_signal_handlers_block_by_func
3070 G_CALLBACK(folderview_selected
), folderview
);
3071 gtk_cmctree_select(GTK_CMCTREE(widget
), node
);
3072 g_signal_handlers_unblock_by_func
3074 G_CALLBACK(folderview_selected
), folderview
);
3075 gdk_drag_status(context
,
3076 (gdk_drag_context_get_actions(context
) == GDK_ACTION_COPY
?
3077 GDK_ACTION_COPY
: GDK_ACTION_MOVE
) , time
);
3079 if (folderview
->opened
)
3080 gtk_cmctree_select(GTK_CMCTREE(widget
), folderview
->opened
);
3081 gdk_drag_status(context
, 0, time
);
3087 static void folderview_drag_leave_cb(GtkWidget
*widget
,
3088 GdkDragContext
*context
,
3090 FolderView
*folderview
)
3092 drag_state_stop(folderview
);
3093 folderview
->scroll_value
= 0;
3094 gtk_cmctree_select(GTK_CMCTREE(widget
), folderview
->opened
);
3097 static void free_info (gpointer stuff
, gpointer data
)
3102 void folderview_finish_dnd(const gchar
*data
, GdkDragContext
*drag_context
,
3103 guint time
, FolderItem
*item
)
3106 GSList
*msglist
= NULL
;
3107 list
= uri_list_extract_filenames(data
);
3108 if (!(item
&& item
->folder
&& folder_item_parent(item
) != NULL
3109 && FOLDER_CLASS(item
->folder
)->add_msg
!= NULL
))
3111 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3112 debug_print("item doesn't fit\n");
3116 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3117 debug_print("list is empty\n");
3120 for (tmp
= list
; tmp
!= NULL
; tmp
= tmp
->next
) {
3121 MsgFileInfo
*info
= NULL
;
3123 if (file_is_email((gchar
*)tmp
->data
)) {
3124 info
= g_new0(MsgFileInfo
, 1);
3125 info
->msginfo
= NULL
;
3126 info
->file
= (gchar
*)tmp
->data
;
3127 msglist
= g_slist_prepend(msglist
, info
);
3128 debug_print("file is a mail\n");
3130 debug_print("file isn't a mail\n");
3134 msglist
= g_slist_reverse(msglist
);
3135 folder_item_add_msgs(item
, msglist
, FALSE
);
3136 g_slist_foreach(msglist
, free_info
, NULL
);
3137 g_slist_free(msglist
);
3138 gtk_drag_finish(drag_context
, TRUE
, FALSE
, time
);
3140 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3142 list_free_strings_full(list
);
3145 static void folderview_drag_received_cb(GtkWidget
*widget
,
3146 GdkDragContext
*drag_context
,
3149 GtkSelectionData
*data
,
3152 FolderView
*folderview
)
3155 FolderItem
*item
= NULL
, *src_item
;
3156 GtkCMCTreeNode
*node
;
3157 int offset
= prefs_common
.show_col_headers
? 24:0;
3159 folderview
->scroll_value
= 0;
3161 if (info
== TARGET_DUMMY
) {
3162 drag_state_stop(folderview
);
3163 const gchar
*ddata
= (const gchar
*)gtk_selection_data_get_data(data
);
3164 if ((gchar
*)strstr(ddata
, "FROM_OTHER_FOLDER") != ddata
) {
3165 /* comes from summaryview */
3166 if (gtk_cmclist_get_selection_info
3167 (GTK_CMCLIST(widget
), x
- offset
, y
- offset
, &row
, &column
) == 0)
3170 node
= gtk_cmctree_node_nth(GTK_CMCTREE(widget
), row
);
3171 item
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget
), node
);
3172 src_item
= folderview
->summaryview
->folder_item
;
3174 if (item
->no_select
) {
3175 alertpanel_error(_("The destination folder can only be used to "
3176 "store subfolders."));
3179 /* re-check (due to acceptable possibly set for folder moves */
3180 if (!(item
&& item
->folder
&& item
->path
&& !item
->no_select
&&
3181 src_item
&& src_item
!= item
&& FOLDER_CLASS(item
->folder
)->copy_msg
!= NULL
)) {
3185 switch (gdk_drag_context_get_selected_action(drag_context
)) {
3186 case GDK_ACTION_COPY
:
3187 summary_copy_selected_to(folderview
->summaryview
, item
);
3188 gtk_drag_finish(drag_context
, TRUE
, FALSE
, time
);
3190 case GDK_ACTION_MOVE
:
3191 case GDK_ACTION_DEFAULT
:
3193 if (FOLDER_CLASS(src_item
->folder
)->remove_msg
== NULL
)
3194 summary_copy_selected_to(folderview
->summaryview
, item
);
3196 summary_move_selected_to(folderview
->summaryview
, item
);
3197 gtk_drag_finish(drag_context
, TRUE
, TRUE
, time
);
3200 /* comes from folderview */
3202 gboolean folder_is_normal
= TRUE
;
3203 gboolean copy
= (GDK_ACTION_COPY
==
3204 gdk_drag_context_get_selected_action(drag_context
));
3206 source
= (char *)gtk_selection_data_get_data(data
) + 17;
3207 if (gtk_cmclist_get_selection_info
3208 (GTK_CMCLIST(widget
), x
- offset
, y
- offset
, &row
, &column
) == 0
3210 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3213 node
= gtk_cmctree_node_nth(GTK_CMCTREE(widget
), row
);
3214 item
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget
), node
);
3215 src_item
= folder_find_item_from_identifier(source
);
3219 src_item
->stype
== F_NORMAL
&&
3220 !folder_has_parent_of_type(src_item
, F_OUTBOX
) &&
3221 !folder_has_parent_of_type(src_item
, F_DRAFT
) &&
3222 !folder_has_parent_of_type(src_item
, F_QUEUE
) &&
3223 !folder_has_parent_of_type(src_item
, F_TRASH
);
3224 if (!item
|| !src_item
|| !folder_is_normal
) {
3225 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3229 folderview_move_folder(folderview
, src_item
, item
, copy
);
3230 gtk_drag_finish(drag_context
, TRUE
, TRUE
, time
);
3232 folderview
->nodes_to_recollapse
= NULL
;
3233 } else if (info
== TARGET_MAIL_URI_LIST
) {
3234 if (gtk_cmclist_get_selection_info
3235 (GTK_CMCLIST(widget
), x
- offset
, y
- offset
, &row
, &column
) == 0)
3238 node
= gtk_cmctree_node_nth(GTK_CMCTREE(widget
), row
);
3240 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3241 debug_print("no node\n");
3244 item
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget
), node
);
3246 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3247 debug_print("no item\n");
3250 folderview_finish_dnd(gtk_selection_data_get_data(data
),
3251 drag_context
, time
, item
);
3255 static void folderview_drag_end_cb(GtkWidget
*widget
,
3256 GdkDragContext
*drag_context
,
3257 FolderView
*folderview
)
3259 drag_state_stop(folderview
);
3260 folderview
->scroll_value
= 0;
3261 g_slist_free(folderview
->nodes_to_recollapse
);
3262 folderview
->nodes_to_recollapse
= NULL
;
3265 void folderview_register_popup(FolderViewPopup
*fpopup
)
3269 for (folderviews
= folderview_list
; folderviews
!= NULL
; folderviews
= g_list_next(folderviews
)) {
3270 FolderView
*folderview
= folderviews
->data
;
3271 GtkActionGroup
*factory
;
3273 factory
= create_action_group(folderview
, fpopup
);
3274 g_hash_table_insert(folderview
->popups
, fpopup
->klass
, factory
);
3276 g_hash_table_insert(folderview_popups
, fpopup
->klass
, fpopup
);
3279 void folderview_unregister_popup(FolderViewPopup
*fpopup
)
3284 for (folderviews
= folderview_list
; folderviews
!= NULL
; folderviews
= g_list_next(folderviews
)) {
3285 FolderView
*folderview
= folderviews
->data
;
3287 g_hash_table_remove(folderview
->popups
, fpopup
->klass
);
3289 g_hash_table_remove(folderview_popups
, fpopup
->klass
);
3292 void folderview_remove_item(FolderView
*folderview
, FolderItem
*item
)
3294 g_return_if_fail(folderview
!= NULL
);
3295 g_return_if_fail(item
!= NULL
);
3297 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
3298 g_return_if_fail(ctree
!= NULL
);
3300 GtkCMCTreeNode
*node
=
3301 gtk_cmctree_find_by_row_data(ctree
, NULL
, item
);
3302 g_return_if_fail(node
!= NULL
);
3304 gtk_cmctree_remove_node(ctree
, node
);
3307 void folderview_freeze(FolderView
*folderview
)
3310 gtk_cmclist_freeze(GTK_CMCLIST(folderview
->ctree
));
3313 void folderview_thaw(FolderView
*folderview
)
3316 gtk_cmclist_thaw(GTK_CMCLIST(folderview
->ctree
));
3319 void folderview_grab_focus(FolderView
*folderview
)
3322 gtk_widget_grab_focus(folderview
->ctree
);
3325 static void folderview_header_set_displayed_columns_cb(GtkAction
*gaction
,
3328 prefs_folder_column_open();
3331 static gboolean
folderview_header_button_pressed(GtkWidget
*widget
,
3335 GdkEventButton
*event
= (GdkEventButton
*)_event
;
3336 FolderView
*folderview
= (FolderView
*)user_data
;
3338 cm_return_val_if_fail(folderview
!= NULL
, FALSE
);
3340 /* Only handle single button presses. */
3341 if (event
->type
== GDK_2BUTTON_PRESS
||
3342 event
->type
== GDK_3BUTTON_PRESS
)
3345 /* Handle right-click for context menu */
3346 if (event
->button
== 3) {
3347 gtk_menu_popup(GTK_MENU(folderview
->headerpopupmenu
),
3348 NULL
, NULL
, NULL
, NULL
, 3, event
->time
);