2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2013 Hiroyuki Yamamoto and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include <glib/gi18n.h>
24 #include <gdk/gdkkeysyms.h>
31 #include "mainwindow.h"
32 #include "folderview.h"
33 #include "summaryview.h"
34 #include "summary_search.h"
35 #include "inputdialog.h"
36 #include "manage_window.h"
37 #include "alertpanel.h"
39 #include "stock_pixmap.h"
43 #include "prefs_common.h"
44 #include "prefs_account.h"
45 #include "prefs_filtering.h"
46 #include "prefs_folder_item.h"
49 #include "foldersel.h"
51 #include "statusbar.h"
53 #include "folderutils.h"
54 #include "partial_download.h"
55 #include "prefs_folder_column.h"
56 #include "filtering.h"
57 #include "quicksearch.h"
61 #include "gtkcmctree.h"
63 #define COL_FOLDER_WIDTH 150
64 #define COL_NUM_WIDTH 32
66 static GList
*folderview_list
= NULL
;
68 static GtkStyle
*normal_style
;
69 static GtkStyle
*normal_color_style
;
70 static GtkStyle
*bold_style
;
71 static GtkStyle
*bold_color_style
;
72 static GtkStyle
*bold_tgtfold_style
;
74 static GdkPixbuf
*inboxxpm
;
75 static GdkPixbuf
*inboxhrmxpm
;
76 static GdkPixbuf
*inboxopenxpm
;
77 static GdkPixbuf
*inboxopenhrmxpm
;
78 static GdkPixbuf
*outboxxpm
;
79 static GdkPixbuf
*outboxhrmxpm
;
80 static GdkPixbuf
*outboxopenxpm
;
81 static GdkPixbuf
*outboxopenhrmxpm
;
82 static GdkPixbuf
*folderxpm
;
83 static GdkPixbuf
*folderhrmxpm
;
84 static GdkPixbuf
*folderopenxpm
;
85 static GdkPixbuf
*folderopenhrmxpm
;
86 static GdkPixbuf
*trashopenxpm
;
87 static GdkPixbuf
*trashopenhrmxpm
;
88 static GdkPixbuf
*trashxpm
;
89 static GdkPixbuf
*trashhrmxpm
;
90 static GdkPixbuf
*queuexpm
;
91 static GdkPixbuf
*queuehrmxpm
;
92 static GdkPixbuf
*queueopenxpm
;
93 static GdkPixbuf
*queueopenhrmxpm
;
94 static GdkPixbuf
*draftsxpm
;
95 static GdkPixbuf
*draftsopenxpm
;
96 static GdkPixbuf
*foldersubsxpm
;
97 static GdkPixbuf
*foldersubsopenxpm
;
98 static GdkPixbuf
*foldernoselectxpm
;
99 static GdkPixbuf
*foldernoselectopenxpm
;
101 static GdkPixbuf
*m_inboxxpm
;
102 static GdkPixbuf
*m_inboxhrmxpm
;
103 static GdkPixbuf
*m_inboxopenxpm
;
104 static GdkPixbuf
*m_inboxopenhrmxpm
;
105 static GdkPixbuf
*m_outboxxpm
;
106 static GdkPixbuf
*m_outboxhrmxpm
;
107 static GdkPixbuf
*m_outboxopenxpm
;
108 static GdkPixbuf
*m_outboxopenhrmxpm
;
109 static GdkPixbuf
*m_folderxpm
;
110 static GdkPixbuf
*m_folderhrmxpm
;
111 static GdkPixbuf
*m_folderopenxpm
;
112 static GdkPixbuf
*m_folderopenhrmxpm
;
113 static GdkPixbuf
*m_trashopenxpm
;
114 static GdkPixbuf
*m_trashopenhrmxpm
;
115 static GdkPixbuf
*m_trashxpm
;
116 static GdkPixbuf
*m_trashhrmxpm
;
117 static GdkPixbuf
*m_queuexpm
;
118 static GdkPixbuf
*m_queuehrmxpm
;
119 static GdkPixbuf
*m_queueopenxpm
;
120 static GdkPixbuf
*m_queueopenhrmxpm
;
121 static GdkPixbuf
*m_draftsxpm
;
122 static GdkPixbuf
*m_draftsopenxpm
;
123 static GdkPixbuf
*m_foldersubsxpm
;
124 static GdkPixbuf
*m_foldernoselectxpm
;
126 static GdkPixbuf
*newxpm
;
127 static GdkPixbuf
*unreadxpm
;
128 static GdkPixbuf
*readxpm
;
130 static void folderview_select_node (FolderView
*folderview
,
131 GtkCMCTreeNode
*node
);
132 static void folderview_set_folders (FolderView
*folderview
);
133 static void folderview_sort_folders (FolderView
*folderview
,
134 GtkCMCTreeNode
*root
,
136 static void folderview_append_folder (FolderView
*folderview
,
138 static void folderview_update_node (FolderView
*folderview
,
139 GtkCMCTreeNode
*node
);
141 static gint
folderview_clist_compare (GtkCMCList
*clist
,
145 /* callback functions */
146 static gboolean
folderview_button_pressed (GtkWidget
*ctree
,
147 GdkEventButton
*event
,
148 FolderView
*folderview
);
149 static gboolean
folderview_button_released (GtkWidget
*ctree
,
150 GdkEventButton
*event
,
151 FolderView
*folderview
);
152 static gboolean
folderview_key_pressed (GtkWidget
*widget
,
154 FolderView
*folderview
);
155 static void folderview_selected (GtkCMCTree
*ctree
,
158 FolderView
*folderview
);
159 static void folderview_tree_expanded (GtkCMCTree
*ctree
,
160 GtkCMCTreeNode
*node
,
161 FolderView
*folderview
);
162 static void folderview_tree_collapsed (GtkCMCTree
*ctree
,
163 GtkCMCTreeNode
*node
,
164 FolderView
*folderview
);
165 static void folderview_popup_close (GtkMenuShell
*menu_shell
,
166 FolderView
*folderview
);
167 static void folderview_col_resized (GtkCMCList
*clist
,
170 FolderView
*folderview
);
172 static void mark_all_read_handler (GtkAction
*action
,
176 static void mark_all_read_cb (GtkAction
*action
,
178 static void mark_all_read_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
);
237 GHashTable
*folderview_popups
;
239 static GtkActionEntry folderview_common_popup_entries
[] =
241 {"FolderViewPopup", NULL
, "FolderViewPopup" },
242 {"FolderViewPopup/MarkAllRead", NULL
, N_("Mark all re_ad"), NULL
, NULL
, G_CALLBACK(mark_all_read_cb
) },
243 {"FolderViewPopup/MarkAllReadRec", NULL
, N_("Mark all read recursi_vely"), NULL
, NULL
, G_CALLBACK(mark_all_read_recursive_cb
) },
244 {"FolderViewPopup/---", NULL
, "---" },
245 {"FolderViewPopup/RunProcessing", NULL
, N_("R_un processing rules"), NULL
, NULL
, G_CALLBACK(folderview_run_processing_cb
) },
246 {"FolderViewPopup/SearchFolder", NULL
, N_("_Search folder..."), NULL
, NULL
, G_CALLBACK(folderview_search_cb
) },
247 {"FolderViewPopup/Properties", NULL
, N_("_Properties..."), NULL
, NULL
, G_CALLBACK(folderview_property_cb
) },
248 {"FolderViewPopup/Processing", NULL
, N_("Process_ing..."), NULL
, NULL
, G_CALLBACK(folderview_processing_cb
) },
249 {"FolderViewPopup/EmptyTrash", NULL
, N_("Empty _trash..."), NULL
, NULL
, G_CALLBACK(folderview_empty_trash_cb
) },
250 {"FolderViewPopup/SendQueue", NULL
, N_("Send _queue..."), NULL
, NULL
, G_CALLBACK(folderview_send_queue_cb
) },
254 GtkTargetEntry folderview_drag_types
[] =
256 {"claws-mail/internal", GTK_TARGET_SAME_APP
, TARGET_DUMMY
},
257 {"text/uri-list", 0, TARGET_MAIL_URI_LIST
}
260 void folderview_initialize(void)
262 FolderViewPopup
*fpopup
;
264 fpopup
= g_new0(FolderViewPopup
, 1);
266 fpopup
->klass
= "common";
267 fpopup
->path
= "<CommonFolder>";
268 fpopup
->entries
= folderview_common_popup_entries
;
269 fpopup
->n_entries
= G_N_ELEMENTS(folderview_common_popup_entries
);
270 fpopup
->set_sensitivity
= NULL
;
272 folderview_popups
= g_hash_table_new(g_str_hash
, g_str_equal
);
273 g_hash_table_insert(folderview_popups
, "common", fpopup
);
276 static GtkActionGroup
*create_action_group(FolderView
*folderview
, FolderViewPopup
*fpopup
)
278 FolderViewPopup
*fpopup_common
;
279 GtkActionGroup
*action_group
;
281 action_group
= cm_menu_create_action_group(
283 fpopup
->entries
, fpopup
->n_entries
,
284 (gpointer
)folderview
);
286 if (fpopup
->toggle_entries
)
287 gtk_action_group_add_toggle_actions(action_group
, fpopup
->toggle_entries
,
288 fpopup
->n_toggle_entries
,
289 (gpointer
)folderview
);
290 if (fpopup
->radio_entries
)
291 gtk_action_group_add_radio_actions(action_group
, fpopup
->radio_entries
,
292 fpopup
->n_radio_entries
, fpopup
->radio_default
,
293 G_CALLBACK(fpopup
->radio_callback
),
294 (gpointer
)folderview
);
296 fpopup_common
= g_hash_table_lookup(folderview_popups
, "common");
297 if (fpopup_common
!= fpopup
) {
298 gtk_action_group_add_actions(action_group
, fpopup_common
->entries
,
299 fpopup_common
->n_entries
,
300 (gpointer
)folderview
);
301 if (fpopup_common
->toggle_entries
)
302 gtk_action_group_add_toggle_actions(action_group
, fpopup_common
->toggle_entries
,
303 fpopup_common
->n_toggle_entries
,
304 (gpointer
)folderview
);
305 if (fpopup_common
->radio_entries
)
306 gtk_action_group_add_radio_actions(action_group
, fpopup_common
->radio_entries
,
307 fpopup_common
->n_radio_entries
, fpopup_common
->radio_default
,
308 G_CALLBACK(fpopup_common
->radio_callback
),
309 (gpointer
)folderview
);
315 static void create_action_groups(gpointer key
, gpointer value
, gpointer data
)
317 FolderView
*folderview
= data
;
318 FolderViewPopup
*fpopup
= value
;
319 GtkActionGroup
*group
;
321 group
= create_action_group(folderview
, fpopup
);
322 g_hash_table_insert(folderview
->popups
, fpopup
->klass
, group
);
325 static void folderview_column_set_titles(FolderView
*folderview
)
327 GtkWidget
*ctree
= folderview
->ctree
;
328 GtkWidget
*label_folder
;
329 GtkWidget
*label_new
;
330 GtkWidget
*label_unread
;
331 GtkWidget
*label_total
;
332 GtkWidget
*hbox_folder
;
334 GtkWidget
*hbox_unread
;
335 GtkWidget
*hbox_total
;
336 gint
*col_pos
= folderview
->col_pos
;
338 debug_print("setting titles...\n");
339 gtk_widget_realize(folderview
->ctree
);
340 gtk_widget_show_all(folderview
->scrolledwin
);
342 /* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
343 * instead text (text overflows making them unreadable and ugly) */
344 stock_pixbuf_gdk(STOCK_PIXMAP_NEW
, &newxpm
);
345 stock_pixbuf_gdk(STOCK_PIXMAP_UNREAD
, &unreadxpm
);
346 stock_pixbuf_gdk(STOCK_PIXMAP_READ
, &readxpm
);
348 label_folder
= gtk_label_new(_("Folder"));
349 label_new
= gtk_image_new_from_pixbuf(newxpm
);
350 label_unread
= gtk_image_new_from_pixbuf(unreadxpm
);
351 label_total
= gtk_image_new_from_pixbuf(readxpm
);
353 gtk_cmclist_column_titles_active(GTK_CMCLIST(ctree
));
355 hbox_folder
= gtk_hbox_new(FALSE
, 4);
356 hbox_new
= gtk_hbox_new(FALSE
, 4);
357 hbox_unread
= gtk_hbox_new(FALSE
, 4);
358 hbox_total
= gtk_hbox_new(FALSE
, 4);
361 gtk_box_pack_start(GTK_BOX(hbox_folder
), label_folder
, TRUE
, TRUE
, 0);
362 gtk_misc_set_alignment (GTK_MISC (label_folder
), 0, 0.5);
363 gtk_box_pack_start(GTK_BOX(hbox_new
), label_new
, TRUE
, TRUE
, 0);
364 gtk_misc_set_alignment (GTK_MISC (label_new
), 1, 0.5);
365 gtk_box_pack_start(GTK_BOX(hbox_unread
), label_unread
, TRUE
, TRUE
, 0);
366 gtk_misc_set_alignment (GTK_MISC (label_unread
), 1, 0.5);
367 gtk_box_pack_start(GTK_BOX(hbox_total
), label_total
, TRUE
, TRUE
, 0);
368 gtk_misc_set_alignment (GTK_MISC (label_total
), 1, 0.5);
370 gtk_widget_show_all(hbox_folder
);
371 gtk_widget_show_all(hbox_new
);
372 gtk_widget_show_all(hbox_unread
);
373 gtk_widget_show_all(hbox_total
);
376 gtk_widget_set_size_request(hbox_new
, -1, 20);
377 gtk_widget_set_size_request(hbox_unread
, -1, 20);
378 gtk_widget_set_size_request(hbox_total
, -1, 20);
381 gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree
),col_pos
[F_COL_FOLDER
],hbox_folder
);
382 gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree
),col_pos
[F_COL_NEW
],hbox_new
);
383 gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree
),col_pos
[F_COL_UNREAD
],hbox_unread
);
384 gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree
),col_pos
[F_COL_TOTAL
],hbox_total
);
390 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree
), col_pos
[F_COL_NEW
], _("New"));
391 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree
), col_pos
[F_COL_UNREAD
], _("Unread"));
392 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree
), col_pos
[F_COL_TOTAL
], _("Total"));
395 static gboolean
folderview_popup_menu(GtkWidget
*widget
, gpointer data
)
397 FolderView
*folderview
= (FolderView
*)data
;
398 GdkEventButton event
;
399 if (folderview_get_selected_item(folderview
) == NULL
)
403 event
.time
= gtk_get_current_event_time();
405 folderview_set_sens_and_popup_menu(folderview
, -1,
412 static GtkWidget
*folderview_ctree_create(FolderView
*folderview
)
416 FolderColumnState
*col_state
;
417 FolderColumnType type
;
418 gchar
*titles
[N_FOLDER_COLS
];
420 GtkWidget
*scrolledwin
= folderview
->scrolledwin
;
422 debug_print("creating tree...\n");
423 memset(titles
, 0, sizeof(titles
));
425 col_state
= prefs_folder_column_get_config();
426 memset(titles
, 0, sizeof(titles
));
428 col_pos
= folderview
->col_pos
;
430 for (i
= 0; i
< N_FOLDER_COLS
; i
++) {
431 folderview
->col_state
[i
] = col_state
[i
];
432 type
= col_state
[i
].type
;
436 titles
[col_pos
[F_COL_FOLDER
]] = _("Folder");
437 titles
[col_pos
[F_COL_NEW
]] = _("New");
438 titles
[col_pos
[F_COL_UNREAD
]] = _("Unread");
439 /* TRANSLATORS: This in Number sign in American style */
440 titles
[col_pos
[F_COL_TOTAL
]] = _("#");
442 ctree
= gtk_sctree_new_with_titles(N_FOLDER_COLS
, col_pos
[F_COL_FOLDER
],
445 if (prefs_common
.show_col_headers
== FALSE
)
446 gtk_cmclist_column_titles_hide(GTK_CMCLIST(ctree
));
449 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree
), GTK_SELECTION_BROWSE
);
450 gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree
), col_pos
[F_COL_NEW
],
452 gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree
),
453 col_pos
[F_COL_UNREAD
],
455 gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree
),
456 col_pos
[F_COL_TOTAL
],
458 gtk_cmctree_set_line_style(GTK_CMCTREE(ctree
), GTK_CMCTREE_LINES_NONE
);
459 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree
),
460 GTK_CMCTREE_EXPANDER_TRIANGLE
);
462 gtk_sctree_set_stripes(GTK_SCTREE(ctree
), prefs_common
.use_stripes_in_summaries
);
463 gtk_sctree_set_recursive_expand(GTK_SCTREE(ctree
), FALSE
);
465 gtk_cmctree_set_indent(GTK_CMCTREE(ctree
), CTREE_INDENT
);
466 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree
), folderview_clist_compare
);
468 /* don't let title buttons take key focus */
469 for (i
= 0; i
< N_FOLDER_COLS
; i
++) {
470 gtkut_widget_set_can_focus(GTK_CMCLIST(ctree
)->column
[i
].button
, FALSE
);
471 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree
), col_pos
[i
],
472 prefs_common
.folder_col_size
[i
]);
473 gtk_cmclist_set_column_visibility
474 (GTK_CMCLIST(ctree
), i
, col_state
[i
].visible
);
477 g_signal_connect(G_OBJECT(ctree
), "key_press_event",
478 G_CALLBACK(folderview_key_pressed
),
480 g_signal_connect(G_OBJECT(ctree
), "button_press_event",
481 G_CALLBACK(folderview_button_pressed
),
483 g_signal_connect(G_OBJECT(ctree
), "popup-menu",
484 G_CALLBACK(folderview_popup_menu
), folderview
);
485 g_signal_connect(G_OBJECT(ctree
), "button_release_event",
486 G_CALLBACK(folderview_button_released
),
488 g_signal_connect(G_OBJECT(ctree
), "tree_select_row",
489 G_CALLBACK(folderview_selected
), folderview
);
491 /* drag-n-dropping folders on maemo is impractical as this
492 * opens the folder almost everytime */
493 g_signal_connect(G_OBJECT(ctree
), "start_drag",
494 G_CALLBACK(folderview_start_drag
), folderview
);
496 g_signal_connect(G_OBJECT(ctree
), "drag_data_get",
497 G_CALLBACK(folderview_drag_data_get
),
500 g_signal_connect_after(G_OBJECT(ctree
), "tree_expand",
501 G_CALLBACK(folderview_tree_expanded
),
503 g_signal_connect_after(G_OBJECT(ctree
), "tree_collapse",
504 G_CALLBACK(folderview_tree_collapsed
),
507 g_signal_connect(G_OBJECT(ctree
), "resize_column",
508 G_CALLBACK(folderview_col_resized
),
512 gtk_drag_dest_set(ctree
, GTK_DEST_DEFAULT_ALL
& ~GTK_DEST_DEFAULT_HIGHLIGHT
,
513 folderview_drag_types
, 2,
514 GDK_ACTION_MOVE
| GDK_ACTION_COPY
| GDK_ACTION_DEFAULT
);
515 g_signal_connect(G_OBJECT(ctree
), "drag_motion",
516 G_CALLBACK(folderview_drag_motion_cb
),
518 g_signal_connect(G_OBJECT(ctree
), "drag_leave",
519 G_CALLBACK(folderview_drag_leave_cb
),
521 g_signal_connect(G_OBJECT(ctree
), "drag_data_received",
522 G_CALLBACK(folderview_drag_received_cb
),
524 g_signal_connect(G_OBJECT(ctree
), "drag_end",
525 G_CALLBACK(folderview_drag_end_cb
),
528 gtk_container_add(GTK_CONTAINER(scrolledwin
), ctree
);
533 void folderview_set_column_order(FolderView
*folderview
)
535 GtkWidget
*ctree
= folderview
->ctree
;
536 FolderItem
*item
= folderview_get_selected_item(folderview
);
537 FolderItem
*sel_item
= NULL
, *op_item
= NULL
;
538 GtkWidget
*scrolledwin
= folderview
->scrolledwin
;
540 if (folderview
->drag_timer_id
!= 0) {
541 g_source_remove(folderview
->drag_timer_id
);
542 folderview
->drag_timer_id
= 0;
544 if (folderview
->deferred_refresh_id
!= 0) {
545 g_source_remove(folderview
->deferred_refresh_id
);
546 folderview
->deferred_refresh_id
= 0;
548 if (folderview
->scroll_timeout_id
!= 0) {
549 g_source_remove(folderview
->scroll_timeout_id
);
550 folderview
->scroll_timeout_id
= 0;
552 if (folderview
->postpone_select_id
!= 0) {
553 g_source_remove(folderview
->postpone_select_id
);
554 folderview
->postpone_select_id
= 0;
557 if (folderview
->selected
)
558 sel_item
= folderview_get_selected_item(folderview
);
559 if (folderview
->opened
)
560 op_item
= folderview_get_opened_item(folderview
);
562 debug_print("recreating tree...\n");
563 gtk_widget_destroy(folderview
->ctree
);
566 folderview
->ctree
= ctree
= folderview_ctree_create(folderview
);
567 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin
),
568 GTK_CMCLIST(ctree
)->hadjustment
);
569 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin
),
570 GTK_CMCLIST(ctree
)->vadjustment
);
571 gtk_widget_show(ctree
);
574 folderview
->selected
= gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree
), NULL
, sel_item
);
576 folderview
->opened
= gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree
), NULL
, op_item
);
578 folderview_set(folderview
);
579 folderview_column_set_titles(folderview
);
581 folderview_select(folderview
,item
);
584 FolderView
*folderview_create(void)
586 FolderView
*folderview
;
587 GtkWidget
*scrolledwin
;
590 debug_print("Creating folder view...\n");
591 folderview
= g_new0(FolderView
, 1);
593 scrolledwin
= gtk_scrolled_window_new(NULL
, NULL
);
594 gtk_scrolled_window_set_policy
595 (GTK_SCROLLED_WINDOW(scrolledwin
),
596 GTK_POLICY_AUTOMATIC
,
597 prefs_common
.folderview_vscrollbar_policy
);
598 gtk_widget_set_size_request(scrolledwin
,
599 prefs_common
.folderview_width
,
600 prefs_common
.folderview_height
);
602 folderview
->scrolledwin
= scrolledwin
;
603 ctree
= folderview_ctree_create(folderview
);
605 /* create popup factories */
606 folderview
->popups
= g_hash_table_new(g_str_hash
, g_str_equal
);
607 g_hash_table_foreach(folderview_popups
, create_action_groups
, folderview
);
609 folderview
->ctree
= ctree
;
611 folderview
->folder_update_callback_id
=
612 hooks_register_hook(FOLDER_UPDATE_HOOKLIST
, folderview_update_folder
, (gpointer
) folderview
);
613 folderview
->folder_item_update_callback_id
=
614 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST
, folderview_update_item_claws
, (gpointer
) folderview
);
616 gtk_widget_show_all(scrolledwin
);
618 folderview
->target_list
= gtk_target_list_new(folderview_drag_types
, 2);
619 folderview_list
= g_list_append(folderview_list
, folderview
);
621 folderview
->drag_timer_id
= 0;
622 folderview
->deferred_refresh_id
= 0;
623 folderview
->scroll_timeout_id
= 0;
624 folderview
->postpone_select_id
= 0;
629 void folderview_init(FolderView
*folderview
)
631 GtkWidget
*ctree
= folderview
->ctree
;
633 PangoFontDescription
*normal_font
;
635 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE
, &inboxxpm
);
636 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE_HRM
, &inboxhrmxpm
);
637 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN
, &inboxopenxpm
);
638 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN_HRM
, &inboxopenhrmxpm
);
639 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE
, &outboxxpm
);
640 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE_HRM
, &outboxhrmxpm
);
641 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN
, &outboxopenxpm
);
642 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN_HRM
, &outboxopenhrmxpm
);
643 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE
, &folderxpm
);
644 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE_HRM
, &folderhrmxpm
);
645 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN
, &folderopenxpm
);
646 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN_HRM
, &folderopenhrmxpm
);
647 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN
, &trashopenxpm
);
648 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN_HRM
, &trashopenhrmxpm
);
649 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE
, &trashxpm
);
650 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE_HRM
, &trashhrmxpm
);
651 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE
, &queuexpm
);
652 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE_HRM
, &queuehrmxpm
);
653 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN
, &queueopenxpm
);
654 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN_HRM
, &queueopenhrmxpm
);
655 stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_CLOSE
, &draftsxpm
);
656 stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_OPEN
, &draftsopenxpm
);
657 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_SUBS_OPEN
, &foldersubsopenxpm
);
658 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_SUBS_CLOSE
, &foldersubsxpm
);
659 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_NOSELECT_OPEN
, &foldernoselectopenxpm
);
660 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_NOSELECT_CLOSE
, &foldernoselectxpm
);
662 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE_MARK
, &m_inboxxpm
);
663 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK
, &m_inboxhrmxpm
);
664 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN_MARK
, &m_inboxopenxpm
);
665 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN_HRM_MARK
, &m_inboxopenhrmxpm
);
666 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE_MARK
, &m_outboxxpm
);
667 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK
, &m_outboxhrmxpm
);
668 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN_MARK
, &m_outboxopenxpm
);
669 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK
, &m_outboxopenhrmxpm
);
670 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE_MARK
, &m_folderxpm
);
671 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE_HRM_MARK
, &m_folderhrmxpm
);
672 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN_MARK
, &m_folderopenxpm
);
673 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN_HRM_MARK
, &m_folderopenhrmxpm
);
674 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN_MARK
, &m_trashopenxpm
);
675 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN_HRM_MARK
, &m_trashopenhrmxpm
);
676 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE_MARK
, &m_trashxpm
);
677 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK
, &m_trashhrmxpm
);
678 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE_MARK
, &m_queuexpm
);
679 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK
, &m_queuehrmxpm
);
680 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN_MARK
, &m_queueopenxpm
);
681 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK
, &m_queueopenhrmxpm
);
682 stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_CLOSE_MARK
, &m_draftsxpm
);
683 stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_OPEN_MARK
, &m_draftsopenxpm
);
684 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_SUBS_CLOSE_MARK
, &m_foldersubsxpm
);
685 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_NOSELECT_CLOSE_MARK
, &m_foldernoselectxpm
);
687 normal_font
= pango_font_description_from_string(NORMAL_FONT
);
689 gtk_widget_modify_font(ctree
, normal_font
);
690 pango_font_description_free(normal_font
);
692 gtk_cmclist_set_row_height(GTK_CMCLIST(ctree
), 0);
695 PangoFontDescription
*font_desc
;
696 normal_style
= gtk_style_copy(gtk_widget_get_style(ctree
));
697 font_desc
= pango_font_description_from_string(NORMAL_FONT
);
699 if (normal_style
->font_desc
)
700 pango_font_description_free
701 (normal_style
->font_desc
);
702 normal_style
->font_desc
= font_desc
;
704 gtkut_convert_int_to_gdk_color(prefs_common
.color_new
, &gdk_color
);
705 normal_color_style
= gtk_style_copy(normal_style
);
706 normal_color_style
->fg
[GTK_STATE_NORMAL
] = gdk_color
;
710 gtkut_convert_int_to_gdk_color(prefs_common
.color_new
, &gdk_color
);
711 bold_style
= gtk_style_copy(gtk_widget_get_style(ctree
));
712 if (prefs_common
.derive_from_normal_font
|| !BOLD_FONT
) {
713 PangoFontDescription
*font_desc
;
714 font_desc
= pango_font_description_from_string(NORMAL_FONT
);
716 pango_font_description_free(bold_style
->font_desc
);
717 bold_style
->font_desc
= font_desc
;
719 pango_font_description_set_weight
720 (bold_style
->font_desc
, PANGO_WEIGHT_BOLD
);
722 PangoFontDescription
*font_desc
;
723 font_desc
= pango_font_description_from_string(BOLD_FONT
);
725 if (bold_style
->font_desc
)
726 pango_font_description_free
727 (bold_style
->font_desc
);
728 bold_style
->font_desc
= font_desc
;
731 bold_color_style
= gtk_style_copy(bold_style
);
732 bold_color_style
->fg
[GTK_STATE_NORMAL
] = gdk_color
;
734 bold_tgtfold_style
= gtk_style_copy(bold_style
);
735 bold_tgtfold_style
->fg
[GTK_STATE_NORMAL
] = folderview
->color_op
;
739 static gboolean
folderview_defer_set(gpointer data
)
741 FolderView
*folderview
= (FolderView
*)data
;
742 MainWindow
*mainwin
= folderview
->mainwin
;
746 if (mainwin
->lock_count
)
749 debug_print("doing deferred folderview_set now\n");
750 folderview_set(folderview
);
752 folderview
->deferred_refresh_id
= 0;
756 void folderview_set(FolderView
*folderview
)
758 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
759 MainWindow
*mainwin
= folderview
->mainwin
;
760 FolderItem
*sel_item
= NULL
, *op_item
= NULL
;
765 if (mainwin
->lock_count
) {
766 if (folderview
->deferred_refresh_id
== 0)
767 folderview
->deferred_refresh_id
=
768 g_timeout_add(500, folderview_defer_set
, folderview
);
769 debug_print("deferred folderview_set\n");
774 debug_print("Setting folder info...\n");
775 STATUSBAR_PUSH(mainwin
, _("Setting folder info..."));
777 main_window_cursor_wait(mainwin
);
779 if (folderview
->selected
)
780 sel_item
= folderview_get_selected_item(folderview
);
781 if (folderview
->opened
)
782 op_item
= folderview_get_opened_item(folderview
);
784 folderview
->selected
= NULL
;
785 folderview
->opened
= NULL
;
787 gtk_cmclist_freeze(GTK_CMCLIST(ctree
));
788 gtk_cmclist_clear(GTK_CMCLIST(ctree
));
790 folderview_set_folders(folderview
);
793 folderview
->selected
= gtk_cmctree_find_by_row_data(ctree
, NULL
, sel_item
);
795 folderview
->opened
= gtk_cmctree_find_by_row_data(ctree
, NULL
, op_item
);
797 gtk_cmclist_thaw(GTK_CMCLIST(ctree
));
798 main_window_cursor_normal(mainwin
);
799 STATUSBAR_POP(mainwin
);
803 void folderview_set_all(void)
807 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
)
808 folderview_set((FolderView
*)list
->data
);
811 void folderview_select(FolderView
*folderview
, FolderItem
*item
)
813 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
814 GtkCMCTreeNode
*node
;
815 GtkCMCTreeNode
*old_selected
= folderview
->selected
;
819 node
= gtk_cmctree_find_by_row_data(ctree
, NULL
, item
);
820 if (node
) folderview_select_node(folderview
, node
);
822 if (old_selected
!= node
)
823 folder_update_op_count();
826 static void mark_all_read_cb(GtkAction
*action
, gpointer data
)
828 mark_all_read_handler(action
, data
, FALSE
);
831 static void mark_all_read_recursive_cb(GtkAction
*action
, gpointer data
)
833 mark_all_read_handler(action
, data
, TRUE
);
836 static void mark_all_read_handler(GtkAction
*action
, gpointer data
, gboolean recursive
)
838 FolderView
*folderview
= (FolderView
*)data
;
843 item
= folderview_get_selected_item(folderview
);
847 message
= recursive
? _("Do you really want to mark all mails in this "
848 "folder and its sub-folders as read?") :
849 _("Do you really want to mark all mails in this "
851 if (folderview
->summaryview
->folder_item
!= item
&&
852 prefs_common
.ask_mark_all_read
) {
853 val
= alertpanel_full(_("Mark all as read"),
854 message
, GTK_STOCK_NO
, GTK_STOCK_YES
, NULL
,
855 TRUE
, NULL
, ALERT_QUESTION
, G_ALERTDEFAULT
);
857 if ((val
& ~G_ALERTDISABLE
) != G_ALERTALTERNATE
)
859 else if (val
& G_ALERTDISABLE
)
860 prefs_common
.ask_mark_all_read
= FALSE
;
863 folder_item_update_freeze();
864 if (folderview
->summaryview
->folder_item
!= item
&& !recursive
)
865 summary_lock(folderview
->summaryview
);
867 summary_freeze(folderview
->summaryview
);
870 folderutils_mark_all_read_recursive(item
);
872 folderutils_mark_all_read(item
);
874 if (folderview
->summaryview
->folder_item
!= item
&& !recursive
)
875 summary_unlock(folderview
->summaryview
);
877 summary_thaw(folderview
->summaryview
);
878 folder_item_update_thaw();
881 static void folderview_select_node(FolderView
*folderview
, GtkCMCTreeNode
*node
)
883 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
885 cm_return_if_fail(node
!= NULL
);
887 if (folderview
->open_folder
) {
891 gtk_cmclist_freeze(GTK_CMCLIST(ctree
));
892 gtkut_ctree_expand_parent_all(ctree
, node
);
894 folderview
->open_folder
= TRUE
;
895 gtkut_ctree_set_focus_row(ctree
, node
);
896 gtk_cmctree_select(ctree
, node
);
897 gtk_cmclist_thaw(GTK_CMCLIST(ctree
));
898 if ((folderview
->summaryview
->folder_item
&&
899 folderview
->summaryview
->folder_item
->total_msgs
> 0) ||
900 prefs_common
.layout_mode
== SMALL_LAYOUT
)
901 summary_select_node(folderview
->summaryview
,
902 folderview
->summaryview
->selected
, -1);
904 gtk_widget_grab_focus(folderview
->ctree
);
907 void folderview_unselect(FolderView
*folderview
)
909 if (folderview
->opened
&& !GTK_CMCTREE_ROW(folderview
->opened
)->children
)
911 (GTK_CMCTREE(folderview
->ctree
), folderview
->opened
);
913 folderview
->selected
= folderview
->opened
= NULL
;
916 static GtkCMCTreeNode
*folderview_find_next_with_flag(GtkCMCTree
*ctree
,
917 GtkCMCTreeNode
*node
,
923 node
= gtkut_ctree_node_next(ctree
, node
);
925 node
= GTK_CMCTREE_NODE(GTK_CMCLIST(ctree
)->row_list
);
927 for (; node
!= NULL
; node
= gtkut_ctree_node_next(ctree
, node
)) {
928 item
= gtk_cmctree_node_get_row_data(ctree
, node
);
931 if (item
->stype
== F_TRASH
|| item
->stype
== F_DRAFT
)
935 if(item
->unread_msgs
> 0)
939 if(item
->new_msgs
> 0)
943 if(item
->marked_msgs
> 0)
947 if(item
->total_msgs
> 0)
956 void folderview_select_next_with_flag(FolderView
*folderview
,
959 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
960 GtkCMCTreeNode
*node
= NULL
;
961 EntryAction last_summary_select_prio
= prefs_common
.summary_select_prio
[0];
965 prefs_common
.summary_select_prio
[0] = ACTION_UNREAD
;
968 prefs_common
.summary_select_prio
[0] = ACTION_NEW
;
971 prefs_common
.summary_select_prio
[0] = ACTION_MARKED
;
974 prefs_common
.summary_select_prio
[0] = ACTION_FIRST_LIST
;
978 node
= folderview_find_next_with_flag(ctree
, folderview
->opened
, flag
);
980 folderview_select_node(folderview
, node
);
984 if (!folderview
->opened
||
985 folderview
->opened
== GTK_CMCTREE_NODE(GTK_CMCLIST(ctree
)->row_list
)) {
989 /* search again from the first node */
990 node
= folderview_find_next_with_flag(ctree
, NULL
, flag
);
992 folderview_select_node(folderview
, node
);
995 prefs_common
.summary_select_prio
[0] = last_summary_select_prio
;
998 FolderItem
*folderview_get_selected_item(FolderView
*folderview
)
1000 g_return_val_if_fail(folderview
!= NULL
, NULL
);
1001 g_return_val_if_fail(folderview
->ctree
!= NULL
, NULL
);
1003 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
1005 if (!folderview
->selected
) return NULL
;
1006 return gtk_cmctree_node_get_row_data(ctree
, folderview
->selected
);
1009 FolderItem
*folderview_get_opened_item(FolderView
*folderview
)
1011 g_return_val_if_fail(folderview
!= NULL
, NULL
);
1012 g_return_val_if_fail(folderview
->ctree
!= NULL
, NULL
);
1014 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
1016 if (!folderview
->opened
) return NULL
;
1017 return gtk_cmctree_node_get_row_data(ctree
, folderview
->opened
);
1020 static void folderview_set_folders(FolderView
*folderview
)
1023 list
= folder_get_list();
1025 for (; list
!= NULL
; list
= list
->next
) {
1026 folderview_append_folder(folderview
, FOLDER(list
->data
));
1030 static gchar
*get_scan_str(FolderItem
*item
)
1033 return g_strdup_printf(_("Scanning folder %s/%s..."),
1034 item
->folder
->name
, item
->path
);
1036 return g_strdup_printf(_("Scanning folder %s..."),
1037 item
->folder
->name
);
1039 static void folderview_scan_tree_func(Folder
*folder
, FolderItem
*item
,
1043 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
) {
1044 FolderView
*folderview
= (FolderView
*)list
->data
;
1045 MainWindow
*mainwin
= folderview
->mainwin
;
1046 gchar
*str
= get_scan_str(item
);
1048 STATUSBAR_PUSH(mainwin
, str
);
1049 STATUSBAR_POP(mainwin
);
1054 void folderview_rescan_tree(Folder
*folder
, gboolean rebuild
)
1057 MainWindow
*mainwin
= mainwindow_get_mainwindow();
1058 FolderView
*folderview
= NULL
;
1059 GtkAdjustment
*pos
= NULL
;
1062 cm_return_if_fail(folder
!= NULL
);
1064 if (!folder
->klass
->scan_tree
) return;
1067 alertpanel_full(_("Rebuild folder tree"),
1068 _("Rebuilding the folder tree will remove "
1069 "local caches. Do you want to continue?"),
1070 GTK_STOCK_NO
, GTK_STOCK_YES
, NULL
, FALSE
,
1071 NULL
, ALERT_WARNING
, G_ALERTDEFAULT
)
1072 != G_ALERTALTERNATE
) {
1078 window
= label_window_create(_("Rebuilding folder tree..."));
1080 window
= label_window_create(_("Scanning folder tree..."));
1083 folderview
= mainwin
->folderview
;
1086 pos
= gtk_scrolled_window_get_vadjustment(
1087 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
1088 height
= gtk_adjustment_get_value(pos
);
1091 folder_set_ui_func(folder
, folderview_scan_tree_func
, NULL
);
1092 folder_scan_tree(folder
, rebuild
);
1093 folder_set_ui_func(folder
, NULL
, NULL
);
1095 folderview_set_all();
1098 pos
= gtk_scrolled_window_get_vadjustment(
1099 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
1100 gtk_adjustment_set_value(pos
, height
);
1101 gtk_adjustment_changed(pos
);
1103 label_window_destroy(window
);
1107 /** folderview_check_new()
1108 * Scan and update the folder and return the
1109 * count the number of new messages since last check.
1110 * \param folder the folder to check for new messages
1111 * \return the number of new messages since last check
1113 gint
folderview_check_new(Folder
*folder
)
1117 FolderView
*folderview
;
1119 GtkCMCTreeNode
*node
;
1121 gint former_new_msgs
= 0;
1122 gint former_new
= 0, former_unread
= 0, former_total
;
1124 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
) {
1125 folderview
= (FolderView
*)list
->data
;
1126 ctree
= GTK_CMCTREE(folderview
->ctree
);
1127 folderview
->scanning_folder
= folder
;
1129 main_window_lock(folderview
->mainwin
);
1131 for (node
= GTK_CMCTREE_NODE(GTK_CMCLIST(ctree
)->row_list
);
1132 node
!= NULL
; node
= gtkut_ctree_node_next(ctree
, node
)) {
1134 item
= gtk_cmctree_node_get_row_data(ctree
, node
);
1135 if (!item
|| !item
->path
|| !item
->folder
) continue;
1136 if (item
->no_select
) continue;
1137 if (folder
&& folder
!= item
->folder
) continue;
1138 if (!folder
&& !FOLDER_IS_LOCAL(item
->folder
)) continue;
1139 if (!item
->prefs
->newmailcheck
) continue;
1140 if (item
->processing_pending
== TRUE
) {
1141 debug_print("skipping %s, processing pending\n",
1142 item
->path
? item
->path
: item
->name
);
1145 if (item
->scanning
!= ITEM_NOT_SCANNING
) {
1146 debug_print("skipping %s, scanning\n",
1147 item
->path
? item
->path
: item
->name
);
1151 str
= get_scan_str(item
);
1153 STATUSBAR_PUSH(folderview
->mainwin
, str
);
1157 folderview_scan_tree_func(item
->folder
, item
, NULL
);
1158 former_new
= item
->new_msgs
;
1159 former_unread
= item
->unread_msgs
;
1160 former_total
= item
->total_msgs
;
1162 if (item
->folder
->klass
->scan_required
&&
1163 (item
->folder
->klass
->scan_required(item
->folder
, item
) ||
1164 item
->folder
->inbox
== item
||
1165 item
->opened
== TRUE
||
1166 item
->processing_pending
== TRUE
)) {
1167 if (folder_item_scan(item
) < 0) {
1169 summaryview_unlock(folderview
->summaryview
, item
);
1170 if (FOLDER_TYPE(item
->folder
) == F_NEWS
|| FOLDER_IS_LOCAL(folder
)) {
1171 log_error(LOG_PROTOCOL
, _("Couldn't scan folder %s\n"),
1172 item
->path
? item
->path
:item
->name
);
1173 STATUSBAR_POP(folderview
->mainwin
);
1175 } else if (!FOLDER_IS_LOCAL(folder
)) {
1176 STATUSBAR_POP(folderview
->mainwin
);
1181 } else if (!item
->folder
->klass
->scan_required
) {
1182 if (folder_item_scan(item
) < 0) {
1183 summaryview_unlock(folderview
->summaryview
, item
);
1184 if (folder
&& !FOLDER_IS_LOCAL(folder
)) {
1185 STATUSBAR_POP(folderview
->mainwin
);
1190 if (former_new
!= item
->new_msgs
||
1191 former_unread
!= item
->unread_msgs
||
1192 former_total
!= item
->total_msgs
)
1193 folderview_update_node(folderview
, node
);
1195 new_msgs
+= item
->new_msgs
;
1196 former_new_msgs
+= former_new
;
1197 STATUSBAR_POP(folderview
->mainwin
);
1199 folderview
->scanning_folder
= NULL
;
1200 main_window_unlock(folderview
->mainwin
);
1204 folder_write_list();
1205 /* Number of new messages since last check is the just the difference
1206 * between former_new_msgs and new_msgs. If new_msgs is less than
1207 * former_new_msgs, that would mean another session accessed the folder
1208 * and the result is not well defined.
1210 new_msgs
= (former_new_msgs
< new_msgs
? new_msgs
- former_new_msgs
: 0);
1214 void folderview_check_new_all(void)
1218 FolderView
*folderview
;
1220 folderview
= (FolderView
*)folderview_list
->data
;
1223 main_window_lock(folderview
->mainwin
);
1224 window
= label_window_create
1225 (_("Checking for new messages in all folders..."));
1227 list
= folder_get_list();
1228 for (; list
!= NULL
; list
= list
->next
) {
1229 Folder
*folder
= list
->data
;
1231 folderview_check_new(folder
);
1234 folder_write_list();
1235 folderview_set_all();
1237 label_window_destroy(window
);
1238 main_window_unlock(folderview
->mainwin
);
1242 static gboolean
folderview_have_children_sub(FolderView
*folderview
,
1248 if (!item
|| !item
->folder
|| !item
->folder
->node
)
1251 node
= item
->folder
->node
;
1253 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1254 node
= node
->children
;
1256 if (in_sub
&& item
->total_msgs
> 0) {
1260 while (node
!= NULL
) {
1261 if (node
&& node
->data
) {
1262 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1264 if (folderview_have_children_sub(folderview
,
1273 static gboolean
folderview_have_children(FolderView
*folderview
,
1276 return folderview_have_children_sub(folderview
, item
, FALSE
);
1279 static gboolean
folderview_have_new_children_sub(FolderView
*folderview
,
1285 if (!item
|| !item
->folder
|| !item
->folder
->node
)
1288 node
= item
->folder
->node
;
1290 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1291 node
= node
->children
;
1294 (item
->new_msgs
> 0 ||
1295 (folder_has_parent_of_type(item
, F_QUEUE
) && item
->total_msgs
> 0))) {
1299 while (node
!= NULL
) {
1300 if (node
&& node
->data
) {
1301 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1303 if (folderview_have_new_children_sub(folderview
,
1312 static gboolean
folderview_have_new_children(FolderView
*folderview
,
1315 return folderview_have_new_children_sub(folderview
, item
, FALSE
);
1318 static gboolean
folderview_have_unread_children_sub(FolderView
*folderview
,
1324 if (!item
|| !item
->folder
|| !item
->folder
->node
)
1327 node
= item
->folder
->node
;
1329 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1330 node
= node
->children
;
1333 (item
->unread_msgs
> 0 ||
1334 (folder_has_parent_of_type(item
, F_QUEUE
) && item
->total_msgs
> 0))) {
1338 while (node
!= NULL
) {
1339 if (node
&& node
->data
) {
1340 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1342 if (folderview_have_unread_children_sub(folderview
,
1352 static gboolean
folderview_have_unread_children(FolderView
*folderview
,
1355 return folderview_have_unread_children_sub(folderview
, item
, FALSE
);
1358 static gboolean
folderview_have_matching_children_sub(FolderView
*folderview
,
1364 if (!item
|| !item
->folder
|| !item
->folder
->node
)
1367 node
= item
->folder
->node
;
1369 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1370 node
= node
->children
;
1372 if (in_sub
&& item
->search_match
){
1376 while (node
!= NULL
) {
1377 if (node
&& node
->data
) {
1378 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1380 if (folderview_have_matching_children_sub(folderview
,
1390 static gboolean
folderview_have_matching_children(FolderView
*folderview
,
1393 return folderview_have_matching_children_sub(folderview
, item
, FALSE
);
1396 static gboolean
folderview_have_marked_children_sub(FolderView
*folderview
,
1402 if (!item
|| !item
->folder
|| !item
->folder
->node
)
1405 node
= item
->folder
->node
;
1407 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1408 node
= node
->children
;
1410 if (item
->marked_msgs
!= 0) {
1414 while (node
!= NULL
) {
1415 if (node
&& node
->data
) {
1416 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1418 if (folderview_have_marked_children_sub(folderview
,
1427 static gboolean
folderview_have_marked_children(FolderView
*folderview
,
1430 return folderview_have_marked_children_sub(folderview
, item
, FALSE
);
1433 static void folderview_update_node(FolderView
*folderview
, GtkCMCTreeNode
*node
)
1435 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
1436 GtkStyle
*style
= NULL
;
1437 GtkStyle
*color_style
= NULL
;
1439 GdkPixbuf
*xpm
, *openxpm
;
1440 static GdkPixbuf
*searchicon
;
1441 gboolean mark
= FALSE
;
1444 gboolean add_unread_mark
;
1445 gboolean add_sub_match_mark
;
1446 gboolean use_bold
, use_color
;
1447 gint
*col_pos
= folderview
->col_pos
;
1448 SpecialFolderItemType stype
;
1450 item
= gtk_cmctree_node_get_row_data(ctree
, node
);
1451 cm_return_if_fail(item
!= NULL
);
1453 if (!GTK_CMCTREE_ROW(node
)->expanded
)
1454 mark
= folderview_have_marked_children(folderview
, item
);
1456 mark
= (item
->marked_msgs
!= 0);
1458 stype
= item
->stype
;
1459 if (stype
== F_NORMAL
) {
1460 if (folder_has_parent_of_type(item
, F_TRASH
))
1462 else if (folder_has_parent_of_type(item
, F_DRAFT
))
1464 else if (folder_has_parent_of_type(item
, F_OUTBOX
))
1466 else if (folder_has_parent_of_type(item
, F_QUEUE
))
1471 if (item
->hide_read_msgs
|| item
->hide_read_threads
) {
1472 xpm
= mark
?m_inboxhrmxpm
:inboxhrmxpm
;
1473 openxpm
= mark
?m_inboxopenhrmxpm
:inboxopenhrmxpm
;
1475 xpm
= mark
?m_inboxxpm
:inboxxpm
;
1476 openxpm
= mark
?m_inboxopenxpm
:inboxopenxpm
;
1480 if (item
->hide_read_msgs
|| item
->hide_read_threads
) {
1481 xpm
= mark
?m_outboxhrmxpm
:outboxhrmxpm
;
1482 openxpm
= mark
?m_outboxopenhrmxpm
:outboxopenhrmxpm
;
1484 xpm
= mark
?m_outboxxpm
:outboxxpm
;
1485 openxpm
= mark
?m_outboxopenxpm
:outboxopenxpm
;
1489 if (item
->hide_read_msgs
|| item
->hide_read_threads
) {
1490 xpm
= mark
?m_queuehrmxpm
:queuehrmxpm
;
1491 openxpm
= mark
?m_queueopenhrmxpm
:queueopenhrmxpm
;
1493 xpm
= mark
?m_queuexpm
:queuexpm
;
1494 openxpm
= mark
?m_queueopenxpm
:queueopenxpm
;
1498 if (item
->hide_read_msgs
|| item
->hide_read_threads
) {
1499 xpm
= mark
?m_trashhrmxpm
:trashhrmxpm
;
1500 openxpm
= mark
?m_trashopenhrmxpm
:trashopenhrmxpm
;
1502 xpm
= mark
?m_trashxpm
:trashxpm
;
1503 openxpm
= mark
?m_trashopenxpm
:trashopenxpm
;
1507 xpm
= mark
?m_draftsxpm
:draftsxpm
;
1508 openxpm
= mark
?m_draftsopenxpm
:draftsopenxpm
;
1512 FOLDER_TYPE(item
->folder
) == F_IMAP
&&
1513 item
->folder
->account
->imap_subsonly
) {
1514 xpm
= mark
?m_foldersubsxpm
:foldersubsxpm
;
1515 openxpm
= foldersubsopenxpm
;
1516 } else if (item
->no_select
) {
1517 xpm
= mark
?m_foldernoselectxpm
:foldernoselectxpm
;
1518 openxpm
= foldernoselectopenxpm
;
1519 } else if (item
->hide_read_msgs
|| item
->hide_read_threads
) {
1520 xpm
= mark
?m_folderhrmxpm
:folderhrmxpm
;
1521 openxpm
= mark
?m_folderopenhrmxpm
:folderopenhrmxpm
;
1523 xpm
= mark
?m_folderxpm
:folderxpm
;
1524 openxpm
= mark
?m_folderopenxpm
:folderopenxpm
;
1528 name
= folder_item_get_name(item
);
1530 if (!GTK_CMCTREE_ROW(node
)->expanded
) {
1531 add_unread_mark
= folderview_have_unread_children(
1533 add_sub_match_mark
= folderview_have_matching_children(
1536 add_unread_mark
= FALSE
;
1537 add_sub_match_mark
= FALSE
;
1540 if (item
->search_match
) {
1542 stock_pixbuf_gdk(STOCK_PIXMAP_QUICKSEARCH
,
1545 xpm
= openxpm
= searchicon
;
1549 if (prefs_common
.display_folder_unread
) {
1550 if (folder_has_parent_of_type(item
, F_QUEUE
)) {
1551 /* only total_msgs matters here */
1552 if (item
->total_msgs
> 0) {
1553 /* show total number (should be equal to the unread number)
1555 str
= g_strdup_printf("%s (%d%s%s)",
1556 name
, item
->total_msgs
,
1557 (add_unread_mark
|| add_sub_match_mark
) ? "+" : "",
1558 (item
->unreadmarked_msgs
> 0) ? "!" : "");
1561 if (prefs_common
.display_folder_unread
== 1) {
1562 if (item
->unread_msgs
> 0) {
1563 /* show unread number and signs */
1564 str
= g_strdup_printf("%s (%d%s%s)",
1565 name
, item
->unread_msgs
,
1566 (add_unread_mark
|| add_sub_match_mark
) ? "+" : "",
1567 (item
->unreadmarked_msgs
> 0) ? "!" : "");
1570 if (item
->total_msgs
> 0) {
1571 /* show unread number, total number and signs if any */
1572 str
= g_strdup_printf("%s (%d/%d%s%s)",
1573 name
, item
->unread_msgs
, item
->total_msgs
,
1574 (add_unread_mark
|| add_sub_match_mark
) ? "+" : "",
1575 (item
->unreadmarked_msgs
> 0) ? "!" : "");
1579 if ((str
== NULL
) &&
1580 (add_unread_mark
|| add_sub_match_mark
|| (item
->unreadmarked_msgs
> 0))) {
1581 /* no unread/total numbers, but at least one sign */
1582 str
= g_strdup_printf("%s (%s%s)",
1584 (add_unread_mark
|| add_sub_match_mark
) ? "+" : "",
1585 (item
->unreadmarked_msgs
> 0) ? "!" : "");
1589 /* last fallback, folder name only or with +! sign */
1590 if (item
->unreadmarked_msgs
> 0 && add_sub_match_mark
) {
1591 str
= g_strdup_printf("%s%s",
1593 } else if (item
->unreadmarked_msgs
> 0) {
1594 str
= g_strdup_printf("%s%s",
1596 } else if (add_sub_match_mark
) {
1597 str
= g_strdup_printf("%s%s",
1600 str
= g_strdup_printf("%s", name
);
1603 gtk_cmctree_set_node_info(ctree
, node
, str
, FOLDER_SPACING
,
1605 FALSE
, GTK_CMCTREE_ROW(node
)->expanded
);
1609 if (!folder_item_parent(item
)) {
1610 gtk_cmctree_node_set_text(ctree
, node
, col_pos
[F_COL_NEW
], "-");
1611 gtk_cmctree_node_set_text(ctree
, node
, col_pos
[F_COL_UNREAD
], "-");
1612 gtk_cmctree_node_set_text(ctree
, node
, col_pos
[F_COL_TOTAL
], "-");
1614 gtk_cmctree_node_set_text(ctree
, node
, col_pos
[F_COL_NEW
], item
->new_msgs
> 0 ? itos(item
->new_msgs
) : prefs_common
.zero_replacement
);
1615 gtk_cmctree_node_set_text(ctree
, node
, col_pos
[F_COL_UNREAD
], item
->unread_msgs
> 0 ? itos(item
->unread_msgs
) : prefs_common
.zero_replacement
);
1616 gtk_cmctree_node_set_text(ctree
, node
, col_pos
[F_COL_TOTAL
], item
->total_msgs
> 0 ? itos(item
->total_msgs
) : prefs_common
.zero_replacement
);
1619 if (folder_has_parent_of_type(item
, F_OUTBOX
) ||
1620 folder_has_parent_of_type(item
, F_TRASH
)) {
1621 use_bold
= use_color
= FALSE
;
1622 } else if (folder_has_parent_of_type(item
, F_QUEUE
)) {
1623 GSList
*list
= folder_item_get_msg_list(item
);
1625 use_bold
= use_color
= FALSE
;
1626 for (cur
= list
; cur
; cur
= cur
->next
) {
1627 MsgInfo
*msginfo
= (MsgInfo
*)cur
->data
;
1628 if (!MSG_IS_DELETED(msginfo
->flags
)) {
1629 /* highlight queue folder if there are any messages */
1630 use_bold
= use_color
= TRUE
;
1634 if (!GTK_CMCTREE_ROW(node
)->expanded
&&
1635 use_bold
== FALSE
&&
1636 folderview_have_children(folderview
, item
))
1637 use_bold
= use_color
= TRUE
;
1638 procmsg_msg_list_free(list
);
1640 /* if unread messages exist, print with bold font */
1641 use_bold
= (item
->unread_msgs
> 0|| item
->new_msgs
> 0)
1643 /* if new messages exist, print with colored letter */
1645 (item
->new_msgs
> 0) ||
1647 folderview_have_new_children(folderview
, item
));
1650 gtk_cmctree_node_set_foreground(ctree
, node
, NULL
);
1655 if (item
->prefs
->color
> 0 && !use_color
) {
1656 gtkut_convert_int_to_gdk_color(item
->prefs
->color
, &gdk_color
);
1657 color_style
= gtk_style_copy(bold_style
);
1658 color_style
->fg
[GTK_STATE_NORMAL
] = gdk_color
;
1659 style
= color_style
;
1660 } else if (use_color
) {
1661 style
= bold_color_style
;
1664 if (item
->op_count
> 0) {
1665 style
= bold_tgtfold_style
;
1667 } else if (use_color
) {
1668 style
= normal_color_style
;
1669 gtk_cmctree_node_set_foreground(ctree
, node
,
1670 &folderview
->color_new
);
1671 } else if (item
->op_count
> 0) {
1672 style
= bold_tgtfold_style
;
1673 } else if (item
->prefs
->color
> 0) {
1675 gtkut_convert_int_to_gdk_color(item
->prefs
->color
, &gdk_color
);
1676 color_style
= gtk_style_copy(normal_style
);
1677 color_style
->fg
[GTK_STATE_NORMAL
] = gdk_color
;
1678 style
= color_style
;
1680 style
= normal_style
;
1683 gtk_cmctree_node_set_row_style(ctree
, node
, style
);
1685 if ((node
= gtkut_ctree_find_collapsed_parent(ctree
, node
)) != NULL
)
1686 folderview_update_node(folderview
, node
);
1689 void folderview_update_search_icon(FolderItem
*item
, gboolean matches
)
1692 FolderView
*folderview
;
1694 GtkCMCTreeNode
*node
;
1696 cm_return_if_fail(item
!= NULL
);
1698 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
) {
1699 folderview
= (FolderView
*)list
->data
;
1700 ctree
= GTK_CMCTREE(folderview
->ctree
);
1702 node
= gtk_cmctree_find_by_row_data(ctree
, NULL
, item
);
1703 if (node
&& item
->search_match
!= matches
) {
1704 item
->search_match
= matches
;
1705 folderview_update_node(folderview
, node
);
1710 static gboolean
folderview_update_item_claws(gpointer source
, gpointer data
)
1712 FolderItemUpdateData
*update_info
= (FolderItemUpdateData
*)source
;
1713 FolderView
*folderview
= (FolderView
*)data
;
1715 GtkCMCTreeNode
*node
;
1716 cm_return_val_if_fail(update_info
!= NULL
, TRUE
);
1717 cm_return_val_if_fail(update_info
->item
!= NULL
, TRUE
);
1718 cm_return_val_if_fail(folderview
!= NULL
, FALSE
);
1720 ctree
= GTK_CMCTREE(folderview
->ctree
);
1722 node
= gtk_cmctree_find_by_row_data(ctree
, NULL
, update_info
->item
);
1725 if (update_info
->update_flags
& (F_ITEM_UPDATE_MSGCNT
| F_ITEM_UPDATE_NAME
))
1726 folderview_update_node(folderview
, node
);
1728 if ((update_info
->update_flags
& F_ITEM_UPDATE_CONTENT
) &&
1729 update_info
->item
== folderview
->summaryview
->folder_item
&&
1730 update_info
->item
!= NULL
)
1731 if (!quicksearch_has_sat_predicate(folderview
->summaryview
->quicksearch
))
1732 summary_show(folderview
->summaryview
, update_info
->item
);
1738 static gboolean
folderview_gnode_func(GtkCMCTree
*ctree
, guint depth
,
1739 GNode
*gnode
, GtkCMCTreeNode
*cnode
,
1742 FolderView
*folderview
= (FolderView
*)data
;
1743 FolderItem
*item
= FOLDER_ITEM(gnode
->data
);
1745 cm_return_val_if_fail(item
!= NULL
, FALSE
);
1747 gtk_cmctree_node_set_row_data(ctree
, cnode
, item
);
1748 folderview_update_node(folderview
, cnode
);
1753 static void folderview_expand_func(GtkCMCTree
*ctree
, GtkCMCTreeNode
*node
,
1756 FolderView
*folderview
= (FolderView
*)data
;
1759 if (GTK_CMCTREE_ROW(node
)->children
) {
1760 item
= gtk_cmctree_node_get_row_data(ctree
, node
);
1761 cm_return_if_fail(item
!= NULL
);
1763 if (!item
->collapsed
)
1764 gtk_cmctree_expand(ctree
, node
);
1766 folderview_update_node(folderview
, node
);
1770 static void set_special_folder(GtkCMCTree
*ctree
, FolderItem
*item
,
1771 GtkCMCTreeNode
*root
, GtkCMCTreeNode
**prev
)
1774 GtkCMCTreeNode
*node
, *parent
, *sibling
;
1776 node
= gtk_cmctree_find_by_row_data(ctree
, root
, item
);
1778 g_warning("%s not found.", item
->path
);
1780 parent
= GTK_CMCTREE_ROW(node
)->parent
;
1781 if (*prev
&& parent
== GTK_CMCTREE_ROW(*prev
)->parent
)
1782 sibling
= GTK_CMCTREE_ROW(*prev
)->sibling
;
1784 sibling
= GTK_CMCTREE_ROW(parent
)->children
;
1788 tmp
= gtk_cmctree_node_get_row_data
1790 if (tmp
&& tmp
->stype
!= F_NORMAL
)
1791 sibling
= GTK_CMCTREE_ROW(sibling
)->sibling
;
1795 if (node
!= sibling
)
1796 gtk_cmctree_move(ctree
, node
, parent
, sibling
);
1803 static void folderview_sort_folders(FolderView
*folderview
, GtkCMCTreeNode
*root
,
1806 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
1807 GtkCMCTreeNode
*prev
= NULL
;
1809 gtk_cmclist_freeze(GTK_CMCLIST(ctree
));
1810 gtk_sctree_sort_recursive(ctree
, root
);
1811 if (root
&& GTK_CMCTREE_ROW(root
)->parent
) {
1812 gtk_cmclist_thaw(GTK_CMCLIST(ctree
));
1815 set_special_folder(ctree
, folder
->inbox
, root
, &prev
);
1816 set_special_folder(ctree
, folder
->outbox
, root
, &prev
);
1817 set_special_folder(ctree
, folder
->draft
, root
, &prev
);
1818 set_special_folder(ctree
, folder
->queue
, root
, &prev
);
1819 set_special_folder(ctree
, folder
->trash
, root
, &prev
);
1820 gtk_cmclist_thaw(GTK_CMCLIST(ctree
));
1823 static void folderview_append_folder(FolderView
*folderview
, Folder
*folder
)
1825 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
1826 GtkCMCTreeNode
*root
;
1828 cm_return_if_fail(folder
!= NULL
);
1830 root
= gtk_sctree_insert_gnode(ctree
, NULL
, NULL
, folder
->node
,
1831 folderview_gnode_func
, folderview
);
1832 gtk_cmctree_pre_recursive(ctree
, root
, folderview_expand_func
,
1834 folderview_sort_folders(folderview
, root
, folder
);
1837 /* callback functions */
1838 static void folderview_set_sens_and_popup_menu(FolderView
*folderview
, gint row
,
1839 GdkEventButton
*event
)
1843 FolderViewPopup
*fpopup
;
1844 GtkActionGroup
*action_group
;
1846 FolderItem
*special_trash
= NULL
, *special_queue
= NULL
;
1848 GtkUIManager
*ui_manager
= gtk_ui_manager_new();
1850 if (folderview
->ui_manager
)
1851 g_object_unref(folderview
->ui_manager
);
1853 folderview
->ui_manager
= ui_manager
;
1854 item
= folderview_get_selected_item(folderview
);
1856 cm_return_if_fail(item
!= NULL
);
1857 cm_return_if_fail(item
->folder
!= NULL
);
1858 folder
= item
->folder
;
1860 fpopup
= g_hash_table_lookup(folderview_popups
, folder
->klass
->idstr
);
1863 action_group
= g_hash_table_lookup(folderview
->popups
, folder
->klass
->idstr
);
1865 fpopup
= g_hash_table_lookup(folderview_popups
, "common");
1866 action_group
= g_hash_table_lookup(folderview
->popups
, "common");
1869 gtk_ui_manager_insert_action_group(ui_manager
, action_group
, 0);
1870 MENUITEM_ADDUI_MANAGER(ui_manager
, "/", "Popup", "Popup", GTK_UI_MANAGER_MENUBAR
)
1871 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup", "FolderViewPopup", "FolderViewPopup", GTK_UI_MANAGER_MENU
)
1873 if (fpopup
->add_menuitems
)
1874 fpopup
->add_menuitems(ui_manager
, item
);
1876 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "MarkAllRead", "FolderViewPopup/MarkAllRead", GTK_UI_MANAGER_MENUITEM
)
1877 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "MarkAllReadRec", "FolderViewPopup/MarkAllReadRec", GTK_UI_MANAGER_MENUITEM
)
1878 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "Separator1", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR
)
1879 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "RunProcessing", "FolderViewPopup/RunProcessing", GTK_UI_MANAGER_MENUITEM
)
1880 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "SearchFolder", "FolderViewPopup/SearchFolder", GTK_UI_MANAGER_MENUITEM
)
1881 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "Properties", "FolderViewPopup/Properties", GTK_UI_MANAGER_MENUITEM
)
1882 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "Processing", "FolderViewPopup/Processing", GTK_UI_MANAGER_MENUITEM
)
1884 if (fpopup
->set_sensitivity
!= NULL
)
1885 fpopup
->set_sensitivity(ui_manager
, item
);
1887 if (NULL
!= (ac
= account_find_from_item(item
))) {
1888 special_trash
= account_get_special_folder(ac
, F_TRASH
);
1889 special_queue
= account_get_special_folder(ac
, F_QUEUE
);
1892 if ((item
== folder
->trash
|| item
== special_trash
1893 || folder_has_parent_of_type(item
, F_TRASH
))) {
1894 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "SeparatorTrash", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR
)
1895 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "EmptyTrash", "FolderViewPopup/EmptyTrash", GTK_UI_MANAGER_MENUITEM
)
1898 if ((item
== folder
->queue
|| item
== special_queue
1899 || folder_has_parent_of_type(item
, F_QUEUE
))) {
1900 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "SeparatorQueue", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR
)
1901 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "SendQueue", "FolderViewPopup/SendQueue", GTK_UI_MANAGER_MENUITEM
)
1904 #define SET_SENS(name, sens) \
1905 cm_menu_set_sensitive_full(ui_manager, "Popup/"name, sens)
1907 SET_SENS("FolderViewPopup/MarkAllRead", item
->unread_msgs
>= 1);
1908 SET_SENS("FolderViewPopup/MarkAllReadRec", folderview_have_unread_children(folderview
,item
));
1909 SET_SENS("FolderViewPopup/SearchFolder", item
->total_msgs
>= 1 &&
1910 folderview
->selected
== folderview
->opened
);
1911 SET_SENS("FolderViewPopup/Properties", TRUE
);
1913 SET_SENS("FolderViewPopup/RunProcessing", item
->prefs
->processing
&&
1914 item
->total_msgs
>= 1 && !item
->processing_pending
);
1915 SET_SENS("FolderViewPopup/Processing", item
->node
->parent
!= NULL
&&
1916 !item
->no_select
&& !item
->processing_pending
);
1918 if (item
== folder
->trash
|| item
== special_trash
1919 || folder_has_parent_of_type(item
, F_TRASH
)) {
1920 GSList
*msglist
= folder_item_get_msg_list(item
);
1921 SET_SENS("FolderViewPopup/EmptyTrash", msglist
!= NULL
);
1922 procmsg_msg_list_free(msglist
);
1924 if (item
== folder
->queue
|| item
== special_queue
1925 || folder_has_parent_of_type(item
, F_QUEUE
)) {
1926 GSList
*msglist
= folder_item_get_msg_list(item
);
1927 SET_SENS("FolderViewPopup/SendQueue", msglist
!= NULL
);
1928 procmsg_msg_list_free(msglist
);
1932 popup
= gtk_menu_item_get_submenu(GTK_MENU_ITEM(
1933 gtk_ui_manager_get_widget(ui_manager
, "/Popup/FolderViewPopup")) );
1934 g_signal_connect(G_OBJECT(popup
), "selection_done",
1935 G_CALLBACK(folderview_popup_close
),
1937 gtk_menu_popup(GTK_MENU(popup
), NULL
, NULL
, NULL
, NULL
,
1938 event
->button
, event
->time
);
1941 static gboolean
folderview_button_pressed(GtkWidget
*ctree
, GdkEventButton
*event
,
1942 FolderView
*folderview
)
1944 GtkCMCList
*clist
= GTK_CMCLIST(ctree
);
1945 gint prev_row
= -1, row
= -1, column
= -1;
1947 if (!event
) return FALSE
;
1949 if (event
->button
== 1 || event
->button
== 2) {
1950 if (!gtk_sctree_is_hot_spot (GTK_SCTREE(clist
), event
->x
, event
->y
))
1951 folderview
->open_folder
= TRUE
;
1953 if (event
->type
== GDK_2BUTTON_PRESS
) {
1954 if (clist
->selection
) {
1955 GtkCMCTreeNode
*node
;
1957 node
= GTK_CMCTREE_NODE(clist
->selection
->data
);
1959 gtk_cmctree_toggle_expansion(
1962 folderview
->open_folder
= FALSE
;
1969 if (event
->button
== 2 || event
->button
== 3) {
1971 if (clist
->selection
) {
1972 GtkCMCTreeNode
*node
;
1974 node
= GTK_CMCTREE_NODE(clist
->selection
->data
);
1976 prev_row
= gtkut_ctree_get_nth_from_node
1977 (GTK_CMCTREE(ctree
), node
);
1980 if (!gtk_cmclist_get_selection_info(clist
, event
->x
, event
->y
,
1983 if (prev_row
!= row
) {
1984 gtk_cmclist_unselect_all(clist
);
1985 if (event
->button
== 2)
1986 folderview_select_node
1988 gtk_cmctree_node_nth(GTK_CMCTREE(ctree
),
1991 gtk_cmclist_select_row(clist
, row
, column
);
1995 if (event
->button
!= 3) return FALSE
;
1997 folderview_set_sens_and_popup_menu(folderview
, row
, event
);
2001 static gboolean
folderview_button_released(GtkWidget
*ctree
, GdkEventButton
*event
,
2002 FolderView
*folderview
)
2004 int row
= -1, column
= -1;
2006 if (!event
) return FALSE
;
2008 if (!gtk_cmclist_get_selection_info(GTK_CMCLIST(ctree
), event
->x
, event
->y
,
2011 if (event
->button
== 1 && folderview
->open_folder
== FALSE
&&
2012 folderview
->opened
!= NULL
) {
2013 gtkut_ctree_set_focus_row(GTK_CMCTREE(ctree
),
2014 folderview
->opened
);
2015 gtk_cmctree_select(GTK_CMCTREE(ctree
), folderview
->opened
);
2021 #define BREAK_ON_MODIFIER_KEY() \
2022 if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0) break
2024 static gboolean
folderview_key_pressed(GtkWidget
*widget
, GdkEventKey
*event
,
2025 FolderView
*folderview
)
2027 GtkCMCTreeNode
*node
;
2030 if (!event
) return FALSE
;
2032 if (quicksearch_has_focus(folderview
->summaryview
->quicksearch
))
2035 switch (event
->keyval
) {
2037 if (folderview
->selected
) {
2038 if (GTK_CMCTREE_ROW(folderview
->selected
)->children
!= NULL
2039 && !GTK_CMCTREE_ROW(folderview
->selected
)->expanded
)
2040 gtk_cmctree_expand(GTK_CMCTREE(folderview
->ctree
),
2041 folderview
->selected
);
2043 folderview_select_node(folderview
,
2044 folderview
->selected
);
2048 case GDK_KEY_Return
:
2049 if (folderview
->selected
&& GTK_CMCTREE_ROW(folderview
->selected
)->children
) {
2050 gtk_cmctree_toggle_expansion(
2051 GTK_CMCTREE(folderview
->ctree
),
2052 folderview
->selected
);
2056 case GDK_KEY_Return
:
2057 case GDK_KEY_KP_Enter
:
2058 if (folderview
->selected
)
2059 folderview_select_node(folderview
, folderview
->selected
);
2063 BREAK_ON_MODIFIER_KEY();
2064 if (folderview
->selected
) {
2065 if (folderview
->opened
== folderview
->selected
&&
2066 (!folderview
->summaryview
->folder_item
||
2067 folderview
->summaryview
->folder_item
->total_msgs
== 0))
2068 folderview_select_next_with_flag(folderview
, MSG_UNREAD
);
2070 folderview_select_node(folderview
,
2071 folderview
->selected
);
2075 if (folderview
->selected
) {
2076 if (GTK_CMCTREE_ROW(folderview
->selected
)->expanded
) {
2077 gtk_cmctree_collapse(GTK_CMCTREE(folderview
->ctree
),
2078 folderview
->selected
);
2080 if ((item
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(folderview
->ctree
),
2081 folderview
->selected
))) {
2082 if ((node
= gtk_cmctree_find_by_row_data(GTK_CMCTREE(folderview
->ctree
),
2083 NULL
, folder_item_parent(item
)))) {
2084 gtk_sctree_select(GTK_SCTREE(folderview
->ctree
), node
);
2085 if (!gtk_cmctree_node_is_visible(GTK_CMCTREE(folderview
->ctree
), node
))
2086 gtk_cmctree_node_moveto(GTK_CMCTREE(folderview
->ctree
),
2095 if (event
->keyval
== GDK_KEY_Home
)
2096 node
= gtk_cmctree_node_nth(GTK_CMCTREE(folderview
->ctree
), 0);
2098 node
= gtk_cmctree_last(GTK_CMCTREE(folderview
->ctree
),
2099 gtk_cmctree_node_nth(GTK_CMCTREE(folderview
->ctree
), 0));
2101 gtk_sctree_select(GTK_SCTREE(folderview
->ctree
), node
);
2103 if (!gtk_cmctree_node_is_visible(GTK_CMCTREE(folderview
->ctree
), node
))
2104 gtk_cmctree_node_moveto(GTK_CMCTREE(folderview
->ctree
),
2114 typedef struct _PostponedSelectData
2117 GtkCMCTreeNode
*row
;
2119 FolderView
*folderview
;
2120 } PostponedSelectData
;
2122 static gboolean
postpone_select(void *data
)
2124 PostponedSelectData
*psdata
= (PostponedSelectData
*)data
;
2125 debug_print("trying again\n");
2127 psdata
->folderview
->postpone_select_id
= 0;
2128 psdata
->folderview
->open_folder
= TRUE
;
2129 main_window_cursor_normal(psdata
->folderview
->mainwin
);
2130 STATUSBAR_POP(psdata
->folderview
->mainwin
);
2131 folderview_selected(psdata
->ctree
, psdata
->row
,
2132 psdata
->column
, psdata
->folderview
);
2137 void folderview_close_opened(FolderView
*folderview
, gboolean dirty
)
2139 if (folderview
->opened
) {
2141 folderview
->opened
= NULL
;
2145 FolderItem
*olditem
=
2146 gtk_cmctree_node_get_row_data(GTK_CMCTREE(folderview
->ctree
),
2147 folderview
->opened
);
2149 gchar
*buf
= g_strdup_printf(_("Closing folder %s..."),
2150 olditem
->path
? olditem
->path
:olditem
->name
);
2151 /* will be null if we just moved the previously opened folder */
2152 STATUSBAR_PUSH(folderview
->mainwin
, buf
);
2153 main_window_cursor_wait(folderview
->mainwin
);
2155 summary_save_prefs_to_folderitem(folderview
->summaryview
, olditem
);
2156 summary_show(folderview
->summaryview
, NULL
);
2157 folder_item_close(olditem
);
2158 main_window_cursor_normal(folderview
->mainwin
);
2159 STATUSBAR_POP(folderview
->mainwin
);
2160 if (olditem
->folder
->klass
->item_closed
)
2161 olditem
->folder
->klass
->item_closed(olditem
);
2166 if (folderview
->opened
&&
2167 !GTK_CMCTREE_ROW(folderview
->opened
)->children
)
2168 gtk_cmctree_collapse(GTK_CMCTREE(folderview
->ctree
), folderview
->opened
);
2170 folderview
->opened
= NULL
;
2172 static void folderview_selected(GtkCMCTree
*ctree
, GtkCMCTreeNode
*row
,
2173 gint column
, FolderView
*folderview
)
2175 static gboolean can_select
= TRUE
; /* exclusive lock */
2180 GtkCMCTreeNode
*old_opened
= folderview
->opened
;
2182 folderview
->selected
= row
;
2184 debug_print("newly selected %p, opened %p\n", folderview
->selected
,
2185 folderview
->opened
);
2186 if (folderview
->opened
== row
) {
2187 folderview
->open_folder
= FALSE
;
2192 item
= gtk_cmctree_node_get_row_data(ctree
, row
);
2195 folderview
->open_folder
= FALSE
;
2199 if (!can_select
|| summary_is_locked(folderview
->summaryview
)) {
2200 if (folderview
->opened
) {
2201 gtkut_ctree_set_focus_row(ctree
, folderview
->opened
);
2202 gtk_cmctree_select(ctree
, folderview
->opened
);
2204 folderview
->open_folder
= FALSE
;
2209 if (!folderview
->open_folder
) {
2216 /* Save cache for old folder */
2217 /* We don't want to lose all caches if sylpheed crashed */
2218 /* resets folderview->opened to NULL */
2219 folderview_close_opened(folderview
, FALSE
);
2221 /* CLAWS: set compose button type: news folder items
2222 * always have a news folder as parent */
2224 toolbar_set_compose_button
2225 (folderview
->mainwin
->toolbar
,
2226 FOLDER_TYPE(item
->folder
) == F_NEWS
?
2227 COMPOSEBUTTON_NEWS
: COMPOSEBUTTON_MAIL
);
2230 debug_print("Folder %s is selected\n", item
->path
);
2232 if (!GTK_CMCTREE_ROW(row
)->children
)
2233 gtk_cmctree_expand(ctree
, row
);
2235 /* ungrab the mouse event */
2236 if (gtk_widget_has_grab(GTK_WIDGET(ctree
))) {
2237 gtk_grab_remove(GTK_WIDGET(ctree
));
2238 if (gdk_pointer_is_grabbed())
2239 gdk_pointer_ungrab(GDK_CURRENT_TIME
);
2243 /* TODO: wwp: avoid displaying (null) in the status bar */
2244 buf
= g_strdup_printf(_("Opening folder %s..."), item
->path
?
2245 item
->path
: "(null)");
2246 debug_print("%s\n", buf
);
2247 STATUSBAR_PUSH(folderview
->mainwin
, buf
);
2250 main_window_cursor_wait(folderview
->mainwin
);
2252 if (folderview
->scanning_folder
== item
->folder
) {
2255 res
= folder_item_open(item
);
2258 if (res
== -1 && item
->no_select
== FALSE
) {
2259 main_window_cursor_normal(folderview
->mainwin
);
2260 STATUSBAR_POP(folderview
->mainwin
);
2262 alertpanel_error(_("Folder could not be opened."));
2264 folderview
->open_folder
= FALSE
;
2268 } else if (res
== -2 && item
->no_select
== FALSE
) {
2269 PostponedSelectData
*data
= g_new0(PostponedSelectData
, 1);
2270 data
->ctree
= ctree
;
2272 data
->column
= column
;
2273 data
->folderview
= folderview
;
2274 debug_print("postponing open of %s till end of scan\n",
2275 item
->path
? item
->path
:item
->name
);
2276 folderview
->open_folder
= FALSE
;
2278 if (folderview
->postpone_select_id
!= 0)
2279 g_source_remove(folderview
->postpone_select_id
);
2280 folderview
->postpone_select_id
= g_timeout_add(500, postpone_select
, data
);
2285 main_window_cursor_normal(folderview
->mainwin
);
2288 summary_set_prefs_from_folderitem(folderview
->summaryview
, item
);
2289 opened
= summary_show(folderview
->summaryview
, item
);
2291 folder_clean_cache_memory(item
);
2294 gtkut_ctree_set_focus_row(ctree
, old_opened
);
2295 gtk_cmctree_select(ctree
, old_opened
);
2296 folderview
->opened
= old_opened
;
2298 folderview
->opened
= row
;
2299 if (gtk_cmctree_node_is_visible(ctree
, row
)
2300 != GTK_VISIBILITY_FULL
)
2301 gtk_cmctree_node_moveto(ctree
, row
, -1, 0.5, 0);
2304 STATUSBAR_POP(folderview
->mainwin
);
2306 folderview
->open_folder
= FALSE
;
2311 static void folderview_tree_expanded(GtkCMCTree
*ctree
, GtkCMCTreeNode
*node
,
2312 FolderView
*folderview
)
2316 item
= gtk_cmctree_node_get_row_data(ctree
, node
);
2317 cm_return_if_fail(item
!= NULL
);
2318 item
->collapsed
= FALSE
;
2319 folderview_update_node(folderview
, node
);
2322 static void folderview_tree_collapsed(GtkCMCTree
*ctree
, GtkCMCTreeNode
*node
,
2323 FolderView
*folderview
)
2327 item
= gtk_cmctree_node_get_row_data(ctree
, node
);
2328 cm_return_if_fail(item
!= NULL
);
2329 item
->collapsed
= TRUE
;
2330 folderview_update_node(folderview
, node
);
2333 static void folderview_popup_close(GtkMenuShell
*menu_shell
,
2334 FolderView
*folderview
)
2336 if (!folderview
->opened
) return;
2338 gtk_cmctree_select(GTK_CMCTREE(folderview
->ctree
), folderview
->opened
);
2341 static void folderview_col_resized(GtkCMCList
*clist
, gint column
, gint width
,
2342 FolderView
*folderview
)
2344 FolderColumnType type
= folderview
->col_state
[column
].type
;
2346 prefs_common
.folder_col_size
[type
] = width
;
2349 static void folderview_create_folder_node(FolderView
*folderview
, FolderItem
*item
)
2351 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
2352 gchar
*text
[N_FOLDER_COLS
] = {NULL
, "0", "0", "0"};
2353 GtkCMCTreeNode
*node
, *parent_node
;
2354 gint
*col_pos
= folderview
->col_pos
;
2355 FolderItemUpdateData hookdata
;
2357 parent_node
= gtk_cmctree_find_by_row_data(ctree
, NULL
, folder_item_parent(item
));
2358 if (parent_node
== NULL
)
2361 gtk_cmclist_freeze(GTK_CMCLIST(ctree
));
2363 text
[col_pos
[F_COL_FOLDER
]] = item
->name
;
2364 node
= gtk_sctree_insert_node(ctree
, parent_node
, NULL
, text
,
2369 gtk_cmctree_expand(ctree
, parent_node
);
2370 gtk_cmctree_node_set_row_data(ctree
, node
, item
);
2372 gtk_cmctree_node_set_row_style(ctree
, node
, normal_style
);
2373 folderview_sort_folders(folderview
, parent_node
, item
->folder
);
2375 hookdata
.item
= item
;
2376 hookdata
.update_flags
= F_ITEM_UPDATE_NAME
;
2377 hookdata
.msg
= NULL
;
2378 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST
, &hookdata
);
2380 gtk_cmclist_thaw(GTK_CMCLIST(ctree
));
2383 static void folderview_empty_trash_cb(GtkAction
*action
, gpointer data
)
2385 FolderView
*folderview
= (FolderView
*)data
;
2387 GSList
*mlist
= NULL
;
2389 FolderItem
*special_trash
= NULL
;
2392 if (!folderview
->selected
) return;
2393 item
= folderview_get_selected_item(folderview
);
2394 cm_return_if_fail(item
!= NULL
);
2395 cm_return_if_fail(item
->folder
!= NULL
);
2397 if (NULL
!= (ac
= account_find_from_item(item
)))
2398 special_trash
= account_get_special_folder(ac
, F_TRASH
);
2400 if (item
!= item
->folder
->trash
&& item
!= special_trash
2401 && !folder_has_parent_of_type(item
, F_TRASH
)) return;
2403 if (prefs_common
.ask_on_clean
) {
2404 if (alertpanel(_("Empty trash"),
2405 _("Delete all messages in trash?"),
2406 GTK_STOCK_CANCEL
, g_strconcat("+", _("_Empty trash"), NULL
), NULL
) != G_ALERTALTERNATE
)
2410 mlist
= folder_item_get_msg_list(item
);
2412 for (cur
= mlist
; cur
!= NULL
; cur
= cur
->next
) {
2413 MsgInfo
* msginfo
= (MsgInfo
*) cur
->data
;
2414 if (MSG_IS_LOCKED(msginfo
->flags
))
2416 /* is it partially received? (partial_recv isn't cached) */
2417 if (msginfo
->total_size
!= 0 &&
2418 msginfo
->size
!= (off_t
)msginfo
->total_size
)
2419 partial_mark_for_delete(msginfo
);
2421 procmsg_msg_list_free(mlist
);
2423 folder_item_remove_all_msg(item
);
2426 static void folderview_send_queue_cb(GtkAction
*action
, gpointer data
)
2428 FolderView
*folderview
= (FolderView
*)data
;
2430 FolderItem
*special_queue
= NULL
;
2432 gchar
*errstr
= NULL
;
2434 if (!folderview
->selected
) return;
2435 item
= folderview_get_selected_item(folderview
);
2436 cm_return_if_fail(item
!= NULL
);
2437 cm_return_if_fail(item
->folder
!= NULL
);
2439 if (NULL
!= (ac
= account_find_from_item(item
)))
2440 special_queue
= account_get_special_folder(ac
, F_QUEUE
);
2442 if (item
!= item
->folder
->queue
&& item
!= special_queue
2443 && !folder_has_parent_of_type(item
, F_QUEUE
)) return;
2445 if (procmsg_queue_is_empty(item
))
2448 if (prefs_common
.work_offline
)
2449 if (alertpanel(_("Offline warning"),
2450 _("You're working offline. Override?"),
2451 GTK_STOCK_NO
, GTK_STOCK_YES
,
2452 NULL
) != G_ALERTALTERNATE
)
2455 /* ask for confirmation before sending queued messages only
2456 in online mode and if there is at least one message queued
2457 in any of the folder queue
2459 if (prefs_common
.confirm_send_queued_messages
) {
2460 if (!prefs_common
.work_offline
) {
2461 if (alertpanel(_("Send queued messages"),
2462 _("Send all queued messages?"),
2463 GTK_STOCK_CANCEL
, _("_Send"),
2464 NULL
) != G_ALERTALTERNATE
)
2469 if (procmsg_send_queue(item
, prefs_common
.savemsg
, &errstr
) < 0) {
2471 alertpanel_error_log(_("Some errors occurred while "
2472 "sending queued messages."));
2474 alertpanel_error_log(_("Some errors occurred "
2475 "while sending queued messages:\n%s"), errstr
);
2481 static void folderview_search_cb(GtkAction
*action
, gpointer data
)
2483 FolderView
*folderview
= (FolderView
*)data
;
2484 summary_search(folderview
->summaryview
);
2487 static void folderview_run_processing_cb(GtkAction
*action
, gpointer data
)
2489 FolderView
*folderview
= (FolderView
*)data
;
2492 if (!folderview
->selected
) return;
2494 item
= folderview_get_selected_item(folderview
);
2495 cm_return_if_fail(item
!= NULL
);
2496 cm_return_if_fail(item
->folder
!= NULL
);
2498 item
->processing_pending
= TRUE
;
2499 folder_item_apply_processing(item
);
2500 item
->processing_pending
= FALSE
;
2503 static void folderview_property_cb(GtkAction
*action
, gpointer data
)
2505 FolderView
*folderview
= (FolderView
*)data
;
2508 if (!folderview
->selected
) return;
2510 item
= folderview_get_selected_item(folderview
);
2511 cm_return_if_fail(item
!= NULL
);
2512 cm_return_if_fail(item
->folder
!= NULL
);
2514 prefs_folder_item_open(item
);
2517 static void folderview_recollapse_nodes(FolderView
*folderview
, GtkCMCTreeNode
*node
)
2519 GSList
*list
= NULL
;
2520 GSList
*done
= NULL
;
2521 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
2523 for (list
= folderview
->nodes_to_recollapse
; list
!= NULL
; list
= g_slist_next(list
)) {
2524 if (!gtkut_ctree_node_is_parent(GTK_CMCTREE_NODE(list
->data
), node
)
2525 && list
->data
!= node
) {
2526 gtk_cmctree_collapse(ctree
, GTK_CMCTREE_NODE(list
->data
));
2527 done
= g_slist_append(done
, GTK_CMCTREE_NODE(list
->data
));
2530 for (list
= done
; list
!= NULL
; list
= g_slist_next(list
)) {
2531 folderview
->nodes_to_recollapse
= g_slist_remove(folderview
->nodes_to_recollapse
,
2537 void folderview_move_folder(FolderView
*folderview
, FolderItem
*from_folder
,
2538 FolderItem
*to_folder
, gboolean copy
)
2540 FolderItem
*new_folder
= NULL
;
2544 cm_return_if_fail(folderview
!= NULL
);
2545 cm_return_if_fail(from_folder
!= NULL
);
2546 cm_return_if_fail(to_folder
!= NULL
);
2548 if (prefs_common
.warn_dnd
) {
2549 buf
= g_strdup_printf(copy
? _("Do you really want to copy folder '%s' in '%s'?"):
2550 _("Do you really want to make folder '%s' a subfolder of '%s'?"),
2551 from_folder
->name
, to_folder
->name
);
2552 status
= alertpanel_full(copy
? _("Copy folder"):_("Move folder"), buf
,
2553 GTK_STOCK_NO
, GTK_STOCK_YES
, NULL
, TRUE
,
2554 NULL
, ALERT_QUESTION
, G_ALERTDEFAULT
);
2557 if ((status
& ~G_ALERTDISABLE
) != G_ALERTALTERNATE
)
2559 else if (status
& G_ALERTDISABLE
)
2560 prefs_common
.warn_dnd
= FALSE
;
2563 buf
= g_strdup_printf(copy
? _("Copying %s to %s..."):_("Moving %s to %s..."),
2564 from_folder
->name
, to_folder
->name
);
2565 STATUSBAR_PUSH(folderview
->mainwin
, buf
);
2567 summary_clear_all(folderview
->summaryview
);
2568 folderview
->opened
= NULL
;
2569 folderview
->selected
= NULL
;
2570 gtk_widget_set_sensitive(GTK_WIDGET(folderview
->ctree
), FALSE
);
2572 main_window_cursor_wait(folderview
->mainwin
);
2574 statusbar_verbosity_set(FALSE
);
2575 folder_item_update_freeze();
2576 gtk_cmclist_freeze(GTK_CMCLIST(folderview
->ctree
));
2577 if ((status
= folder_item_move_to(from_folder
, to_folder
, &new_folder
, copy
)) == F_MOVE_OK
) {
2578 statusbar_verbosity_set(FALSE
);
2579 main_window_cursor_normal(folderview
->mainwin
);
2580 STATUSBAR_POP(folderview
->mainwin
);
2581 folder_item_update_thaw();
2582 folder_item_update_recursive(new_folder
, F_ITEM_UPDATE_MSGCNT
);
2584 folderview_sort_folders(folderview
,
2585 gtk_cmctree_find_by_row_data(GTK_CMCTREE(folderview
->ctree
),
2586 NULL
, to_folder
), new_folder
->folder
);
2587 folderview_select(folderview
, new_folder
);
2588 gtk_cmclist_thaw(GTK_CMCLIST(folderview
->ctree
));
2590 statusbar_verbosity_set(FALSE
);
2591 main_window_cursor_normal(folderview
->mainwin
);
2592 STATUSBAR_POP(folderview
->mainwin
);
2593 gtk_cmclist_thaw(GTK_CMCLIST(folderview
->ctree
));
2594 folder_item_update_thaw();
2596 case F_MOVE_FAILED_DEST_IS_PARENT
:
2597 alertpanel_error(_("Source and destination are the same."));
2599 case F_MOVE_FAILED_DEST_IS_CHILD
:
2600 alertpanel_error(copy
? _("Can't copy a folder to one of its children."):
2601 _("Can't move a folder to one of its children."));
2603 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX
:
2604 alertpanel_error(_("A folder cannot be moved between different mailboxes."));
2607 alertpanel_error(copy
? _("Copy failed!"):_("Move failed!"));
2612 gtk_widget_set_sensitive(GTK_WIDGET(folderview
->ctree
), TRUE
);
2615 static gint
folderview_clist_compare(GtkCMCList
*clist
,
2616 gconstpointer ptr1
, gconstpointer ptr2
)
2618 FolderItem
*item1
= ((GtkCMCListRow
*)ptr1
)->data
;
2619 FolderItem
*item2
= ((GtkCMCListRow
*)ptr2
)->data
;
2621 if (item1
->order
> 0 && item2
->order
> 0) // if we have an order item, use it
2623 return item1
->order
- item2
->order
;
2626 // if only one folder has an order it comes first
2627 if (item1
->order
> 0)
2631 if (item2
->order
> 0)
2637 return (item2
->name
!= NULL
);
2641 return g_utf8_collate(item1
->name
, item2
->name
);
2644 static void folderview_processing_cb(GtkAction
*action
, gpointer data
)
2646 FolderView
*folderview
= (FolderView
*)data
;
2650 if (!folderview
->selected
) return;
2652 item
= folderview_get_selected_item(folderview
);
2653 cm_return_if_fail(item
!= NULL
);
2654 cm_return_if_fail(item
->folder
!= NULL
);
2656 id
= folder_item_get_identifier(item
);
2657 title
= g_strdup_printf (_("Processing configuration for folder %s"), id
);
2660 prefs_filtering_open(&item
->prefs
->processing
, title
,
2661 MANUAL_ANCHOR_PROCESSING
, NULL
, NULL
, FALSE
);
2665 void folderview_set_target_folder_color(gint color_op
)
2669 FolderView
*folderview
;
2671 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
) {
2672 folderview
= (FolderView
*)list
->data
;
2673 gtkut_convert_int_to_gdk_color(color_op
, &folderview
->color_op
);
2675 bold_tgtfold_style
->fg
[GTK_STATE_NORMAL
] =
2676 folderview
->color_op
;
2682 static gchar
*last_smallfont
= NULL
;
2683 static gchar
*last_normalfont
= NULL
;
2684 static gchar
*last_boldfont
= NULL
;
2685 static gboolean last_derive
= 0;
2687 void folderview_reinit_fonts(FolderView
*folderview
)
2690 g_free(last_smallfont
);
2691 last_smallfont
= NULL
;
2692 g_free(last_normalfont
);
2693 last_normalfont
= NULL
;
2694 g_free(last_boldfont
);
2695 last_boldfont
= NULL
;
2698 void folderview_reflect_prefs(void)
2700 gboolean update_font
= FALSE
;
2701 FolderView
*folderview
= mainwindow_get_mainwindow()->folderview
;
2702 FolderItem
*item
= folderview_get_selected_item(folderview
);
2703 GtkAdjustment
*pos
= gtk_scrolled_window_get_vadjustment(
2704 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
2705 gint height
= gtk_adjustment_get_value(pos
);
2707 if (!last_smallfont
|| strcmp(last_smallfont
, SMALL_FONT
) ||
2708 !last_normalfont
|| strcmp(last_normalfont
, NORMAL_FONT
) ||
2709 !last_boldfont
|| strcmp(last_boldfont
, BOLD_FONT
) ||
2710 last_derive
!= prefs_common
.derive_from_normal_font
)
2716 g_free(last_smallfont
);
2717 last_smallfont
= g_strdup(SMALL_FONT
);
2718 g_free(last_normalfont
);
2719 last_normalfont
= g_strdup(NORMAL_FONT
);
2720 g_free(last_boldfont
);
2721 last_boldfont
= g_strdup(BOLD_FONT
);
2722 last_derive
= prefs_common
.derive_from_normal_font
;
2724 #define STYLE_FREE(s) \
2726 g_object_unref(s); \
2730 STYLE_FREE(normal_style
);
2731 STYLE_FREE(normal_color_style
);
2732 STYLE_FREE(bold_style
);
2733 STYLE_FREE(bold_color_style
);
2734 STYLE_FREE(bold_tgtfold_style
);
2738 folderview_init(folderview
);
2739 gtk_cmclist_freeze(GTK_CMCLIST(folderview
->ctree
));
2740 folderview_column_set_titles(folderview
);
2741 folderview_set_all();
2743 g_signal_handlers_block_by_func
2744 (G_OBJECT(folderview
->ctree
),
2745 G_CALLBACK(folderview_selected
), folderview
);
2748 GtkCMCTreeNode
*node
= gtk_cmctree_find_by_row_data(
2749 GTK_CMCTREE(folderview
->ctree
), NULL
, item
);
2751 folderview_select(folderview
, item
);
2752 folderview
->open_folder
= FALSE
;
2753 folderview
->selected
= node
;
2756 g_signal_handlers_unblock_by_func
2757 (G_OBJECT(folderview
->ctree
),
2758 G_CALLBACK(folderview_selected
), folderview
);
2760 pos
= gtk_scrolled_window_get_vadjustment(
2761 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
2762 gtk_adjustment_set_value(pos
, height
);
2763 gtk_adjustment_changed(pos
);
2764 gtk_cmclist_thaw(GTK_CMCLIST(folderview
->ctree
));
2767 static void drag_state_stop(FolderView
*folderview
)
2769 if (folderview
->drag_timer_id
)
2770 g_source_remove(folderview
->drag_timer_id
);
2771 folderview
->drag_timer_id
= 0;
2772 folderview
->drag_node
= NULL
;
2775 static gboolean
folderview_defer_expand(FolderView
*folderview
)
2777 if (folderview
->drag_node
) {
2778 folderview_recollapse_nodes(folderview
, folderview
->drag_node
);
2779 if (folderview
->drag_item
->collapsed
) {
2780 gtk_cmctree_expand(GTK_CMCTREE(folderview
->ctree
), folderview
->drag_node
);
2781 folderview
->nodes_to_recollapse
= g_slist_append
2782 (folderview
->nodes_to_recollapse
, folderview
->drag_node
);
2785 folderview
->drag_item
= NULL
;
2786 folderview
->drag_timer_id
= 0;
2790 static void drag_state_start(FolderView
*folderview
, GtkCMCTreeNode
*node
, FolderItem
*item
)
2792 /* the idea is that we call drag_state_start() whenever we want expansion to
2793 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2794 * we need to call drag_state_stop() */
2795 drag_state_stop(folderview
);
2796 /* request expansion */
2797 if (0 != (folderview
->drag_timer_id
= g_timeout_add
2798 (prefs_common
.hover_timeout
,
2799 (GSourceFunc
)folderview_defer_expand
,
2801 folderview
->drag_node
= node
;
2802 folderview
->drag_item
= item
;
2805 #ifndef GENERIC_UMPC
2806 static void folderview_start_drag(GtkWidget
*widget
, gint button
, GdkEvent
*event
,
2807 FolderView
*folderview
)
2809 GdkDragContext
*context
;
2811 cm_return_if_fail(folderview
!= NULL
);
2812 if (folderview
->selected
== NULL
) return;
2813 if (folderview
->nodes_to_recollapse
)
2814 g_slist_free(folderview
->nodes_to_recollapse
);
2815 folderview
->nodes_to_recollapse
= NULL
;
2816 context
= gtk_drag_begin(widget
, folderview
->target_list
,
2817 GDK_ACTION_MOVE
|GDK_ACTION_COPY
|GDK_ACTION_DEFAULT
, button
, event
);
2818 gtk_drag_set_icon_default(context
);
2821 static void folderview_drag_data_get(GtkWidget
*widget
,
2822 GdkDragContext
*drag_context
,
2823 GtkSelectionData
*selection_data
,
2826 FolderView
*folderview
)
2830 gchar
*source
= NULL
;
2831 if (info
== TARGET_DUMMY
) {
2832 sel
= GTK_CMCLIST(folderview
->ctree
)->selection
;
2836 item
= gtk_cmctree_node_get_row_data
2837 (GTK_CMCTREE(folderview
->ctree
),
2838 GTK_CMCTREE_NODE(sel
->data
));
2840 source
= g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item
));
2841 gtk_selection_data_set(selection_data
,
2842 gtk_selection_data_get_target(selection_data
), 8,
2843 source
, strlen(source
));
2846 g_warning("unknown info %d", info
);
2850 static gboolean
folderview_update_folder(gpointer source
, gpointer userdata
)
2852 FolderUpdateData
*hookdata
;
2853 FolderView
*folderview
;
2857 folderview
= (FolderView
*) userdata
;
2858 cm_return_val_if_fail(hookdata
!= NULL
, FALSE
);
2859 cm_return_val_if_fail(folderview
!= NULL
, FALSE
);
2861 ctree
= folderview
->ctree
;
2862 cm_return_val_if_fail(ctree
!= NULL
, FALSE
);
2864 if (hookdata
->update_flags
& FOLDER_ADD_FOLDERITEM
)
2865 folderview_create_folder_node(folderview
, hookdata
->item
);
2866 else if (hookdata
->update_flags
& FOLDER_RENAME_FOLDERITEM
) {
2867 GtkCMCTreeNode
*node
= gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree
),
2868 NULL
, folder_item_parent(hookdata
->item
));
2869 folderview_sort_folders(folderview
, node
, hookdata
->folder
);
2870 } else if (hookdata
->update_flags
& FOLDER_REMOVE_FOLDERITEM
) {
2871 GtkCMCTreeNode
*node
;
2873 node
= gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree
), NULL
, hookdata
->item
);
2875 gtk_cmctree_remove_node(GTK_CMCTREE(ctree
), node
);
2876 if (folderview
->selected
== node
)
2877 folderview
->selected
= NULL
;
2878 if (folderview
->opened
== node
)
2879 folderview
->opened
= NULL
;
2881 } else if (hookdata
->update_flags
& FOLDER_MOVE_FOLDERITEM
) {
2882 /* do nothing, it's done by the ADD and REMOVE) */
2883 } else if (hookdata
->update_flags
& (FOLDER_TREE_CHANGED
| FOLDER_ADD_FOLDER
| FOLDER_REMOVE_FOLDER
))
2884 folderview_set(folderview
);
2889 static gboolean
folderview_dnd_scroll_cb(gpointer data
)
2891 FolderView
*folderview
= (FolderView
*)data
;
2892 GtkAdjustment
*pos
= gtk_scrolled_window_get_vadjustment(
2893 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
2894 gint new_val
= (int)gtk_adjustment_get_value(pos
) + folderview
->scroll_value
;
2895 gint max
= (int)gtk_adjustment_get_upper(pos
) -
2896 (int)gtk_adjustment_get_page_size(pos
);
2898 if (folderview
->scroll_value
== 0) {
2899 folderview
->scroll_timeout_id
= 0;
2903 if (folderview
->scroll_value
> 0 && new_val
> max
) {
2905 } else if (folderview
->scroll_value
< 0 && new_val
< 0) {
2908 gtk_adjustment_set_value(pos
, new_val
);
2913 static gboolean
folderview_drag_motion_cb(GtkWidget
*widget
,
2914 GdkDragContext
*context
,
2918 FolderView
*folderview
)
2921 FolderItem
*item
= NULL
, *src_item
= NULL
;
2922 GtkCMCTreeNode
*node
= NULL
;
2923 gboolean acceptable
= FALSE
;
2924 GtkAdjustment
*pos
= gtk_scrolled_window_get_vadjustment(
2925 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
2926 int height
= (int)gtk_adjustment_get_page_size(pos
);
2927 int total_height
= (int)gtk_adjustment_get_upper(pos
);
2928 int vpos
= (int)gtk_adjustment_get_value(pos
);
2929 int offset
= prefs_common
.show_col_headers
? 24:0;
2932 if (gtk_cmclist_get_selection_info
2933 (GTK_CMCLIST(widget
), x
- offset
, y
- offset
, &row
, &column
)) {
2934 GtkWidget
*srcwidget
;
2936 if (y
> height
- (48 - offset
) && height
+ vpos
< total_height
) {
2937 dist
= -(height
- (48 - offset
) - y
);
2938 folderview
->scroll_value
= 1.41f
* (1+(dist
/ 6));
2939 } else if (y
< 72 - (24 - offset
) && y
>= 0) {
2940 dist
= 72 - (24 - offset
) - y
;
2941 folderview
->scroll_value
= -1.41f
* (1+(dist
/ 6));
2943 folderview
->scroll_value
= 0;
2945 if (folderview
->scroll_value
!= 0 && folderview
->scroll_timeout_id
== 0) {
2946 folderview
->scroll_timeout_id
=
2947 g_timeout_add(30, folderview_dnd_scroll_cb
,
2951 node
= gtk_cmctree_node_nth(GTK_CMCTREE(widget
), row
);
2952 item
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget
), node
);
2953 src_item
= folderview
->summaryview
->folder_item
;
2955 srcwidget
= gtk_drag_get_source_widget(context
);
2956 if (srcwidget
== summary_get_main_widget(folderview
->summaryview
)) {
2957 /* comes from summaryview */
2958 /* we are copying messages, so only accept folder items that are not
2959 the source item, are no root items and can copy messages */
2960 if (item
&& item
->folder
&& folder_item_parent(item
) != NULL
&& src_item
&&
2961 src_item
!= item
&& FOLDER_CLASS(item
->folder
)->copy_msg
!= NULL
&&
2962 FOLDER_TYPE(item
->folder
) != F_UNKNOWN
)
2964 } else if (srcwidget
== folderview
->ctree
) {
2965 /* comes from folderview */
2966 /* we are moving folder items, only accept folders that are not
2967 the source items and can copy messages and create folder items */
2968 if (item
&& item
->folder
&& src_item
&& src_item
!= item
&&
2969 FOLDER_CLASS(item
->folder
)->copy_msg
!= NULL
&&
2970 FOLDER_CLASS(item
->folder
)->create_folder
!= NULL
&&
2971 ((FOLDER_TYPE(item
->folder
) != F_UNKNOWN
&& FOLDER_TYPE(src_item
->folder
) != F_UNKNOWN
)
2972 || item
->folder
== src_item
->folder
))
2975 /* comes from another app */
2976 /* we are adding messages, so only accept folder items that are
2977 no root items and can copy messages */
2978 if (item
&& item
->folder
&& folder_item_parent(item
) != NULL
2979 && FOLDER_CLASS(item
->folder
)->add_msg
!= NULL
&&
2980 FOLDER_TYPE(item
->folder
) != F_UNKNOWN
)
2985 if (acceptable
|| (src_item
&& src_item
== item
))
2986 drag_state_start(folderview
, node
, item
);
2989 g_signal_handlers_block_by_func
2991 G_CALLBACK(folderview_selected
), folderview
);
2992 gtk_cmctree_select(GTK_CMCTREE(widget
), node
);
2993 g_signal_handlers_unblock_by_func
2995 G_CALLBACK(folderview_selected
), folderview
);
2996 gdk_drag_status(context
,
2997 (gdk_drag_context_get_actions(context
) == GDK_ACTION_COPY
?
2998 GDK_ACTION_COPY
: GDK_ACTION_MOVE
) , time
);
3000 if (folderview
->opened
)
3001 gtk_cmctree_select(GTK_CMCTREE(widget
), folderview
->opened
);
3002 gdk_drag_status(context
, 0, time
);
3008 static void folderview_drag_leave_cb(GtkWidget
*widget
,
3009 GdkDragContext
*context
,
3011 FolderView
*folderview
)
3013 drag_state_stop(folderview
);
3014 folderview
->scroll_value
= 0;
3015 gtk_cmctree_select(GTK_CMCTREE(widget
), folderview
->opened
);
3018 static void free_info (gpointer stuff
, gpointer data
)
3023 void folderview_finish_dnd(const gchar
*data
, GdkDragContext
*drag_context
,
3024 guint time
, FolderItem
*item
)
3027 GSList
*msglist
= NULL
;
3028 list
= uri_list_extract_filenames(data
);
3029 if (!(item
&& item
->folder
&& folder_item_parent(item
) != NULL
3030 && FOLDER_CLASS(item
->folder
)->add_msg
!= NULL
))
3032 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3033 debug_print("item doesn't fit\n");
3037 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3038 debug_print("list is empty\n");
3041 for (tmp
= list
; tmp
!= NULL
; tmp
= tmp
->next
) {
3042 MsgFileInfo
*info
= NULL
;
3044 if (file_is_email((gchar
*)tmp
->data
)) {
3045 info
= g_new0(MsgFileInfo
, 1);
3046 info
->msginfo
= NULL
;
3047 info
->file
= (gchar
*)tmp
->data
;
3048 msglist
= g_slist_prepend(msglist
, info
);
3049 debug_print("file is a mail\n");
3051 debug_print("file isn't a mail\n");
3055 msglist
= g_slist_reverse(msglist
);
3056 folder_item_add_msgs(item
, msglist
, FALSE
);
3057 g_slist_foreach(msglist
, free_info
, NULL
);
3058 g_slist_free(msglist
);
3059 gtk_drag_finish(drag_context
, TRUE
, FALSE
, time
);
3061 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3063 list_free_strings(list
);
3067 static void folderview_drag_received_cb(GtkWidget
*widget
,
3068 GdkDragContext
*drag_context
,
3071 GtkSelectionData
*data
,
3074 FolderView
*folderview
)
3077 FolderItem
*item
= NULL
, *src_item
;
3078 GtkCMCTreeNode
*node
;
3079 int offset
= prefs_common
.show_col_headers
? 24:0;
3081 folderview
->scroll_value
= 0;
3083 if (info
== TARGET_DUMMY
) {
3084 drag_state_stop(folderview
);
3085 const gchar
*ddata
= (const gchar
*)gtk_selection_data_get_data(data
);
3086 if ((gchar
*)strstr(ddata
, "FROM_OTHER_FOLDER") != ddata
) {
3087 /* comes from summaryview */
3088 if (gtk_cmclist_get_selection_info
3089 (GTK_CMCLIST(widget
), x
- offset
, y
- offset
, &row
, &column
) == 0)
3092 node
= gtk_cmctree_node_nth(GTK_CMCTREE(widget
), row
);
3093 item
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget
), node
);
3094 src_item
= folderview
->summaryview
->folder_item
;
3096 if (item
->no_select
) {
3097 alertpanel_error(_("The destination folder can only be used to "
3098 "store subfolders."));
3101 /* re-check (due to acceptable possibly set for folder moves */
3102 if (!(item
&& item
->folder
&& item
->path
&& !item
->no_select
&&
3103 src_item
&& src_item
!= item
&& FOLDER_CLASS(item
->folder
)->copy_msg
!= NULL
)) {
3106 if (item
&& src_item
) {
3107 switch (gdk_drag_context_get_selected_action(drag_context
)) {
3108 case GDK_ACTION_COPY
:
3109 summary_copy_selected_to(folderview
->summaryview
, item
);
3110 gtk_drag_finish(drag_context
, TRUE
, FALSE
, time
);
3112 case GDK_ACTION_MOVE
:
3113 case GDK_ACTION_DEFAULT
:
3115 if (FOLDER_CLASS(src_item
->folder
)->remove_msg
== NULL
)
3116 summary_copy_selected_to(folderview
->summaryview
, item
);
3118 summary_move_selected_to(folderview
->summaryview
, item
);
3119 gtk_drag_finish(drag_context
, TRUE
, TRUE
, time
);
3122 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3124 /* comes from folderview */
3126 gboolean folder_is_normal
= TRUE
;
3127 gboolean copy
= (GDK_ACTION_COPY
==
3128 gdk_drag_context_get_selected_action(drag_context
));
3130 source
= (char *)gtk_selection_data_get_data(data
) + 17;
3131 if (gtk_cmclist_get_selection_info
3132 (GTK_CMCLIST(widget
), x
- offset
, y
- offset
, &row
, &column
) == 0
3134 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3137 node
= gtk_cmctree_node_nth(GTK_CMCTREE(widget
), row
);
3138 item
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget
), node
);
3139 src_item
= folder_find_item_from_identifier(source
);
3143 src_item
->stype
== F_NORMAL
&&
3144 !folder_has_parent_of_type(src_item
, F_OUTBOX
) &&
3145 !folder_has_parent_of_type(src_item
, F_DRAFT
) &&
3146 !folder_has_parent_of_type(src_item
, F_QUEUE
) &&
3147 !folder_has_parent_of_type(src_item
, F_TRASH
);
3148 if (!item
|| !src_item
|| !folder_is_normal
) {
3149 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3153 folderview_move_folder(folderview
, src_item
, item
, copy
);
3154 gtk_drag_finish(drag_context
, TRUE
, TRUE
, time
);
3156 folderview
->nodes_to_recollapse
= NULL
;
3157 } else if (info
== TARGET_MAIL_URI_LIST
) {
3158 if (gtk_cmclist_get_selection_info
3159 (GTK_CMCLIST(widget
), x
- offset
, y
- offset
, &row
, &column
) == 0)
3162 node
= gtk_cmctree_node_nth(GTK_CMCTREE(widget
), row
);
3164 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3165 debug_print("no node\n");
3168 item
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget
), node
);
3170 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3171 debug_print("no item\n");
3174 folderview_finish_dnd(gtk_selection_data_get_data(data
),
3175 drag_context
, time
, item
);
3179 static void folderview_drag_end_cb(GtkWidget
*widget
,
3180 GdkDragContext
*drag_context
,
3181 FolderView
*folderview
)
3183 drag_state_stop(folderview
);
3184 folderview
->scroll_value
= 0;
3185 g_slist_free(folderview
->nodes_to_recollapse
);
3186 folderview
->nodes_to_recollapse
= NULL
;
3189 void folderview_register_popup(FolderViewPopup
*fpopup
)
3193 for (folderviews
= folderview_list
; folderviews
!= NULL
; folderviews
= g_list_next(folderviews
)) {
3194 FolderView
*folderview
= folderviews
->data
;
3195 GtkActionGroup
*factory
;
3197 factory
= create_action_group(folderview
, fpopup
);
3198 g_hash_table_insert(folderview
->popups
, fpopup
->klass
, factory
);
3200 g_hash_table_insert(folderview_popups
, fpopup
->klass
, fpopup
);
3203 void folderview_unregister_popup(FolderViewPopup
*fpopup
)
3208 for (folderviews
= folderview_list
; folderviews
!= NULL
; folderviews
= g_list_next(folderviews
)) {
3209 FolderView
*folderview
= folderviews
->data
;
3211 g_hash_table_remove(folderview
->popups
, fpopup
->klass
);
3213 g_hash_table_remove(folderview_popups
, fpopup
->klass
);
3216 void folderview_remove_item(FolderView
*folderview
, FolderItem
*item
)
3218 g_return_if_fail(folderview
!= NULL
);
3219 g_return_if_fail(item
!= NULL
);
3221 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
3222 g_return_if_fail(ctree
!= NULL
);
3224 GtkCMCTreeNode
*node
=
3225 gtk_cmctree_find_by_row_data(ctree
, NULL
, item
);
3226 g_return_if_fail(node
!= NULL
);
3228 gtk_cmctree_remove_node(ctree
, node
);
3231 void folderview_freeze(FolderView
*folderview
)
3234 gtk_cmclist_freeze(GTK_CMCLIST(folderview
->ctree
));
3237 void folderview_thaw(FolderView
*folderview
)
3240 gtk_cmclist_thaw(GTK_CMCLIST(folderview
->ctree
));
3243 void folderview_grab_focus(FolderView
*folderview
)
3246 gtk_widget_grab_focus(folderview
->ctree
);