2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2023 the Claws Mail team and Hiroyuki Yamamoto
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include <glib/gi18n.h>
24 #include <gdk/gdkkeysyms.h>
31 #include "mainwindow.h"
32 #include "folderview.h"
33 #include "summaryview.h"
34 #include "summary_search.h"
35 #include "inputdialog.h"
36 #include "manage_window.h"
37 #include "alertpanel.h"
39 #include "stock_pixmap.h"
43 #include "prefs_common.h"
44 #include "prefs_account.h"
45 #include "prefs_filtering.h"
46 #include "prefs_folder_item.h"
49 #include "foldersel.h"
51 #include "statusbar.h"
53 #include "folderutils.h"
54 #include "partial_download.h"
55 #include "prefs_folder_column.h"
56 #include "filtering.h"
57 #include "quicksearch.h"
61 #include "gtkcmctree.h"
63 #define COL_FOLDER_WIDTH 150
64 #define COL_NUM_WIDTH 32
66 static GList
*folderview_list
= NULL
;
68 static GtkStyle
*bold_style
;
70 static GdkPixbuf
*inboxxpm
;
71 static GdkPixbuf
*inboxhrmxpm
;
72 static GdkPixbuf
*inboxopenxpm
;
73 static GdkPixbuf
*inboxopenhrmxpm
;
74 static GdkPixbuf
*outboxxpm
;
75 static GdkPixbuf
*outboxhrmxpm
;
76 static GdkPixbuf
*outboxopenxpm
;
77 static GdkPixbuf
*outboxopenhrmxpm
;
78 static GdkPixbuf
*folderxpm
;
79 static GdkPixbuf
*folderhrmxpm
;
80 static GdkPixbuf
*folderopenxpm
;
81 static GdkPixbuf
*folderopenhrmxpm
;
82 static GdkPixbuf
*trashopenxpm
;
83 static GdkPixbuf
*trashopenhrmxpm
;
84 static GdkPixbuf
*trashxpm
;
85 static GdkPixbuf
*trashhrmxpm
;
86 static GdkPixbuf
*queuexpm
;
87 static GdkPixbuf
*queuehrmxpm
;
88 static GdkPixbuf
*queueopenxpm
;
89 static GdkPixbuf
*queueopenhrmxpm
;
90 static GdkPixbuf
*draftsxpm
;
91 static GdkPixbuf
*draftsopenxpm
;
92 static GdkPixbuf
*foldersubsxpm
;
93 static GdkPixbuf
*foldersubsopenxpm
;
94 static GdkPixbuf
*foldernoselectxpm
;
95 static GdkPixbuf
*foldernoselectopenxpm
;
97 static GdkPixbuf
*m_inboxxpm
;
98 static GdkPixbuf
*m_inboxhrmxpm
;
99 static GdkPixbuf
*m_inboxopenxpm
;
100 static GdkPixbuf
*m_inboxopenhrmxpm
;
101 static GdkPixbuf
*m_outboxxpm
;
102 static GdkPixbuf
*m_outboxhrmxpm
;
103 static GdkPixbuf
*m_outboxopenxpm
;
104 static GdkPixbuf
*m_outboxopenhrmxpm
;
105 static GdkPixbuf
*m_folderxpm
;
106 static GdkPixbuf
*m_folderhrmxpm
;
107 static GdkPixbuf
*m_folderopenxpm
;
108 static GdkPixbuf
*m_folderopenhrmxpm
;
109 static GdkPixbuf
*m_trashopenxpm
;
110 static GdkPixbuf
*m_trashopenhrmxpm
;
111 static GdkPixbuf
*m_trashxpm
;
112 static GdkPixbuf
*m_trashhrmxpm
;
113 static GdkPixbuf
*m_queuexpm
;
114 static GdkPixbuf
*m_queuehrmxpm
;
115 static GdkPixbuf
*m_queueopenxpm
;
116 static GdkPixbuf
*m_queueopenhrmxpm
;
117 static GdkPixbuf
*m_draftsxpm
;
118 static GdkPixbuf
*m_draftsopenxpm
;
119 static GdkPixbuf
*m_foldersubsxpm
;
120 static GdkPixbuf
*m_foldernoselectxpm
;
122 static GdkPixbuf
*newxpm
;
123 static GdkPixbuf
*unreadxpm
;
124 static GdkPixbuf
*readxpm
;
126 static void folderview_select_node (FolderView
*folderview
,
127 GtkCMCTreeNode
*node
);
128 static void folderview_set_folders (FolderView
*folderview
);
129 static void folderview_sort_folders (FolderView
*folderview
,
130 GtkCMCTreeNode
*root
,
132 static void folderview_append_folder (FolderView
*folderview
,
134 static void folderview_update_node (FolderView
*folderview
,
135 GtkCMCTreeNode
*node
);
137 static gint
folderview_clist_compare (GtkCMCList
*clist
,
141 /* callback functions */
142 static gboolean
folderview_button_pressed (GtkWidget
*ctree
,
143 GdkEventButton
*event
,
144 FolderView
*folderview
);
145 static gboolean
folderview_button_released (GtkWidget
*ctree
,
146 GdkEventButton
*event
,
147 FolderView
*folderview
);
148 static gboolean
folderview_key_pressed (GtkWidget
*widget
,
150 FolderView
*folderview
);
151 static void folderview_selected (GtkCMCTree
*ctree
,
154 FolderView
*folderview
);
155 static void folderview_tree_expanded (GtkCMCTree
*ctree
,
156 GtkCMCTreeNode
*node
,
157 FolderView
*folderview
);
158 static void folderview_tree_collapsed (GtkCMCTree
*ctree
,
159 GtkCMCTreeNode
*node
,
160 FolderView
*folderview
);
161 static void folderview_popup_close (GtkMenuShell
*menu_shell
,
162 FolderView
*folderview
);
163 static void folderview_col_resized (GtkCMCList
*clist
,
166 FolderView
*folderview
);
168 static void mark_all_read_unread_handler (GtkAction
*action
,
173 static void mark_all_read_cb (GtkAction
*action
,
175 static void mark_all_unread_cb (GtkAction
*action
,
177 static void mark_all_read_recursive_cb (GtkAction
*action
,
179 static void mark_all_unread_recursive_cb (GtkAction
*action
,
182 static void folderview_empty_trash_cb (GtkAction
*action
,
185 static void folderview_send_queue_cb (GtkAction
*action
,
188 static void folderview_search_cb (GtkAction
*action
,
190 static void folderview_run_processing_cb(GtkAction
*action
,
192 static void folderview_startup_folder_cb(GtkAction
*action
,
195 static void folderview_property_cb (GtkAction
*action
,
198 static gboolean
folderview_drag_motion_cb(GtkWidget
*widget
,
199 GdkDragContext
*context
,
203 FolderView
*folderview
);
204 static void folderview_drag_leave_cb (GtkWidget
*widget
,
205 GdkDragContext
*context
,
207 FolderView
*folderview
);
208 static void folderview_drag_received_cb (GtkWidget
*widget
,
209 GdkDragContext
*drag_context
,
212 GtkSelectionData
*data
,
215 FolderView
*folderview
);
217 static void folderview_start_drag (GtkWidget
*widget
, gint button
, GdkEvent
*event
,
218 FolderView
*folderview
);
220 static void folderview_drag_data_get (GtkWidget
*widget
,
221 GdkDragContext
*drag_context
,
222 GtkSelectionData
*selection_data
,
225 FolderView
*folderview
);
226 static void folderview_drag_end_cb (GtkWidget
*widget
,
227 GdkDragContext
*drag_context
,
228 FolderView
*folderview
);
230 static void folderview_create_folder_node (FolderView
*folderview
,
232 static gboolean
folderview_update_folder (gpointer source
,
234 static gboolean
folderview_update_item_claws (gpointer source
,
236 static void folderview_processing_cb(GtkAction
*action
, gpointer data
);
237 static void folderview_set_sens_and_popup_menu(FolderView
*folderview
, gint row
,
238 GdkEventButton
*event
);
239 static void folderview_header_set_displayed_columns_cb(GtkAction
*gaction
,
241 static gboolean
folderview_header_button_pressed(GtkWidget
*widget
,
245 GHashTable
*folderview_popups
;
247 static GtkActionEntry folderview_common_popup_entries
[] =
249 {"FolderViewPopup", NULL
, "FolderViewPopup", NULL
, NULL
, NULL
},
250 {"FolderViewPopup/MarkAllRead", NULL
, N_("Mark all re_ad"), NULL
, NULL
, G_CALLBACK(mark_all_read_cb
) },
251 {"FolderViewPopup/MarkAllUnread", NULL
, N_("Mark all u_nread"), NULL
, NULL
, G_CALLBACK(mark_all_unread_cb
) },
252 {"FolderViewPopup/MarkAllReadRec", NULL
, N_("Mark all read recursi_vely"), NULL
, NULL
, G_CALLBACK(mark_all_read_recursive_cb
) },
253 {"FolderViewPopup/MarkAllUnreadRec", NULL
, N_("Mark all unread recursi_vely"), NULL
, NULL
, G_CALLBACK(mark_all_unread_recursive_cb
) },
254 {"FolderViewPopup/---", NULL
, "---", NULL
, NULL
, NULL
},
255 {"FolderViewPopup/RunProcessing", NULL
, N_("R_un processing rules"), NULL
, NULL
, G_CALLBACK(folderview_run_processing_cb
) },
256 {"FolderViewPopup/SearchFolder", NULL
, N_("_Search folder..."), NULL
, NULL
, G_CALLBACK(folderview_search_cb
) },
257 {"FolderViewPopup/OpenFolder", NULL
, N_("Open on start-up"), NULL
, NULL
, G_CALLBACK(folderview_startup_folder_cb
) },
258 {"FolderViewPopup/Properties", NULL
, N_("_Properties..."), NULL
, NULL
, G_CALLBACK(folderview_property_cb
) },
259 {"FolderViewPopup/Processing", NULL
, N_("Process_ing..."), NULL
, NULL
, G_CALLBACK(folderview_processing_cb
) },
260 {"FolderViewPopup/EmptyTrash", NULL
, N_("Empty _trash..."), NULL
, NULL
, G_CALLBACK(folderview_empty_trash_cb
) },
261 {"FolderViewPopup/SendQueue", NULL
, N_("Send _queue..."), NULL
, NULL
, G_CALLBACK(folderview_send_queue_cb
) },
265 static GtkActionEntry folderview_header_popup_entries
[] =
267 {"FolderViewHeaderPopup", NULL
, "FolderViewHeaderPopup", NULL
, NULL
, NULL
},
268 {"FolderViewHeaderPopup/SetDisplayedColumns", NULL
, N_("Set Displayed columns"), NULL
, NULL
, G_CALLBACK(folderview_header_set_displayed_columns_cb
) }
271 GtkTargetEntry folderview_drag_types
[] =
273 {"claws-mail/internal", GTK_TARGET_SAME_APP
, TARGET_DUMMY
},
274 {"text/uri-list", 0, TARGET_MAIL_URI_LIST
}
277 void folderview_initialize(void)
279 FolderViewPopup
*fpopup
;
281 fpopup
= g_new0(FolderViewPopup
, 1);
283 fpopup
->klass
= "common";
284 fpopup
->path
= "<CommonFolder>";
285 fpopup
->entries
= folderview_common_popup_entries
;
286 fpopup
->n_entries
= G_N_ELEMENTS(folderview_common_popup_entries
);
287 fpopup
->set_sensitivity
= NULL
;
289 folderview_popups
= g_hash_table_new(g_str_hash
, g_str_equal
);
290 g_hash_table_insert(folderview_popups
, "common", fpopup
);
293 static GtkActionGroup
*create_action_group(FolderView
*folderview
, FolderViewPopup
*fpopup
)
295 FolderViewPopup
*fpopup_common
;
296 GtkActionGroup
*action_group
;
298 action_group
= cm_menu_create_action_group(
300 fpopup
->entries
, fpopup
->n_entries
,
301 (gpointer
)folderview
);
303 if (fpopup
->toggle_entries
)
304 gtk_action_group_add_toggle_actions(action_group
, fpopup
->toggle_entries
,
305 fpopup
->n_toggle_entries
,
306 (gpointer
)folderview
);
307 if (fpopup
->radio_entries
)
308 gtk_action_group_add_radio_actions(action_group
, fpopup
->radio_entries
,
309 fpopup
->n_radio_entries
, fpopup
->radio_default
,
310 G_CALLBACK(fpopup
->radio_callback
),
311 (gpointer
)folderview
);
313 fpopup_common
= g_hash_table_lookup(folderview_popups
, "common");
314 if (fpopup_common
!= fpopup
) {
315 gtk_action_group_add_actions(action_group
, fpopup_common
->entries
,
316 fpopup_common
->n_entries
,
317 (gpointer
)folderview
);
318 if (fpopup_common
->toggle_entries
)
319 gtk_action_group_add_toggle_actions(action_group
, fpopup_common
->toggle_entries
,
320 fpopup_common
->n_toggle_entries
,
321 (gpointer
)folderview
);
322 if (fpopup_common
->radio_entries
)
323 gtk_action_group_add_radio_actions(action_group
, fpopup_common
->radio_entries
,
324 fpopup_common
->n_radio_entries
, fpopup_common
->radio_default
,
325 G_CALLBACK(fpopup_common
->radio_callback
),
326 (gpointer
)folderview
);
332 static void create_action_groups(gpointer key
, gpointer value
, gpointer data
)
334 FolderView
*folderview
= data
;
335 FolderViewPopup
*fpopup
= value
;
336 GtkActionGroup
*group
;
338 group
= create_action_group(folderview
, fpopup
);
339 g_hash_table_insert(folderview
->popups
, fpopup
->klass
, group
);
342 static void folderview_column_set_titles(FolderView
*folderview
)
344 GtkWidget
*ctree
= folderview
->ctree
;
345 GtkWidget
*label_folder
;
346 GtkWidget
*label_new
;
347 GtkWidget
*label_unread
;
348 GtkWidget
*label_total
;
349 GtkWidget
*hbox_folder
;
351 GtkWidget
*hbox_unread
;
352 GtkWidget
*hbox_total
;
353 gint
*col_pos
= folderview
->col_pos
;
355 debug_print("setting titles...\n");
356 gtk_widget_realize(folderview
->ctree
);
357 gtk_widget_show_all(folderview
->scrolledwin
);
359 /* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
360 * instead text (text overflows making them unreadable and ugly) */
361 stock_pixbuf_gdk(STOCK_PIXMAP_NEW
, &newxpm
);
362 stock_pixbuf_gdk(STOCK_PIXMAP_UNREAD
, &unreadxpm
);
363 stock_pixbuf_gdk(STOCK_PIXMAP_READ
, &readxpm
);
365 label_folder
= gtk_label_new(_("Folder"));
366 label_new
= gtk_image_new_from_pixbuf(newxpm
);
367 label_unread
= gtk_image_new_from_pixbuf(unreadxpm
);
368 label_total
= gtk_image_new_from_pixbuf(readxpm
);
370 gtk_cmclist_column_titles_active(GTK_CMCLIST(ctree
));
372 hbox_folder
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 4);
373 hbox_new
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 4);
374 hbox_unread
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 4);
375 hbox_total
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 4);
378 gtk_box_pack_start(GTK_BOX(hbox_folder
), label_folder
, TRUE
, TRUE
, 0);
379 gtk_widget_set_halign(label_folder
, GTK_ALIGN_START
);
380 gtk_box_pack_start(GTK_BOX(hbox_new
), label_new
, TRUE
, TRUE
, 0);
381 gtk_widget_set_halign(label_new
, GTK_ALIGN_END
);
382 gtk_box_pack_start(GTK_BOX(hbox_unread
), label_unread
, TRUE
, TRUE
, 0);
383 gtk_widget_set_halign(label_unread
, GTK_ALIGN_END
);
384 gtk_box_pack_start(GTK_BOX(hbox_total
), label_total
, TRUE
, TRUE
, 0);
385 gtk_widget_set_halign(label_total
, GTK_ALIGN_END
);
387 gtk_widget_show_all(hbox_folder
);
388 gtk_widget_show_all(hbox_new
);
389 gtk_widget_show_all(hbox_unread
);
390 gtk_widget_show_all(hbox_total
);
393 gtk_widget_set_size_request(hbox_new
, -1, 20);
394 gtk_widget_set_size_request(hbox_unread
, -1, 20);
395 gtk_widget_set_size_request(hbox_total
, -1, 20);
398 gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree
),col_pos
[F_COL_FOLDER
],hbox_folder
);
399 gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree
),col_pos
[F_COL_NEW
],hbox_new
);
400 gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree
),col_pos
[F_COL_UNREAD
],hbox_unread
);
401 gtk_cmclist_set_column_widget(GTK_CMCLIST(ctree
),col_pos
[F_COL_TOTAL
],hbox_total
);
407 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree
), col_pos
[F_COL_NEW
], _("New"));
408 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree
), col_pos
[F_COL_UNREAD
], _("Unread"));
409 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree
), col_pos
[F_COL_TOTAL
], _("Total"));
412 static gboolean
folderview_popup_menu(GtkWidget
*widget
, gpointer data
)
414 FolderView
*folderview
= (FolderView
*)data
;
415 GdkEventButton event
;
416 if (folderview_get_selected_item(folderview
) == NULL
)
420 event
.time
= gtk_get_current_event_time();
422 folderview_set_sens_and_popup_menu(folderview
, -1,
429 static GtkWidget
*folderview_ctree_create(FolderView
*folderview
)
433 FolderColumnState
*col_state
;
434 FolderColumnType type
;
435 gchar
*titles
[N_FOLDER_COLS
];
437 GtkWidget
*scrolledwin
= folderview
->scrolledwin
;
439 debug_print("creating tree...\n");
440 memset(titles
, 0, sizeof(titles
));
442 col_state
= prefs_folder_column_get_config();
443 memset(titles
, 0, sizeof(titles
));
445 col_pos
= folderview
->col_pos
;
447 for (i
= 0; i
< N_FOLDER_COLS
; i
++) {
448 folderview
->col_state
[i
] = col_state
[i
];
449 type
= col_state
[i
].type
;
453 titles
[col_pos
[F_COL_FOLDER
]] = _("Folder");
454 titles
[col_pos
[F_COL_NEW
]] = _("New");
455 titles
[col_pos
[F_COL_UNREAD
]] = _("Unread");
456 /* TRANSLATORS: This in Number sign in American style */
457 titles
[col_pos
[F_COL_TOTAL
]] = _("#");
459 ctree
= gtk_sctree_new_with_titles(N_FOLDER_COLS
, col_pos
[F_COL_FOLDER
],
462 gtk_widget_set_name(GTK_WIDGET(ctree
), "folderview_sctree");
464 if (prefs_common
.show_col_headers
== FALSE
)
465 gtk_cmclist_column_titles_hide(GTK_CMCLIST(ctree
));
468 gtk_cmclist_set_selection_mode(GTK_CMCLIST(ctree
), GTK_SELECTION_BROWSE
);
469 gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree
), col_pos
[F_COL_NEW
],
471 gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree
),
472 col_pos
[F_COL_UNREAD
],
474 gtk_cmclist_set_column_justification(GTK_CMCLIST(ctree
),
475 col_pos
[F_COL_TOTAL
],
477 gtk_cmctree_set_expander_style(GTK_CMCTREE(ctree
),
478 GTK_CMCTREE_EXPANDER_TRIANGLE
);
480 gtk_sctree_set_stripes(GTK_SCTREE(ctree
), prefs_common
.use_stripes_in_summaries
);
481 gtk_sctree_set_recursive_expand(GTK_SCTREE(ctree
), FALSE
);
483 gtk_cmctree_set_indent(GTK_CMCTREE(ctree
), CTREE_INDENT
);
484 gtk_cmclist_set_compare_func(GTK_CMCLIST(ctree
), folderview_clist_compare
);
486 /* don't let title buttons take key focus */
487 for (i
= 0; i
< N_FOLDER_COLS
; i
++) {
488 gtk_widget_set_can_focus(GTK_CMCLIST(ctree
)->column
[i
].button
, FALSE
);
489 gtk_cmclist_set_column_width(GTK_CMCLIST(ctree
), col_pos
[i
],
490 prefs_common
.folder_col_size
[i
]);
491 gtk_cmclist_set_column_visibility
492 (GTK_CMCLIST(ctree
), i
, col_state
[i
].visible
);
494 g_signal_connect(G_OBJECT(GTK_CMCLIST(ctree
)->column
[i
].button
),
495 "button-press-event",
496 G_CALLBACK(folderview_header_button_pressed
),
500 g_signal_connect(G_OBJECT(ctree
), "key_press_event",
501 G_CALLBACK(folderview_key_pressed
),
503 g_signal_connect(G_OBJECT(ctree
), "button_press_event",
504 G_CALLBACK(folderview_button_pressed
),
506 g_signal_connect(G_OBJECT(ctree
), "popup-menu",
507 G_CALLBACK(folderview_popup_menu
), folderview
);
508 g_signal_connect(G_OBJECT(ctree
), "button_release_event",
509 G_CALLBACK(folderview_button_released
),
511 g_signal_connect(G_OBJECT(ctree
), "tree_select_row",
512 G_CALLBACK(folderview_selected
), folderview
);
514 /* drag-n-dropping folders on maemo is impractical as this
515 * opens the folder almost everytime */
516 g_signal_connect(G_OBJECT(ctree
), "start_drag",
517 G_CALLBACK(folderview_start_drag
), folderview
);
519 g_signal_connect(G_OBJECT(ctree
), "drag_data_get",
520 G_CALLBACK(folderview_drag_data_get
),
523 g_signal_connect_after(G_OBJECT(ctree
), "tree_expand",
524 G_CALLBACK(folderview_tree_expanded
),
526 g_signal_connect_after(G_OBJECT(ctree
), "tree_collapse",
527 G_CALLBACK(folderview_tree_collapsed
),
530 g_signal_connect(G_OBJECT(ctree
), "resize_column",
531 G_CALLBACK(folderview_col_resized
),
535 gtk_drag_dest_set(ctree
, GTK_DEST_DEFAULT_ALL
& ~GTK_DEST_DEFAULT_HIGHLIGHT
,
536 folderview_drag_types
, 2,
537 GDK_ACTION_MOVE
| GDK_ACTION_COPY
| GDK_ACTION_DEFAULT
);
538 g_signal_connect(G_OBJECT(ctree
), "drag_motion",
539 G_CALLBACK(folderview_drag_motion_cb
),
541 g_signal_connect(G_OBJECT(ctree
), "drag_leave",
542 G_CALLBACK(folderview_drag_leave_cb
),
544 g_signal_connect(G_OBJECT(ctree
), "drag_data_received",
545 G_CALLBACK(folderview_drag_received_cb
),
547 g_signal_connect(G_OBJECT(ctree
), "drag_end",
548 G_CALLBACK(folderview_drag_end_cb
),
551 gtk_container_add(GTK_CONTAINER(scrolledwin
), ctree
);
556 void folderview_set_column_order(FolderView
*folderview
)
558 GtkWidget
*ctree
= folderview
->ctree
;
559 FolderItem
*item
= folderview_get_selected_item(folderview
);
560 FolderItem
*sel_item
= NULL
, *op_item
= NULL
;
561 GtkWidget
*scrolledwin
= folderview
->scrolledwin
;
563 if (folderview
->drag_timer_id
!= 0) {
564 g_source_remove(folderview
->drag_timer_id
);
565 folderview
->drag_timer_id
= 0;
567 if (folderview
->deferred_refresh_id
!= 0) {
568 g_source_remove(folderview
->deferred_refresh_id
);
569 folderview
->deferred_refresh_id
= 0;
571 if (folderview
->scroll_timeout_id
!= 0) {
572 g_source_remove(folderview
->scroll_timeout_id
);
573 folderview
->scroll_timeout_id
= 0;
575 if (folderview
->postpone_select_id
!= 0) {
576 g_source_remove(folderview
->postpone_select_id
);
577 folderview
->postpone_select_id
= 0;
580 if (folderview
->selected
)
581 sel_item
= folderview_get_selected_item(folderview
);
582 if (folderview
->opened
)
583 op_item
= folderview_get_opened_item(folderview
);
585 debug_print("recreating tree...\n");
586 gtk_widget_destroy(folderview
->ctree
);
589 folderview
->ctree
= ctree
= folderview_ctree_create(folderview
);
590 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin
),
591 GTK_CMCLIST(ctree
)->hadjustment
);
592 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin
),
593 GTK_CMCLIST(ctree
)->vadjustment
);
594 gtk_widget_show(ctree
);
597 folderview
->selected
= gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree
), NULL
, sel_item
);
599 folderview
->opened
= gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree
), NULL
, op_item
);
601 folderview_set(folderview
);
602 folderview_column_set_titles(folderview
);
604 folderview_select(folderview
,item
);
607 FolderView
*folderview_create(MainWindow
*mainwin
)
609 FolderView
*folderview
;
610 GtkWidget
*scrolledwin
;
613 debug_print("Creating folder view...\n");
614 folderview
= g_new0(FolderView
, 1);
616 scrolledwin
= gtk_scrolled_window_new(NULL
, NULL
);
617 gtk_widget_set_name(GTK_WIDGET(scrolledwin
), "folderview");
618 gtk_scrolled_window_set_policy
619 (GTK_SCROLLED_WINDOW(scrolledwin
),
620 GTK_POLICY_AUTOMATIC
,
621 prefs_common
.folderview_vscrollbar_policy
);
623 folderview
->scrolledwin
= scrolledwin
;
624 ctree
= folderview_ctree_create(folderview
);
625 gtk_cmclist_set_row_height(GTK_CMCLIST(ctree
), 0);
627 /* create popup factories */
628 folderview
->popups
= g_hash_table_new(g_str_hash
, g_str_equal
);
629 g_hash_table_foreach(folderview_popups
, create_action_groups
, folderview
);
631 gtk_action_group_add_actions(mainwin
->action_group
,
632 folderview_header_popup_entries
,
633 G_N_ELEMENTS(folderview_header_popup_entries
),
634 (gpointer
)folderview
);
636 MENUITEM_ADDUI_MANAGER(mainwin
->ui_manager
, "/Menus", "FolderViewHeaderPopup", "FolderViewHeaderPopup", GTK_UI_MANAGER_MENU
)
637 MENUITEM_ADDUI_MANAGER(mainwin
->ui_manager
, "/Menus/FolderViewHeaderPopup", "SetDisplayedColumns", "FolderViewHeaderPopup/SetDisplayedColumns", GTK_UI_MANAGER_MENUITEM
)
639 folderview
->headerpopupmenu
= gtk_menu_item_get_submenu(GTK_MENU_ITEM(
640 gtk_ui_manager_get_widget(mainwin
->ui_manager
,
641 "/Menus/FolderViewHeaderPopup") ));
643 folderview
->ctree
= ctree
;
645 folderview
->folder_update_callback_id
=
646 hooks_register_hook(FOLDER_UPDATE_HOOKLIST
, folderview_update_folder
, (gpointer
) folderview
);
647 folderview
->folder_item_update_callback_id
=
648 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST
, folderview_update_item_claws
, (gpointer
) folderview
);
650 gtk_widget_show_all(scrolledwin
);
652 folderview
->target_list
= gtk_target_list_new(folderview_drag_types
, 2);
653 folderview_list
= g_list_append(folderview_list
, folderview
);
655 folderview
->drag_timer_id
= 0;
656 folderview
->deferred_refresh_id
= 0;
657 folderview
->scroll_timeout_id
= 0;
658 folderview
->postpone_select_id
= 0;
663 static void folderview_set_fonts(FolderView
*folderview
)
665 PangoFontDescription
*font_desc
;
666 GtkWidget
*ctree
= folderview
->ctree
;
668 font_desc
= pango_font_description_from_string(NORMAL_FONT
);
670 gtk_widget_override_font(ctree
, font_desc
);
671 pango_font_description_free(font_desc
);
675 bold_style
= gtk_style_copy(gtk_widget_get_style(ctree
));
677 if (prefs_common
.derive_from_normal_font
|| !BOLD_FONT
) {
678 font_desc
= pango_font_description_from_string(NORMAL_FONT
);
680 pango_font_description_free(bold_style
->font_desc
);
681 bold_style
->font_desc
= font_desc
;
683 pango_font_description_set_weight
684 (bold_style
->font_desc
, PANGO_WEIGHT_BOLD
);
686 font_desc
= pango_font_description_from_string(BOLD_FONT
);
688 pango_font_description_free(bold_style
->font_desc
);
689 bold_style
->font_desc
= font_desc
;
695 void folderview_init(FolderView
*folderview
)
697 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE
, &inboxxpm
);
698 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE_HRM
, &inboxhrmxpm
);
699 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN
, &inboxopenxpm
);
700 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN_HRM
, &inboxopenhrmxpm
);
701 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE
, &outboxxpm
);
702 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE_HRM
, &outboxhrmxpm
);
703 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN
, &outboxopenxpm
);
704 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN_HRM
, &outboxopenhrmxpm
);
705 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE
, &folderxpm
);
706 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE_HRM
, &folderhrmxpm
);
707 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN
, &folderopenxpm
);
708 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN_HRM
, &folderopenhrmxpm
);
709 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN
, &trashopenxpm
);
710 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN_HRM
, &trashopenhrmxpm
);
711 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE
, &trashxpm
);
712 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE_HRM
, &trashhrmxpm
);
713 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE
, &queuexpm
);
714 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE_HRM
, &queuehrmxpm
);
715 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN
, &queueopenxpm
);
716 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN_HRM
, &queueopenhrmxpm
);
717 stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_CLOSE
, &draftsxpm
);
718 stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_OPEN
, &draftsopenxpm
);
719 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_SUBS_OPEN
, &foldersubsopenxpm
);
720 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_SUBS_CLOSE
, &foldersubsxpm
);
721 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_NOSELECT_OPEN
, &foldernoselectopenxpm
);
722 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_NOSELECT_CLOSE
, &foldernoselectxpm
);
724 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE_MARK
, &m_inboxxpm
);
725 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK
, &m_inboxhrmxpm
);
726 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN_MARK
, &m_inboxopenxpm
);
727 stock_pixbuf_gdk(STOCK_PIXMAP_INBOX_OPEN_HRM_MARK
, &m_inboxopenhrmxpm
);
728 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE_MARK
, &m_outboxxpm
);
729 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK
, &m_outboxhrmxpm
);
730 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN_MARK
, &m_outboxopenxpm
);
731 stock_pixbuf_gdk(STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK
, &m_outboxopenhrmxpm
);
732 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE_MARK
, &m_folderxpm
);
733 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_CLOSE_HRM_MARK
, &m_folderhrmxpm
);
734 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN_MARK
, &m_folderopenxpm
);
735 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_OPEN_HRM_MARK
, &m_folderopenhrmxpm
);
736 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN_MARK
, &m_trashopenxpm
);
737 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_OPEN_HRM_MARK
, &m_trashopenhrmxpm
);
738 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE_MARK
, &m_trashxpm
);
739 stock_pixbuf_gdk(STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK
, &m_trashhrmxpm
);
740 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE_MARK
, &m_queuexpm
);
741 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK
, &m_queuehrmxpm
);
742 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN_MARK
, &m_queueopenxpm
);
743 stock_pixbuf_gdk(STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK
, &m_queueopenhrmxpm
);
744 stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_CLOSE_MARK
, &m_draftsxpm
);
745 stock_pixbuf_gdk(STOCK_PIXMAP_DRAFTS_OPEN_MARK
, &m_draftsopenxpm
);
746 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_SUBS_CLOSE_MARK
, &m_foldersubsxpm
);
747 stock_pixbuf_gdk(STOCK_PIXMAP_DIR_NOSELECT_CLOSE_MARK
, &m_foldernoselectxpm
);
749 folderview_set_fonts(folderview
);
752 static gboolean
folderview_defer_set(gpointer data
)
754 FolderView
*folderview
= (FolderView
*)data
;
755 MainWindow
*mainwin
= folderview
->mainwin
;
759 if (mainwin
->lock_count
)
762 debug_print("doing deferred folderview_set now\n");
763 folderview_set(folderview
);
765 folderview
->deferred_refresh_id
= 0;
769 void folderview_set(FolderView
*folderview
)
771 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
772 MainWindow
*mainwin
= folderview
->mainwin
;
773 FolderItem
*sel_item
= NULL
, *op_item
= NULL
;
778 if (mainwin
->lock_count
) {
779 if (folderview
->deferred_refresh_id
== 0)
780 folderview
->deferred_refresh_id
=
781 g_timeout_add(500, folderview_defer_set
, folderview
);
782 debug_print("deferred folderview_set\n");
787 debug_print("Setting folder info...\n");
788 STATUSBAR_PUSH(mainwin
, _("Setting folder info..."));
790 main_window_cursor_wait(mainwin
);
792 if (folderview
->selected
)
793 sel_item
= folderview_get_selected_item(folderview
);
794 if (folderview
->opened
)
795 op_item
= folderview_get_opened_item(folderview
);
797 folderview
->selected
= NULL
;
798 folderview
->opened
= NULL
;
800 gtk_cmclist_freeze(GTK_CMCLIST(ctree
));
801 gtk_cmclist_clear(GTK_CMCLIST(ctree
));
803 folderview_set_folders(folderview
);
806 folderview
->selected
= gtk_cmctree_find_by_row_data(ctree
, NULL
, sel_item
);
808 folderview
->opened
= gtk_cmctree_find_by_row_data(ctree
, NULL
, op_item
);
810 gtk_cmclist_thaw(GTK_CMCLIST(ctree
));
811 main_window_cursor_normal(mainwin
);
812 STATUSBAR_POP(mainwin
);
816 void folderview_set_all(void)
820 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
)
821 folderview_set((FolderView
*)list
->data
);
824 void folderview_select(FolderView
*folderview
, FolderItem
*item
)
826 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
827 GtkCMCTreeNode
*node
;
828 GtkCMCTreeNode
*old_selected
= folderview
->selected
;
832 node
= gtk_cmctree_find_by_row_data(ctree
, NULL
, item
);
833 if (node
) folderview_select_node(folderview
, node
);
835 if (old_selected
!= node
)
836 folder_update_op_count();
839 static void mark_all_read_cb(GtkAction
*action
, gpointer data
)
841 mark_all_read_unread_handler(action
, data
, FALSE
, TRUE
);
844 static void mark_all_unread_cb(GtkAction
*action
, gpointer data
)
846 mark_all_read_unread_handler(action
, data
, FALSE
, FALSE
);
849 static void mark_all_read_recursive_cb(GtkAction
*action
, gpointer data
)
851 mark_all_read_unread_handler(action
, data
, TRUE
, TRUE
);
854 static void mark_all_unread_recursive_cb(GtkAction
*action
, gpointer data
)
856 mark_all_read_unread_handler(action
, data
, TRUE
, FALSE
);
859 static void mark_all_read_unread_handler(GtkAction
*action
, gpointer data
,
860 gboolean recursive
, gboolean read
)
862 FolderView
*folderview
= (FolderView
*)data
;
868 item
= folderview_get_selected_item(folderview
);
873 title
= _("Mark all as read");
874 message
= recursive
? _("Do you really want to mark all mails in this "
875 "folder and its subfolders as read?") :
876 _("Do you really want to mark all mails in this "
879 title
= _("Mark all as unread");
880 message
= recursive
? _("Do you really want to mark all mails in this "
881 "folder and its subfolders as unread?") :
882 _("Do you really want to mark all mails in this "
883 "folder as unread?");
885 if (prefs_common
.ask_mark_all_read
) {
886 val
= alertpanel_full(title
, message
,
887 NULL
, _("_No"), NULL
, _("_Yes"), NULL
, NULL
,
888 ALERTFOCUS_FIRST
, TRUE
, NULL
, ALERT_QUESTION
);
890 if ((val
& ~G_ALERTDISABLE
) != G_ALERTALTERNATE
)
892 else if (val
& G_ALERTDISABLE
)
893 prefs_common
.ask_mark_all_read
= FALSE
;
896 folder_item_update_freeze();
897 if (folderview
->summaryview
->folder_item
!= item
&& !recursive
)
898 summary_lock(folderview
->summaryview
);
900 summary_freeze(folderview
->summaryview
);
904 folderutils_mark_all_read_recursive(item
, TRUE
);
906 if (prefs_common
.run_processingrules_before_mark_all
)
907 folderview_run_processing(item
);
908 folderutils_mark_all_read(item
, TRUE
);
912 folderutils_mark_all_read_recursive(item
, FALSE
);
914 folderutils_mark_all_read(item
, FALSE
);
915 if (prefs_common
.run_processingrules_before_mark_all
)
916 folderview_run_processing(item
);
919 if (folderview
->summaryview
->folder_item
!= item
&& !recursive
)
920 summary_unlock(folderview
->summaryview
);
922 summary_thaw(folderview
->summaryview
);
923 folder_item_update_thaw();
926 static void folderview_select_node(FolderView
*folderview
, GtkCMCTreeNode
*node
)
928 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
930 cm_return_if_fail(node
!= NULL
);
932 if (folderview
->open_folder
) {
936 gtk_cmclist_freeze(GTK_CMCLIST(ctree
));
937 gtkut_ctree_expand_parent_all(ctree
, node
);
939 folderview
->open_folder
= TRUE
;
940 gtkut_ctree_set_focus_row(ctree
, node
);
941 gtk_cmctree_select(ctree
, node
);
942 gtk_cmclist_thaw(GTK_CMCLIST(ctree
));
943 if ((folderview
->summaryview
->folder_item
&&
944 folderview
->summaryview
->folder_item
->total_msgs
> 0) ||
945 prefs_common
.layout_mode
== SMALL_LAYOUT
)
946 summary_select_node(folderview
->summaryview
,
947 folderview
->summaryview
->selected
, OPEN_SELECTED_ON_FOLDER_OPEN
);
949 gtk_widget_grab_focus(folderview
->ctree
);
952 void folderview_unselect(FolderView
*folderview
)
954 if (folderview
->opened
&& !GTK_CMCTREE_ROW(folderview
->opened
)->children
)
956 (GTK_CMCTREE(folderview
->ctree
), folderview
->opened
);
958 folderview
->selected
= folderview
->opened
= NULL
;
961 static GtkCMCTreeNode
*folderview_find_next_with_flag(GtkCMCTree
*ctree
,
962 GtkCMCTreeNode
*node
,
968 node
= gtkut_ctree_node_next(ctree
, node
);
970 node
= GTK_CMCTREE_NODE(GTK_CMCLIST(ctree
)->row_list
);
972 for (; node
!= NULL
; node
= gtkut_ctree_node_next(ctree
, node
)) {
973 item
= gtk_cmctree_node_get_row_data(ctree
, node
);
976 if (item
->stype
== F_TRASH
|| item
->stype
== F_DRAFT
)
980 if((item
->unread_msgs
> 0) && (!item
->prefs
|| !item
->prefs
->skip_on_goto_unread_or_new
))
984 if((item
->new_msgs
> 0) && (!item
->prefs
|| !item
->prefs
->skip_on_goto_unread_or_new
))
988 if(item
->marked_msgs
> 0)
992 if(item
->total_msgs
> 0)
1001 void folderview_select_next_with_flag(FolderView
*folderview
,
1004 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
1005 GtkCMCTreeNode
*node
= NULL
;
1006 EntryAction last_summary_select_prio
= prefs_common
.summary_select_prio
[0];
1010 prefs_common
.summary_select_prio
[0] = ACTION_OLDEST_UNREAD
;
1013 prefs_common
.summary_select_prio
[0] = ACTION_OLDEST_NEW
;
1016 prefs_common
.summary_select_prio
[0] = ACTION_OLDEST_MARKED
;
1019 prefs_common
.summary_select_prio
[0] = ACTION_OLDEST_LIST
;
1023 node
= folderview_find_next_with_flag(ctree
, folderview
->opened
, flag
);
1025 folderview_select_node(folderview
, node
);
1029 if (!folderview
->opened
||
1030 folderview
->opened
== GTK_CMCTREE_NODE(GTK_CMCLIST(ctree
)->row_list
)) {
1034 /* search again from the first node */
1035 node
= folderview_find_next_with_flag(ctree
, NULL
, flag
);
1037 folderview_select_node(folderview
, node
);
1040 prefs_common
.summary_select_prio
[0] = last_summary_select_prio
;
1043 FolderItem
*folderview_get_selected_item(FolderView
*folderview
)
1045 g_return_val_if_fail(folderview
!= NULL
, NULL
);
1046 g_return_val_if_fail(folderview
->ctree
!= NULL
, NULL
);
1048 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
1050 if (!folderview
->selected
) return NULL
;
1051 return gtk_cmctree_node_get_row_data(ctree
, folderview
->selected
);
1054 FolderItem
*folderview_get_opened_item(FolderView
*folderview
)
1056 g_return_val_if_fail(folderview
!= NULL
, NULL
);
1057 g_return_val_if_fail(folderview
->ctree
!= NULL
, NULL
);
1059 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
1061 if (!folderview
->opened
) return NULL
;
1062 return gtk_cmctree_node_get_row_data(ctree
, folderview
->opened
);
1065 static void folderview_set_folders(FolderView
*folderview
)
1068 list
= folder_get_list();
1070 for (; list
!= NULL
; list
= list
->next
) {
1071 folderview_append_folder(folderview
, FOLDER(list
->data
));
1075 static gchar
*get_scan_str(FolderItem
*item
)
1078 return g_strdup_printf(_("Scanning folder %s/%s..."),
1079 item
->folder
->name
, item
->path
);
1081 return g_strdup_printf(_("Scanning folder %s..."),
1082 item
->folder
->name
);
1084 static void folderview_scan_tree_func(Folder
*folder
, FolderItem
*item
,
1088 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
) {
1089 FolderView
*folderview
= (FolderView
*)list
->data
;
1090 MainWindow
*mainwin
= folderview
->mainwin
;
1091 gchar
*str
= get_scan_str(item
);
1093 STATUSBAR_PUSH(mainwin
, str
);
1094 STATUSBAR_POP(mainwin
);
1099 void folderview_rescan_tree(Folder
*folder
, gboolean rebuild
)
1102 MainWindow
*mainwin
= mainwindow_get_mainwindow();
1103 FolderView
*folderview
= NULL
;
1104 GtkAdjustment
*pos
= NULL
;
1107 cm_return_if_fail(folder
!= NULL
);
1109 if (!folder
->klass
->scan_tree
) return;
1112 alertpanel_full(_("Rebuild folder tree"),
1113 _("Rebuilding the folder tree will remove "
1114 "local caches. Do you want to continue?"),
1115 NULL
, _("_No"), NULL
, _("_Yes"), NULL
, NULL
,
1116 ALERTFOCUS_FIRST
, FALSE
, NULL
, ALERT_WARNING
)
1117 != G_ALERTALTERNATE
) {
1123 window
= label_window_create(_("Rebuilding folder tree..."));
1125 window
= label_window_create(_("Scanning folder tree..."));
1128 folderview
= mainwin
->folderview
;
1131 pos
= gtk_scrolled_window_get_vadjustment(
1132 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
1133 height
= gtk_adjustment_get_value(pos
);
1136 folder_set_ui_func(folder
, folderview_scan_tree_func
, NULL
);
1137 folder_scan_tree(folder
, rebuild
);
1138 folder_set_ui_func(folder
, NULL
, NULL
);
1140 folderview_set_all();
1143 pos
= gtk_scrolled_window_get_vadjustment(
1144 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
1145 gtk_adjustment_set_value(pos
, height
);
1147 label_window_destroy(window
);
1151 /** folderview_check_new()
1152 * Scan and update the folder and return the
1153 * count the number of new messages since last check.
1154 * \param folder the folder to check for new messages
1155 * \return the number of new messages since last check
1157 gint
folderview_check_new(Folder
*folder
)
1161 FolderView
*folderview
;
1163 GtkCMCTreeNode
*node
;
1165 gint former_new_msgs
= 0;
1166 gint former_new
= 0, former_unread
= 0, former_total
;
1168 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
) {
1169 folderview
= (FolderView
*)list
->data
;
1170 ctree
= GTK_CMCTREE(folderview
->ctree
);
1171 folderview
->scanning_folder
= folder
;
1173 main_window_lock(folderview
->mainwin
);
1175 for (node
= GTK_CMCTREE_NODE(GTK_CMCLIST(ctree
)->row_list
);
1176 node
!= NULL
; node
= gtkut_ctree_node_next(ctree
, node
)) {
1178 item
= gtk_cmctree_node_get_row_data(ctree
, node
);
1179 if (!item
|| !item
->path
|| !item
->folder
) continue;
1180 if (item
->no_select
) continue;
1181 if (folder
&& folder
!= item
->folder
) continue;
1182 if (!folder
&& !FOLDER_IS_LOCAL(item
->folder
)) continue;
1183 if (!item
->prefs
->newmailcheck
) continue;
1184 if (item
->processing_pending
== TRUE
) {
1185 debug_print("skipping %s, processing pending\n",
1186 item
->path
? item
->path
: item
->name
);
1189 if (item
->scanning
!= ITEM_NOT_SCANNING
) {
1190 debug_print("skipping %s, scanning\n",
1191 item
->path
? item
->path
: item
->name
);
1195 str
= get_scan_str(item
);
1197 STATUSBAR_PUSH(folderview
->mainwin
, str
);
1201 folderview_scan_tree_func(item
->folder
, item
, NULL
);
1202 former_new
= item
->new_msgs
;
1203 former_unread
= item
->unread_msgs
;
1204 former_total
= item
->total_msgs
;
1206 if (item
->folder
->klass
->scan_required
&&
1207 (item
->folder
->klass
->scan_required(item
->folder
, item
) ||
1208 item
->folder
->inbox
== item
||
1209 item
->opened
== TRUE
||
1210 item
->processing_pending
== TRUE
)) {
1211 if (folder_item_scan(item
) < 0) {
1213 if (FOLDER_TYPE(item
->folder
) == F_NEWS
|| FOLDER_IS_LOCAL(folder
)) {
1214 log_error(LOG_PROTOCOL
, _("Couldn't scan folder %s\n"),
1215 item
->path
? item
->path
:item
->name
);
1216 STATUSBAR_POP(folderview
->mainwin
);
1218 } else if (!FOLDER_IS_LOCAL(folder
)) {
1219 STATUSBAR_POP(folderview
->mainwin
);
1224 } else if (!item
->folder
->klass
->scan_required
) {
1225 if (folder_item_scan(item
) < 0) {
1226 if (folder
&& !FOLDER_IS_LOCAL(folder
)) {
1227 STATUSBAR_POP(folderview
->mainwin
);
1232 if (former_new
!= item
->new_msgs
||
1233 former_unread
!= item
->unread_msgs
||
1234 former_total
!= item
->total_msgs
)
1235 folderview_update_node(folderview
, node
);
1237 new_msgs
+= item
->new_msgs
;
1238 former_new_msgs
+= former_new
;
1239 STATUSBAR_POP(folderview
->mainwin
);
1241 folderview
->scanning_folder
= NULL
;
1242 main_window_unlock(folderview
->mainwin
);
1246 folder_write_list();
1247 /* Number of new messages since last check is the just the difference
1248 * between former_new_msgs and new_msgs. If new_msgs is less than
1249 * former_new_msgs, that would mean another session accessed the folder
1250 * and the result is not well defined.
1252 new_msgs
= (former_new_msgs
< new_msgs
? new_msgs
- former_new_msgs
: 0);
1256 void folderview_check_new_all(void)
1260 FolderView
*folderview
;
1262 folderview
= (FolderView
*)folderview_list
->data
;
1265 main_window_lock(folderview
->mainwin
);
1266 window
= label_window_create
1267 (_("Checking for new messages in all folders..."));
1269 list
= folder_get_list();
1270 for (; list
!= NULL
; list
= list
->next
) {
1271 Folder
*folder
= list
->data
;
1273 folderview_check_new(folder
);
1276 folder_write_list();
1277 folderview_set_all();
1279 label_window_destroy(window
);
1280 main_window_unlock(folderview
->mainwin
);
1284 static gboolean
folderview_have_children_sub(FolderView
*folderview
,
1290 if (!item
|| !item
->folder
|| !item
->folder
->node
)
1293 node
= item
->folder
->node
;
1295 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1296 node
= node
->children
;
1298 if (in_sub
&& item
->total_msgs
> 0) {
1302 while (node
!= NULL
) {
1303 if (node
&& node
->data
) {
1304 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1306 if (folderview_have_children_sub(folderview
,
1315 static gboolean
folderview_have_children(FolderView
*folderview
,
1318 return folderview_have_children_sub(folderview
, item
, FALSE
);
1321 static gboolean
folderview_have_new_children_sub(FolderView
*folderview
,
1327 if (!item
|| !item
->folder
|| !item
->folder
->node
)
1330 node
= item
->folder
->node
;
1332 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1333 node
= node
->children
;
1336 (item
->new_msgs
> 0 ||
1337 (folder_has_parent_of_type(item
, F_QUEUE
) && item
->total_msgs
> 0))) {
1341 while (node
!= NULL
) {
1342 if (node
&& node
->data
) {
1343 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1345 if (folderview_have_new_children_sub(folderview
,
1354 static gboolean
folderview_have_new_children(FolderView
*folderview
,
1357 return folderview_have_new_children_sub(folderview
, item
, FALSE
);
1360 static gboolean
folderview_have_unread_children_sub(FolderView
*folderview
,
1366 if (!item
|| !item
->folder
|| !item
->folder
->node
)
1369 node
= item
->folder
->node
;
1371 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1372 node
= node
->children
;
1375 (item
->unread_msgs
> 0 ||
1376 (folder_has_parent_of_type(item
, F_QUEUE
) && item
->total_msgs
> 0))) {
1380 while (node
!= NULL
) {
1381 if (node
&& node
->data
) {
1382 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1384 if (folderview_have_unread_children_sub(folderview
,
1394 static gboolean
folderview_have_unread_children(FolderView
*folderview
,
1397 return folderview_have_unread_children_sub(folderview
, item
, FALSE
);
1400 static gboolean
folderview_have_read_children_sub(FolderView
*folderview
,
1406 if (!item
|| !item
->folder
|| !item
->folder
->node
) {
1410 node
= item
->folder
->node
;
1412 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1413 node
= node
->children
;
1416 (((item
->total_msgs
> 0) &&
1417 (item
->unread_msgs
!= (item
->total_msgs
- item
->ignored_msgs
))))) {
1421 while (node
!= NULL
) {
1422 if (node
&& node
->data
) {
1423 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1425 if (folderview_have_read_children_sub(folderview
,
1436 static gboolean
folderview_have_read_children(FolderView
*folderview
,
1439 return folderview_have_read_children_sub(folderview
, item
, FALSE
);
1442 static gboolean
folderview_have_matching_children_sub(FolderView
*folderview
,
1448 if (!item
|| !item
->folder
|| !item
->folder
->node
)
1451 node
= item
->folder
->node
;
1453 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1454 node
= node
->children
;
1456 if (in_sub
&& item
->search_match
){
1460 while (node
!= NULL
) {
1461 if (node
&& node
->data
) {
1462 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1464 if (folderview_have_matching_children_sub(folderview
,
1474 static gboolean
folderview_have_matching_children(FolderView
*folderview
,
1477 return folderview_have_matching_children_sub(folderview
, item
, FALSE
);
1480 static gboolean
folderview_have_marked_children_sub(FolderView
*folderview
,
1486 if (!item
|| !item
->folder
|| !item
->folder
->node
)
1489 node
= item
->folder
->node
;
1491 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1492 node
= node
->children
;
1494 if (item
->marked_msgs
!= 0) {
1498 while (node
!= NULL
) {
1499 if (node
&& node
->data
) {
1500 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1502 if (folderview_have_marked_children_sub(folderview
,
1511 static gboolean
folderview_have_marked_children(FolderView
*folderview
,
1514 return folderview_have_marked_children_sub(folderview
, item
, FALSE
);
1517 static void folderview_update_node(FolderView
*folderview
, GtkCMCTreeNode
*node
)
1519 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
1520 GtkStyle
*style
= NULL
, *prev_style
;
1522 GdkRGBA black
= { 0, 0, 0, 1 };
1523 GdkPixbuf
*xpm
, *openxpm
;
1524 static GdkPixbuf
*searchicon
;
1525 gboolean mark
= FALSE
;
1528 gboolean add_unread_mark
;
1529 gboolean add_sub_match_mark
;
1530 gboolean use_bold
, use_color
;
1531 gint
*col_pos
= folderview
->col_pos
;
1532 SpecialFolderItemType stype
;
1534 item
= gtk_cmctree_node_get_row_data(ctree
, node
);
1535 cm_return_if_fail(item
!= NULL
);
1537 if (!GTK_CMCTREE_ROW(node
)->expanded
)
1538 mark
= folderview_have_marked_children(folderview
, item
);
1540 mark
= (item
->marked_msgs
!= 0);
1542 stype
= item
->stype
;
1543 if (stype
== F_NORMAL
) {
1544 if (folder_has_parent_of_type(item
, F_TRASH
))
1546 else if (folder_has_parent_of_type(item
, F_DRAFT
))
1548 else if (folder_has_parent_of_type(item
, F_OUTBOX
))
1550 else if (folder_has_parent_of_type(item
, F_QUEUE
))
1555 if (item
->hide_read_msgs
|| item
->hide_read_threads
) {
1556 xpm
= mark
?m_inboxhrmxpm
:inboxhrmxpm
;
1557 openxpm
= mark
?m_inboxopenhrmxpm
:inboxopenhrmxpm
;
1559 xpm
= mark
?m_inboxxpm
:inboxxpm
;
1560 openxpm
= mark
?m_inboxopenxpm
:inboxopenxpm
;
1564 if (item
->hide_read_msgs
|| item
->hide_read_threads
) {
1565 xpm
= mark
?m_outboxhrmxpm
:outboxhrmxpm
;
1566 openxpm
= mark
?m_outboxopenhrmxpm
:outboxopenhrmxpm
;
1568 xpm
= mark
?m_outboxxpm
:outboxxpm
;
1569 openxpm
= mark
?m_outboxopenxpm
:outboxopenxpm
;
1573 if (item
->hide_read_msgs
|| item
->hide_read_threads
) {
1574 xpm
= mark
?m_queuehrmxpm
:queuehrmxpm
;
1575 openxpm
= mark
?m_queueopenhrmxpm
:queueopenhrmxpm
;
1577 xpm
= mark
?m_queuexpm
:queuexpm
;
1578 openxpm
= mark
?m_queueopenxpm
:queueopenxpm
;
1582 if (item
->hide_read_msgs
|| item
->hide_read_threads
) {
1583 xpm
= mark
?m_trashhrmxpm
:trashhrmxpm
;
1584 openxpm
= mark
?m_trashopenhrmxpm
:trashopenhrmxpm
;
1586 xpm
= mark
?m_trashxpm
:trashxpm
;
1587 openxpm
= mark
?m_trashopenxpm
:trashopenxpm
;
1591 xpm
= mark
?m_draftsxpm
:draftsxpm
;
1592 openxpm
= mark
?m_draftsopenxpm
:draftsopenxpm
;
1596 FOLDER_TYPE(item
->folder
) == F_IMAP
&&
1597 item
->folder
->account
->imap_subsonly
) {
1598 xpm
= mark
?m_foldersubsxpm
:foldersubsxpm
;
1599 openxpm
= foldersubsopenxpm
;
1600 } else if (item
->no_select
) {
1601 xpm
= mark
?m_foldernoselectxpm
:foldernoselectxpm
;
1602 openxpm
= foldernoselectopenxpm
;
1603 } else if (item
->hide_read_msgs
|| item
->hide_read_threads
) {
1604 xpm
= mark
?m_folderhrmxpm
:folderhrmxpm
;
1605 openxpm
= mark
?m_folderopenhrmxpm
:folderopenhrmxpm
;
1607 xpm
= mark
?m_folderxpm
:folderxpm
;
1608 openxpm
= mark
?m_folderopenxpm
:folderopenxpm
;
1612 name
= folder_item_get_name(item
);
1614 if (!GTK_CMCTREE_ROW(node
)->expanded
) {
1615 add_unread_mark
= folderview_have_unread_children(
1617 add_sub_match_mark
= folderview_have_matching_children(
1620 add_unread_mark
= FALSE
;
1621 add_sub_match_mark
= FALSE
;
1624 if (item
->search_match
) {
1626 stock_pixbuf_gdk(STOCK_PIXMAP_QUICKSEARCH
,
1629 xpm
= openxpm
= searchicon
;
1633 if (prefs_common
.display_folder_unread
) {
1634 if (folder_has_parent_of_type(item
, F_QUEUE
)) {
1635 /* only total_msgs matters here */
1636 if (item
->total_msgs
> 0) {
1637 /* show total number (should be equal to the unread number)
1639 str
= g_strdup_printf("%s (%d%s%s)",
1640 name
, item
->total_msgs
,
1641 (add_unread_mark
|| add_sub_match_mark
) ? "+" : "",
1642 (item
->unreadmarked_msgs
> 0) ? "!" : "");
1645 if (prefs_common
.display_folder_unread
== 1) {
1646 if (item
->unread_msgs
> 0) {
1647 /* show unread number and signs */
1648 str
= g_strdup_printf("%s (%d%s%s)",
1649 name
, item
->unread_msgs
,
1650 (add_unread_mark
|| add_sub_match_mark
) ? "+" : "",
1651 (item
->unreadmarked_msgs
> 0) ? "!" : "");
1654 if (item
->total_msgs
> 0) {
1655 /* show unread number, total number and signs if any */
1656 str
= g_strdup_printf("%s (%d/%d%s%s)",
1657 name
, item
->unread_msgs
, item
->total_msgs
,
1658 (add_unread_mark
|| add_sub_match_mark
) ? "+" : "",
1659 (item
->unreadmarked_msgs
> 0) ? "!" : "");
1663 if ((str
== NULL
) &&
1664 (add_unread_mark
|| add_sub_match_mark
|| (item
->unreadmarked_msgs
> 0))) {
1665 /* no unread/total numbers, but at least one sign */
1666 str
= g_strdup_printf("%s (%s%s)",
1668 (add_unread_mark
|| add_sub_match_mark
) ? "+" : "",
1669 (item
->unreadmarked_msgs
> 0) ? "!" : "");
1673 /* last fallback, folder name only or with +! sign */
1674 if (item
->unreadmarked_msgs
> 0 && add_sub_match_mark
) {
1675 str
= g_strdup_printf("%s%s",
1677 } else if (item
->unreadmarked_msgs
> 0) {
1678 str
= g_strdup_printf("%s%s",
1680 } else if (add_sub_match_mark
) {
1681 str
= g_strdup_printf("%s%s",
1684 str
= g_strdup_printf("%s", name
);
1687 gtk_cmctree_set_node_info(ctree
, node
, str
, FOLDER_SPACING
,
1689 FALSE
, GTK_CMCTREE_ROW(node
)->expanded
);
1693 if (!folder_item_parent(item
)) {
1694 gtk_cmctree_node_set_text(ctree
, node
, col_pos
[F_COL_NEW
], "-");
1695 gtk_cmctree_node_set_text(ctree
, node
, col_pos
[F_COL_UNREAD
], "-");
1696 gtk_cmctree_node_set_text(ctree
, node
, col_pos
[F_COL_TOTAL
], "-");
1698 gtk_cmctree_node_set_text(ctree
, node
, col_pos
[F_COL_NEW
], item
->new_msgs
> 0 ? itos(item
->new_msgs
) : prefs_common
.zero_replacement
);
1699 gtk_cmctree_node_set_text(ctree
, node
, col_pos
[F_COL_UNREAD
], item
->unread_msgs
> 0 ? itos(item
->unread_msgs
) : prefs_common
.zero_replacement
);
1700 gtk_cmctree_node_set_text(ctree
, node
, col_pos
[F_COL_TOTAL
], item
->total_msgs
> 0 ? itos(item
->total_msgs
) : prefs_common
.zero_replacement
);
1703 if (folder_has_parent_of_type(item
, F_OUTBOX
) ||
1704 folder_has_parent_of_type(item
, F_TRASH
)) {
1705 use_bold
= use_color
= FALSE
;
1706 } else if (folder_has_parent_of_type(item
, F_QUEUE
)) {
1707 GSList
*list
= folder_item_get_msg_list(item
);
1709 use_bold
= use_color
= FALSE
;
1710 for (cur
= list
; cur
; cur
= cur
->next
) {
1711 MsgInfo
*msginfo
= (MsgInfo
*)cur
->data
;
1712 if (!MSG_IS_DELETED(msginfo
->flags
)) {
1713 /* highlight queue folder if there are any messages */
1714 use_bold
= use_color
= TRUE
;
1718 if (!GTK_CMCTREE_ROW(node
)->expanded
&&
1719 use_bold
== FALSE
&&
1720 folderview_have_children(folderview
, item
))
1721 use_bold
= use_color
= TRUE
;
1722 procmsg_msg_list_free(list
);
1724 /* if unread messages exist or target folder is set, print with bold font */
1725 use_bold
= (item
->unread_msgs
> 0 || item
->new_msgs
> 0 || item
->op_count
> 0)
1727 /* if new messages exist, print with colored letter */
1729 (item
->new_msgs
> 0) ||
1731 folderview_have_new_children(folderview
, item
));
1734 gtk_cmctree_node_set_foreground(ctree
, node
, NULL
);
1738 if (item
->op_count
> 0)
1739 gtk_cmctree_node_set_foreground(ctree
, node
, &folderview
->color_op
);
1741 gtk_cmctree_node_set_foreground(ctree
, node
, &folderview
->color_new
);
1742 else if (!gdk_rgba_equal(&item
->prefs
->color
, &black
))
1743 gtk_cmctree_node_set_foreground(ctree
, node
, &item
->prefs
->color
);
1744 } else if (use_color
)
1745 gtk_cmctree_node_set_foreground(ctree
, node
, &folderview
->color_new
);
1746 else if (item
->op_count
> 0)
1747 gtk_cmctree_node_set_foreground(ctree
, node
, &folderview
->color_op
);
1748 else if (!gdk_rgba_equal(&item
->prefs
->color
, &black
))
1749 gtk_cmctree_node_set_foreground(ctree
, node
, &item
->prefs
->color
);
1751 gtk_cmctree_node_set_row_style(ctree
, node
, style
);
1753 prev_style
= gtk_cmctree_node_get_row_style(ctree
, node
);
1755 GtkStyle
*ctree_style
= gtk_widget_get_style(GTK_WIDGET(ctree
));
1757 style
= gtk_style_copy(prev_style
);
1758 style
->text
[GTK_STATE_NORMAL
] = ctree_style
->text
[GTK_STATE_NORMAL
];
1759 style
->text
[GTK_STATE_SELECTED
] = ctree_style
->text
[GTK_STATE_SELECTED
];
1760 gtk_cmctree_node_set_row_style(ctree
, node
, style
);
1761 g_object_unref(style
);
1764 if ((node
= gtkut_ctree_find_collapsed_parent(ctree
, node
)) != NULL
)
1765 folderview_update_node(folderview
, node
);
1768 void folderview_update_search_icon(FolderItem
*item
, gboolean matches
)
1771 FolderView
*folderview
;
1773 GtkCMCTreeNode
*node
;
1775 cm_return_if_fail(item
!= NULL
);
1777 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
) {
1778 folderview
= (FolderView
*)list
->data
;
1779 ctree
= GTK_CMCTREE(folderview
->ctree
);
1781 node
= gtk_cmctree_find_by_row_data(ctree
, NULL
, item
);
1782 if (node
&& item
->search_match
!= matches
) {
1783 item
->search_match
= matches
;
1784 folderview_update_node(folderview
, node
);
1789 static gboolean
folderview_update_item_claws(gpointer source
, gpointer data
)
1791 FolderItemUpdateData
*update_info
= (FolderItemUpdateData
*)source
;
1792 FolderView
*folderview
= (FolderView
*)data
;
1794 GtkCMCTreeNode
*node
;
1795 cm_return_val_if_fail(update_info
!= NULL
, TRUE
);
1796 cm_return_val_if_fail(update_info
->item
!= NULL
, TRUE
);
1797 cm_return_val_if_fail(folderview
!= NULL
, FALSE
);
1799 ctree
= GTK_CMCTREE(folderview
->ctree
);
1801 node
= gtk_cmctree_find_by_row_data(ctree
, NULL
, update_info
->item
);
1804 if (update_info
->update_flags
& (F_ITEM_UPDATE_MSGCNT
| F_ITEM_UPDATE_NAME
))
1805 folderview_update_node(folderview
, node
);
1807 if ((update_info
->update_flags
& F_ITEM_UPDATE_CONTENT
) &&
1808 update_info
->item
== folderview
->summaryview
->folder_item
&&
1809 update_info
->item
!= NULL
)
1810 if (!quicksearch_has_sat_predicate(folderview
->summaryview
->quicksearch
))
1811 summary_show(folderview
->summaryview
, update_info
->item
, FALSE
);
1817 static gboolean
folderview_gnode_func(GtkCMCTree
*ctree
, guint depth
,
1818 GNode
*gnode
, GtkCMCTreeNode
*cnode
,
1821 FolderView
*folderview
= (FolderView
*)data
;
1822 FolderItem
*item
= FOLDER_ITEM(gnode
->data
);
1824 cm_return_val_if_fail(item
!= NULL
, FALSE
);
1826 gtk_cmctree_node_set_row_data(ctree
, cnode
, item
);
1827 folderview_update_node(folderview
, cnode
);
1832 static void folderview_expand_func(GtkCMCTree
*ctree
, GtkCMCTreeNode
*node
,
1835 FolderView
*folderview
= (FolderView
*)data
;
1838 if (GTK_CMCTREE_ROW(node
)->children
) {
1839 item
= gtk_cmctree_node_get_row_data(ctree
, node
);
1840 cm_return_if_fail(item
!= NULL
);
1842 if (!item
->collapsed
)
1843 gtk_cmctree_expand(ctree
, node
);
1845 folderview_update_node(folderview
, node
);
1849 static void set_special_folder(GtkCMCTree
*ctree
, FolderItem
*item
,
1850 GtkCMCTreeNode
*root
, GtkCMCTreeNode
**prev
)
1853 GtkCMCTreeNode
*node
, *parent
, *sibling
;
1855 node
= gtk_cmctree_find_by_row_data(ctree
, root
, item
);
1857 g_warning("%s not found", item
->path
);
1859 parent
= GTK_CMCTREE_ROW(node
)->parent
;
1860 if (*prev
&& parent
== GTK_CMCTREE_ROW(*prev
)->parent
)
1861 sibling
= GTK_CMCTREE_ROW(*prev
)->sibling
;
1863 sibling
= GTK_CMCTREE_ROW(parent
)->children
;
1867 tmp
= gtk_cmctree_node_get_row_data
1869 if (tmp
&& tmp
->stype
!= F_NORMAL
)
1870 sibling
= GTK_CMCTREE_ROW(sibling
)->sibling
;
1874 if (node
!= sibling
)
1875 gtk_cmctree_move(ctree
, node
, parent
, sibling
);
1882 static void folderview_sort_folders(FolderView
*folderview
, GtkCMCTreeNode
*root
,
1885 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
1886 GtkCMCTreeNode
*prev
= NULL
;
1888 gtk_cmclist_freeze(GTK_CMCLIST(ctree
));
1889 gtk_sctree_sort_recursive(ctree
, root
);
1890 if (root
&& GTK_CMCTREE_ROW(root
)->parent
) {
1891 gtk_cmclist_thaw(GTK_CMCLIST(ctree
));
1894 set_special_folder(ctree
, folder
->inbox
, root
, &prev
);
1895 set_special_folder(ctree
, folder
->outbox
, root
, &prev
);
1896 set_special_folder(ctree
, folder
->draft
, root
, &prev
);
1897 set_special_folder(ctree
, folder
->queue
, root
, &prev
);
1898 set_special_folder(ctree
, folder
->trash
, root
, &prev
);
1899 gtk_cmclist_thaw(GTK_CMCLIST(ctree
));
1902 static void folderview_append_folder(FolderView
*folderview
, Folder
*folder
)
1904 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
1905 GtkCMCTreeNode
*root
;
1907 cm_return_if_fail(folder
!= NULL
);
1909 root
= gtk_sctree_insert_gnode(ctree
, NULL
, NULL
, folder
->node
,
1910 folderview_gnode_func
, folderview
);
1911 gtk_cmctree_pre_recursive(ctree
, root
, folderview_expand_func
,
1913 folderview_sort_folders(folderview
, root
, folder
);
1916 /* callback functions */
1917 static void folderview_set_sens_and_popup_menu(FolderView
*folderview
, gint row
,
1918 GdkEventButton
*event
)
1922 FolderViewPopup
*fpopup
;
1923 GtkActionGroup
*action_group
;
1925 FolderItem
*special_trash
= NULL
, *special_queue
= NULL
;
1927 GtkUIManager
*ui_manager
= gtk_ui_manager_new();
1929 if (folderview
->ui_manager
)
1930 g_object_unref(folderview
->ui_manager
);
1932 folderview
->ui_manager
= ui_manager
;
1933 item
= folderview_get_selected_item(folderview
);
1935 cm_return_if_fail(item
!= NULL
);
1936 cm_return_if_fail(item
->folder
!= NULL
);
1937 folder
= item
->folder
;
1939 fpopup
= g_hash_table_lookup(folderview_popups
, folder
->klass
->idstr
);
1942 action_group
= g_hash_table_lookup(folderview
->popups
, folder
->klass
->idstr
);
1944 fpopup
= g_hash_table_lookup(folderview_popups
, "common");
1945 action_group
= g_hash_table_lookup(folderview
->popups
, "common");
1948 gtk_ui_manager_insert_action_group(ui_manager
, action_group
, 0);
1949 MENUITEM_ADDUI_MANAGER(ui_manager
, "/", "Popup", "Popup", GTK_UI_MANAGER_MENUBAR
)
1950 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup", "FolderViewPopup", "FolderViewPopup", GTK_UI_MANAGER_MENU
)
1952 if (fpopup
->add_menuitems
)
1953 fpopup
->add_menuitems(ui_manager
, item
);
1955 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "MarkAllRead", "FolderViewPopup/MarkAllRead", GTK_UI_MANAGER_MENUITEM
)
1956 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "MarkAllUnread", "FolderViewPopup/MarkAllUnread", GTK_UI_MANAGER_MENUITEM
)
1957 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "MarkAllReadRec", "FolderViewPopup/MarkAllReadRec", GTK_UI_MANAGER_MENUITEM
)
1958 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "MarkAllUnreadRec", "FolderViewPopup/MarkAllUnreadRec", GTK_UI_MANAGER_MENUITEM
)
1959 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "Separator1", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR
)
1960 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "RunProcessing", "FolderViewPopup/RunProcessing", GTK_UI_MANAGER_MENUITEM
)
1961 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "SearchFolder", "FolderViewPopup/SearchFolder", GTK_UI_MANAGER_MENUITEM
)
1962 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "OpenFolder", "FolderViewPopup/OpenFolder", GTK_UI_MANAGER_MENUITEM
)
1963 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "Properties", "FolderViewPopup/Properties", GTK_UI_MANAGER_MENUITEM
)
1964 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "Processing", "FolderViewPopup/Processing", GTK_UI_MANAGER_MENUITEM
)
1966 if (fpopup
->set_sensitivity
!= NULL
)
1967 fpopup
->set_sensitivity(ui_manager
, item
);
1969 if (NULL
!= (ac
= account_find_from_item(item
))) {
1970 special_trash
= account_get_special_folder(ac
, F_TRASH
);
1971 special_queue
= account_get_special_folder(ac
, F_QUEUE
);
1974 if ((item
== folder
->trash
|| item
== special_trash
1975 || folder_has_parent_of_type(item
, F_TRASH
))) {
1976 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "SeparatorTrash", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR
)
1977 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "EmptyTrash", "FolderViewPopup/EmptyTrash", GTK_UI_MANAGER_MENUITEM
)
1980 if ((item
== folder
->queue
|| item
== special_queue
1981 || folder_has_parent_of_type(item
, F_QUEUE
))) {
1982 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "SeparatorQueue", "FolderViewPopup/---", GTK_UI_MANAGER_SEPARATOR
)
1983 MENUITEM_ADDUI_MANAGER(ui_manager
, "/Popup/FolderViewPopup", "SendQueue", "FolderViewPopup/SendQueue", GTK_UI_MANAGER_MENUITEM
)
1986 #define SET_SENS(name, sens) \
1987 cm_menu_set_sensitive_full(ui_manager, "Popup/"name, sens)
1989 SET_SENS("FolderViewPopup/MarkAllRead", item
->unread_msgs
> 0);
1990 SET_SENS("FolderViewPopup/MarkAllUnread", (item
->total_msgs
> 0) &&
1991 (item
->unread_msgs
!= (item
->total_msgs
- item
->ignored_msgs
)));
1992 SET_SENS("FolderViewPopup/MarkAllReadRec", folderview_have_unread_children(folderview
,item
));
1993 SET_SENS("FolderViewPopup/MarkAllUnreadRec", folderview_have_read_children(folderview
,item
));
1994 SET_SENS("FolderViewPopup/SearchFolder", item
->total_msgs
> 0 &&
1995 folderview
->selected
== folderview
->opened
);
1996 SET_SENS("FolderViewPopup/Properties", TRUE
);
1998 SET_SENS("FolderViewPopup/RunProcessing", item
->prefs
->processing
&&
1999 item
->total_msgs
>= 1 && !item
->processing_pending
);
2000 SET_SENS("FolderViewPopup/Processing", item
->node
->parent
!= NULL
&&
2001 !item
->no_select
&& !item
->processing_pending
);
2003 if (item
->node
->parent
!= NULL
) {
2004 gchar
*id
= folder_item_get_identifier(item
);
2005 SET_SENS("FolderViewPopup/OpenFolder", !prefs_common
.goto_folder_on_startup
2006 || strcmp(id
, prefs_common
.startup_folder
));
2010 if (item
== folder
->trash
|| item
== special_trash
2011 || folder_has_parent_of_type(item
, F_TRASH
)) {
2012 GSList
*msglist
= folder_item_get_msg_list(item
);
2013 SET_SENS("FolderViewPopup/EmptyTrash", msglist
!= NULL
);
2014 procmsg_msg_list_free(msglist
);
2016 if (item
== folder
->queue
|| item
== special_queue
2017 || folder_has_parent_of_type(item
, F_QUEUE
)) {
2018 GSList
*msglist
= folder_item_get_msg_list(item
);
2019 SET_SENS("FolderViewPopup/SendQueue", msglist
!= NULL
);
2020 procmsg_msg_list_free(msglist
);
2024 popup
= gtk_menu_item_get_submenu(GTK_MENU_ITEM(
2025 gtk_ui_manager_get_widget(ui_manager
, "/Popup/FolderViewPopup")) );
2026 g_signal_connect(G_OBJECT(popup
), "selection_done",
2027 G_CALLBACK(folderview_popup_close
),
2029 gtk_menu_popup_at_pointer(GTK_MENU(popup
), NULL
);
2032 static gboolean
folderview_button_pressed(GtkWidget
*ctree
, GdkEventButton
*event
,
2033 FolderView
*folderview
)
2035 GtkCMCList
*clist
= GTK_CMCLIST(ctree
);
2036 gint prev_row
= -1, row
= -1, column
= -1;
2038 if (!event
) return FALSE
;
2039 if (event
->window
!= clist
->clist_window
) return FALSE
;
2041 if (event
->button
== 1 || event
->button
== 2) {
2042 if (!gtk_sctree_is_hot_spot (GTK_SCTREE(clist
), event
->x
, event
->y
))
2043 folderview
->open_folder
= TRUE
;
2045 if (event
->type
== GDK_2BUTTON_PRESS
) {
2046 if (clist
->selection
) {
2047 GtkCMCTreeNode
*node
;
2049 node
= GTK_CMCTREE_NODE(clist
->selection
->data
);
2051 gtk_cmctree_toggle_expansion(
2054 folderview
->open_folder
= FALSE
;
2061 if (event
->button
== 2 || event
->button
== 3) {
2063 if (clist
->selection
) {
2064 GtkCMCTreeNode
*node
;
2066 node
= GTK_CMCTREE_NODE(clist
->selection
->data
);
2068 prev_row
= gtkut_ctree_get_nth_from_node
2069 (GTK_CMCTREE(ctree
), node
);
2072 if (!gtk_cmclist_get_selection_info(clist
, event
->x
, event
->y
,
2075 if (prev_row
!= row
) {
2076 gtk_cmclist_unselect_all(clist
);
2077 if (event
->button
== 2)
2078 folderview_select_node
2080 gtk_cmctree_node_nth(GTK_CMCTREE(ctree
),
2083 gtk_cmclist_select_row(clist
, row
, column
);
2087 if (event
->button
!= 3) return FALSE
;
2089 folderview_set_sens_and_popup_menu(folderview
, row
, event
);
2093 static gboolean
folderview_button_released(GtkWidget
*ctree
, GdkEventButton
*event
,
2094 FolderView
*folderview
)
2096 int row
= -1, column
= -1;
2098 if (!event
) return FALSE
;
2100 if (!gtk_cmclist_get_selection_info(GTK_CMCLIST(ctree
), event
->x
, event
->y
,
2103 if (event
->button
== 1 && folderview
->open_folder
== FALSE
&&
2104 folderview
->opened
!= NULL
) {
2105 gtkut_ctree_set_focus_row(GTK_CMCTREE(ctree
),
2106 folderview
->opened
);
2107 gtk_cmctree_select(GTK_CMCTREE(ctree
), folderview
->opened
);
2113 #define BREAK_ON_MODIFIER_KEY() \
2114 if ((event->state & (GDK_MOD1_MASK|GDK_CONTROL_MASK)) != 0) break
2116 static gboolean
folderview_key_pressed(GtkWidget
*widget
, GdkEventKey
*event
,
2117 FolderView
*folderview
)
2119 GtkCMCTreeNode
*node
;
2122 if (!event
) return FALSE
;
2124 if (quicksearch_has_focus(folderview
->summaryview
->quicksearch
))
2127 switch (event
->keyval
) {
2129 if (folderview
->selected
) {
2130 if (GTK_CMCTREE_ROW(folderview
->selected
)->children
!= NULL
2131 && !GTK_CMCTREE_ROW(folderview
->selected
)->expanded
)
2132 gtk_cmctree_expand(GTK_CMCTREE(folderview
->ctree
),
2133 folderview
->selected
);
2135 folderview_select_node(folderview
,
2136 folderview
->selected
);
2140 case GDK_KEY_Return
:
2141 if (folderview
->selected
&& GTK_CMCTREE_ROW(folderview
->selected
)->children
) {
2142 gtk_cmctree_toggle_expansion(
2143 GTK_CMCTREE(folderview
->ctree
),
2144 folderview
->selected
);
2148 case GDK_KEY_Return
:
2149 case GDK_KEY_KP_Enter
:
2150 if (folderview
->selected
)
2151 folderview_select_node(folderview
, folderview
->selected
);
2155 BREAK_ON_MODIFIER_KEY();
2156 if (folderview
->selected
) {
2157 if (folderview
->opened
== folderview
->selected
&&
2158 (!folderview
->summaryview
->folder_item
||
2159 folderview
->summaryview
->folder_item
->total_msgs
== 0))
2160 folderview_select_next_with_flag(folderview
, MSG_UNREAD
);
2162 folderview_select_node(folderview
,
2163 folderview
->selected
);
2167 if (folderview
->selected
) {
2168 /* If the folder is expanded and can be collapsed, do that... */
2169 if (GTK_CMCTREE_ROW(folderview
->selected
)->expanded
&&
2170 GTK_CMCTREE_ROW(folderview
->selected
)->children
!= NULL
) {
2171 gtk_cmctree_collapse(GTK_CMCTREE(folderview
->ctree
),
2172 folderview
->selected
);
2174 /* ...otherwise, move cursor to its parent node. */
2175 if ((item
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(folderview
->ctree
),
2176 folderview
->selected
))) {
2177 if ((node
= gtk_cmctree_find_by_row_data(GTK_CMCTREE(folderview
->ctree
),
2178 NULL
, folder_item_parent(item
)))) {
2179 gtk_sctree_select(GTK_SCTREE(folderview
->ctree
), node
);
2180 if (!gtk_cmctree_node_is_visible(GTK_CMCTREE(folderview
->ctree
), node
))
2181 gtk_cmctree_node_moveto(GTK_CMCTREE(folderview
->ctree
),
2190 if (event
->keyval
== GDK_KEY_Home
)
2191 node
= gtk_cmctree_node_nth(GTK_CMCTREE(folderview
->ctree
), 0);
2193 node
= gtk_cmctree_last(GTK_CMCTREE(folderview
->ctree
),
2194 gtk_cmctree_node_nth(GTK_CMCTREE(folderview
->ctree
), 0));
2196 gtk_sctree_select(GTK_SCTREE(folderview
->ctree
), node
);
2198 if (!gtk_cmctree_node_is_visible(GTK_CMCTREE(folderview
->ctree
), node
))
2199 gtk_cmctree_node_moveto(GTK_CMCTREE(folderview
->ctree
),
2209 typedef struct _PostponedSelectData
2212 GtkCMCTreeNode
*row
;
2214 FolderView
*folderview
;
2215 } PostponedSelectData
;
2217 static gboolean
postpone_select(void *data
)
2219 PostponedSelectData
*psdata
= (PostponedSelectData
*)data
;
2220 debug_print("trying again\n");
2222 psdata
->folderview
->postpone_select_id
= 0;
2223 psdata
->folderview
->open_folder
= TRUE
;
2224 main_window_cursor_normal(psdata
->folderview
->mainwin
);
2225 STATUSBAR_POP(psdata
->folderview
->mainwin
);
2226 folderview_selected(psdata
->ctree
, psdata
->row
,
2227 psdata
->column
, psdata
->folderview
);
2232 void folderview_close_opened(FolderView
*folderview
, gboolean dirty
)
2234 if (folderview
->opened
) {
2236 folderview
->opened
= NULL
;
2240 FolderItem
*olditem
=
2241 gtk_cmctree_node_get_row_data(GTK_CMCTREE(folderview
->ctree
),
2242 folderview
->opened
);
2244 gchar
*buf
= g_strdup_printf(_("Closing folder %s..."),
2245 olditem
->path
? olditem
->path
:olditem
->name
);
2246 /* will be null if we just moved the previously opened folder */
2247 STATUSBAR_PUSH(folderview
->mainwin
, buf
);
2248 main_window_cursor_wait(folderview
->mainwin
);
2250 summary_save_prefs_to_folderitem(folderview
->summaryview
, olditem
);
2251 summary_show(folderview
->summaryview
, NULL
, FALSE
);
2252 folder_item_close(olditem
);
2253 main_window_cursor_normal(folderview
->mainwin
);
2254 STATUSBAR_POP(folderview
->mainwin
);
2255 if (olditem
->folder
->klass
->item_closed
)
2256 olditem
->folder
->klass
->item_closed(olditem
);
2261 if (folderview
->opened
&&
2262 !GTK_CMCTREE_ROW(folderview
->opened
)->children
)
2263 gtk_cmctree_collapse(GTK_CMCTREE(folderview
->ctree
), folderview
->opened
);
2265 folderview
->opened
= NULL
;
2267 static void folderview_selected(GtkCMCTree
*ctree
, GtkCMCTreeNode
*row
,
2268 gint column
, FolderView
*folderview
)
2270 GdkDisplay
*display
;
2273 static gboolean can_select
= TRUE
; /* exclusive lock */
2278 GtkCMCTreeNode
*old_opened
= folderview
->opened
;
2280 folderview
->selected
= row
;
2282 display
= gdk_display_get_default();
2283 seat
= gdk_display_get_default_seat(display
);
2284 device
= gdk_seat_get_pointer(seat
);
2286 debug_print("newly selected %p, opened %p\n", folderview
->selected
,
2287 folderview
->opened
);
2288 if (folderview
->opened
== row
) {
2289 folderview
->open_folder
= FALSE
;
2294 item
= gtk_cmctree_node_get_row_data(ctree
, row
);
2297 folderview
->open_folder
= FALSE
;
2301 if (!can_select
|| summary_is_locked(folderview
->summaryview
)) {
2302 if (folderview
->opened
) {
2303 gtkut_ctree_set_focus_row(ctree
, folderview
->opened
);
2304 gtk_cmctree_select(ctree
, folderview
->opened
);
2306 folderview
->open_folder
= FALSE
;
2311 if (!folderview
->open_folder
) {
2318 /* Save cache for old folder */
2319 /* We don't want to lose all caches if app crashes */
2320 /* Resets folderview->opened to NULL */
2321 folderview_close_opened(folderview
, FALSE
);
2323 /* CLAWS: set compose button type: news folder items
2324 * always have a news folder as parent */
2326 toolbar_set_compose_button
2327 (folderview
->mainwin
->toolbar
,
2328 FOLDER_TYPE(item
->folder
) == F_NEWS
?
2329 COMPOSEBUTTON_NEWS
: COMPOSEBUTTON_MAIL
);
2332 debug_print("Folder %s is selected\n", item
->path
);
2334 if (!GTK_CMCTREE_ROW(row
)->children
)
2335 gtk_cmctree_expand(ctree
, row
);
2337 /* ungrab the mouse event */
2338 if (gtk_widget_has_grab(GTK_WIDGET(ctree
))) {
2339 gtk_grab_remove(GTK_WIDGET(ctree
));
2340 if (gdk_display_device_is_grabbed(display
, device
))
2341 gdk_seat_ungrab(seat
);
2345 /* TODO: wwp: avoid displaying (null) in the status bar */
2346 buf
= g_strdup_printf(_("Opening folder %s..."), item
->path
?
2347 item
->path
: "(null)");
2348 debug_print("%s\n", buf
);
2349 STATUSBAR_PUSH(folderview
->mainwin
, buf
);
2352 main_window_cursor_wait(folderview
->mainwin
);
2354 if (folderview
->scanning_folder
== item
->folder
) {
2357 res
= folder_item_open(item
);
2360 if (res
== -1 && item
->no_select
== FALSE
) {
2361 main_window_cursor_normal(folderview
->mainwin
);
2362 STATUSBAR_POP(folderview
->mainwin
);
2364 alertpanel_error(_("Folder could not be opened."));
2366 folderview
->open_folder
= FALSE
;
2370 } else if (res
== -2 && item
->no_select
== FALSE
) {
2371 PostponedSelectData
*data
= g_new0(PostponedSelectData
, 1);
2372 data
->ctree
= ctree
;
2374 data
->column
= column
;
2375 data
->folderview
= folderview
;
2376 debug_print("postponing open of %s till end of scan\n",
2377 item
->path
? item
->path
:item
->name
);
2378 folderview
->open_folder
= FALSE
;
2380 if (folderview
->postpone_select_id
!= 0)
2381 g_source_remove(folderview
->postpone_select_id
);
2382 folderview
->postpone_select_id
= g_timeout_add(500, postpone_select
, data
);
2387 main_window_cursor_normal(folderview
->mainwin
);
2390 summary_set_prefs_from_folderitem(folderview
->summaryview
, item
);
2391 opened
= summary_show(folderview
->summaryview
, item
, FALSE
);
2393 folder_clean_cache_memory(item
);
2396 gtkut_ctree_set_focus_row(ctree
, old_opened
);
2397 gtk_cmctree_select(ctree
, old_opened
);
2398 folderview
->opened
= old_opened
;
2400 folderview
->opened
= row
;
2401 if (gtk_cmctree_node_is_visible(ctree
, row
)
2402 != GTK_VISIBILITY_FULL
)
2403 gtk_cmctree_node_moveto(ctree
, row
, -1, 0.5, 0);
2406 STATUSBAR_POP(folderview
->mainwin
);
2408 folderview
->open_folder
= FALSE
;
2413 static void folderview_tree_expanded(GtkCMCTree
*ctree
, GtkCMCTreeNode
*node
,
2414 FolderView
*folderview
)
2418 item
= gtk_cmctree_node_get_row_data(ctree
, node
);
2419 cm_return_if_fail(item
!= NULL
);
2420 item
->collapsed
= FALSE
;
2421 folderview_update_node(folderview
, node
);
2424 static void folderview_tree_collapsed(GtkCMCTree
*ctree
, GtkCMCTreeNode
*node
,
2425 FolderView
*folderview
)
2429 item
= gtk_cmctree_node_get_row_data(ctree
, node
);
2430 cm_return_if_fail(item
!= NULL
);
2431 item
->collapsed
= TRUE
;
2432 folderview_update_node(folderview
, node
);
2435 static void folderview_popup_close(GtkMenuShell
*menu_shell
,
2436 FolderView
*folderview
)
2438 if (!folderview
->opened
) return;
2440 gtk_cmctree_select(GTK_CMCTREE(folderview
->ctree
), folderview
->opened
);
2443 static void folderview_col_resized(GtkCMCList
*clist
, gint column
, gint width
,
2444 FolderView
*folderview
)
2446 FolderColumnType type
= folderview
->col_state
[column
].type
;
2448 prefs_common
.folder_col_size
[type
] = width
;
2451 static void folderview_create_folder_node(FolderView
*folderview
, FolderItem
*item
)
2453 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
2454 gchar
*text
[N_FOLDER_COLS
] = {NULL
, "0", "0", "0"};
2455 GtkCMCTreeNode
*node
, *parent_node
;
2456 gint
*col_pos
= folderview
->col_pos
;
2457 FolderItemUpdateData hookdata
;
2459 parent_node
= gtk_cmctree_find_by_row_data(ctree
, NULL
, folder_item_parent(item
));
2460 if (parent_node
== NULL
)
2463 gtk_cmclist_freeze(GTK_CMCLIST(ctree
));
2465 text
[col_pos
[F_COL_FOLDER
]] = item
->name
;
2466 node
= gtk_sctree_insert_node(ctree
, parent_node
, NULL
, text
,
2471 gtk_cmctree_expand(ctree
, parent_node
);
2472 gtk_cmctree_node_set_row_data(ctree
, node
, item
);
2473 folderview_sort_folders(folderview
, parent_node
, item
->folder
);
2475 hookdata
.item
= item
;
2476 hookdata
.update_flags
= F_ITEM_UPDATE_NAME
;
2477 hookdata
.msg
= NULL
;
2478 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST
, &hookdata
);
2480 gtk_cmclist_thaw(GTK_CMCLIST(ctree
));
2483 static void folderview_empty_trash_cb(GtkAction
*action
, gpointer data
)
2485 FolderView
*folderview
= (FolderView
*)data
;
2487 GSList
*mlist
= NULL
;
2489 FolderItem
*special_trash
= NULL
;
2492 if (!folderview
->selected
) return;
2493 item
= folderview_get_selected_item(folderview
);
2494 cm_return_if_fail(item
!= NULL
);
2495 cm_return_if_fail(item
->folder
!= NULL
);
2497 if (NULL
!= (ac
= account_find_from_item(item
)))
2498 special_trash
= account_get_special_folder(ac
, F_TRASH
);
2500 if (item
!= item
->folder
->trash
&& item
!= special_trash
2501 && !folder_has_parent_of_type(item
, F_TRASH
)) return;
2503 if (prefs_common
.ask_on_clean
) {
2504 if (alertpanel(_("Empty trash"),
2505 _("Delete all messages in trash?"),
2506 NULL
, _("_Cancel"), NULL
, _("_Empty trash"), NULL
, NULL
,
2507 ALERTFOCUS_SECOND
) != G_ALERTALTERNATE
)
2511 mlist
= folder_item_get_msg_list(item
);
2513 for (cur
= mlist
; cur
!= NULL
; cur
= cur
->next
) {
2514 MsgInfo
* msginfo
= (MsgInfo
*) cur
->data
;
2515 if (MSG_IS_LOCKED(msginfo
->flags
))
2517 /* is it partially received? (partial_recv isn't cached) */
2518 if (msginfo
->total_size
!= 0 &&
2519 msginfo
->size
!= (off_t
)msginfo
->total_size
)
2520 partial_mark_for_delete(msginfo
);
2522 procmsg_msg_list_free(mlist
);
2524 folder_item_remove_all_msg(item
);
2527 static void folderview_send_queue_cb(GtkAction
*action
, gpointer data
)
2529 FolderView
*folderview
= (FolderView
*)data
;
2531 FolderItem
*special_queue
= NULL
;
2533 gchar
*errstr
= NULL
;
2535 if (!folderview
->selected
) return;
2536 item
= folderview_get_selected_item(folderview
);
2537 cm_return_if_fail(item
!= NULL
);
2538 cm_return_if_fail(item
->folder
!= NULL
);
2540 if (NULL
!= (ac
= account_find_from_item(item
)))
2541 special_queue
= account_get_special_folder(ac
, F_QUEUE
);
2543 if (item
!= item
->folder
->queue
&& item
!= special_queue
2544 && !folder_has_parent_of_type(item
, F_QUEUE
)) return;
2546 if (procmsg_queue_is_empty(item
))
2549 if (prefs_common
.work_offline
)
2550 if (alertpanel(_("Offline warning"),
2551 _("You're working offline. Override?"),
2552 NULL
, _("_No"), NULL
, _("_Yes"),
2553 NULL
, NULL
, ALERTFOCUS_FIRST
) != G_ALERTALTERNATE
)
2556 /* ask for confirmation before sending queued messages only
2557 in online mode and if there is at least one message queued
2558 in any of the folder queue
2560 if (prefs_common
.confirm_send_queued_messages
) {
2561 if (!prefs_common
.work_offline
) {
2562 if (alertpanel(_("Send queued messages"),
2563 _("Send all queued messages?"),
2564 NULL
, _("_Cancel"), NULL
, _("_Send"),
2565 NULL
, NULL
, ALERTFOCUS_FIRST
) != G_ALERTALTERNATE
)
2570 if (procmsg_send_queue(item
, prefs_common
.savemsg
, &errstr
) < 0) {
2572 alertpanel_error_log(_("Some errors occurred while "
2573 "sending queued messages."));
2575 alertpanel_error_log(_("Some errors occurred "
2576 "while sending queued messages:\n%s"), errstr
);
2582 static void folderview_search_cb(GtkAction
*action
, gpointer data
)
2584 FolderView
*folderview
= (FolderView
*)data
;
2585 summary_search(folderview
->summaryview
);
2588 static void folderview_startup_folder_cb(GtkAction
*action
, gpointer data
)
2590 FolderView
*folderview
= (FolderView
*)data
;
2593 if (!folderview
->selected
) return;
2595 item
= folderview_get_selected_item(folderview
);
2597 prefs_common
.goto_last_folder_on_startup
= FALSE
;
2598 prefs_common
.startup_folder
= folder_item_get_identifier(item
);
2599 prefs_common
.goto_folder_on_startup
= prefs_common
.startup_folder
? TRUE
: FALSE
;
2602 static void folderview_run_processing_cb(GtkAction
*action
, gpointer data
)
2604 FolderView
*folderview
= (FolderView
*)data
;
2607 if (!folderview
->selected
) return;
2609 item
= folderview_get_selected_item(folderview
);
2611 folderview_run_processing(item
);
2614 void folderview_run_processing(FolderItem
*item
)
2616 cm_return_if_fail(item
!= NULL
);
2617 cm_return_if_fail(item
->folder
!= NULL
);
2619 item
->processing_pending
= TRUE
;
2620 folder_item_apply_processing(item
);
2621 item
->processing_pending
= FALSE
;
2624 static void folderview_property_cb(GtkAction
*action
, gpointer data
)
2626 FolderView
*folderview
= (FolderView
*)data
;
2629 if (!folderview
->selected
) return;
2631 item
= folderview_get_selected_item(folderview
);
2632 cm_return_if_fail(item
!= NULL
);
2633 cm_return_if_fail(item
->folder
!= NULL
);
2635 prefs_folder_item_open(item
);
2638 static void folderview_recollapse_nodes(FolderView
*folderview
, GtkCMCTreeNode
*node
)
2640 GSList
*list
= NULL
;
2641 GSList
*done
= NULL
;
2642 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
2644 for (list
= folderview
->nodes_to_recollapse
; list
!= NULL
; list
= g_slist_next(list
)) {
2645 if (!gtkut_ctree_node_is_parent(GTK_CMCTREE_NODE(list
->data
), node
)
2646 && list
->data
!= node
) {
2647 gtk_cmctree_collapse(ctree
, GTK_CMCTREE_NODE(list
->data
));
2648 done
= g_slist_append(done
, GTK_CMCTREE_NODE(list
->data
));
2651 for (list
= done
; list
!= NULL
; list
= g_slist_next(list
)) {
2652 folderview
->nodes_to_recollapse
= g_slist_remove(folderview
->nodes_to_recollapse
,
2658 void folderview_move_folder(FolderView
*folderview
, FolderItem
*from_folder
,
2659 FolderItem
*to_folder
, gboolean copy
)
2661 FolderItem
*new_folder
= NULL
;
2665 cm_return_if_fail(folderview
!= NULL
);
2666 cm_return_if_fail(from_folder
!= NULL
);
2667 cm_return_if_fail(to_folder
!= NULL
);
2669 if (prefs_common
.warn_dnd
) {
2670 buf
= g_strdup_printf(copy
? _("Do you really want to copy folder '%s' in '%s'?"):
2671 _("Do you really want to make folder '%s' a subfolder of '%s'?"),
2672 from_folder
->name
, to_folder
->name
);
2673 status
= alertpanel_full(copy
? _("Copy folder"):_("Move folder"), buf
,
2674 NULL
, _("_No"), NULL
, _("_Yes"), NULL
, NULL
,
2675 ALERTFOCUS_FIRST
, TRUE
, NULL
, ALERT_QUESTION
);
2678 if ((status
& ~G_ALERTDISABLE
) != G_ALERTALTERNATE
)
2680 else if (status
& G_ALERTDISABLE
)
2681 prefs_common
.warn_dnd
= FALSE
;
2684 buf
= g_strdup_printf(copy
? _("Copying %s to %s..."):_("Moving %s to %s..."),
2685 from_folder
->name
, to_folder
->name
);
2686 STATUSBAR_PUSH(folderview
->mainwin
, buf
);
2688 summary_clear_all(folderview
->summaryview
);
2689 folderview
->opened
= NULL
;
2690 folderview
->selected
= NULL
;
2691 gtk_widget_set_sensitive(GTK_WIDGET(folderview
->ctree
), FALSE
);
2693 main_window_cursor_wait(folderview
->mainwin
);
2695 statusbar_verbosity_set(FALSE
);
2696 folder_item_update_freeze();
2697 gtk_cmclist_freeze(GTK_CMCLIST(folderview
->ctree
));
2698 if ((status
= folder_item_move_to(from_folder
, to_folder
, &new_folder
, copy
)) == F_MOVE_OK
) {
2699 statusbar_verbosity_set(FALSE
);
2700 main_window_cursor_normal(folderview
->mainwin
);
2701 STATUSBAR_POP(folderview
->mainwin
);
2702 folder_item_update_thaw();
2703 folder_item_update_recursive(new_folder
, F_ITEM_UPDATE_MSGCNT
);
2705 folderview_sort_folders(folderview
,
2706 gtk_cmctree_find_by_row_data(GTK_CMCTREE(folderview
->ctree
),
2707 NULL
, to_folder
), new_folder
->folder
);
2708 folderview_select(folderview
, new_folder
);
2709 gtk_cmclist_thaw(GTK_CMCLIST(folderview
->ctree
));
2711 statusbar_verbosity_set(FALSE
);
2712 main_window_cursor_normal(folderview
->mainwin
);
2713 STATUSBAR_POP(folderview
->mainwin
);
2714 gtk_cmclist_thaw(GTK_CMCLIST(folderview
->ctree
));
2715 folder_item_update_thaw();
2717 case F_MOVE_FAILED_DEST_IS_PARENT
:
2718 alertpanel_error(_("Source and destination are the same."));
2720 case F_MOVE_FAILED_DEST_IS_CHILD
:
2721 alertpanel_error(copy
? _("Can't copy a folder to one of its children."):
2722 _("Can't move a folder to one of its children."));
2724 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX
:
2725 alertpanel_error(_("A folder cannot be moved between different mailboxes."));
2728 alertpanel_error(copy
? _("Copy failed!"):_("Move failed!"));
2733 gtk_widget_set_sensitive(GTK_WIDGET(folderview
->ctree
), TRUE
);
2736 static gint
folderview_clist_compare(GtkCMCList
*clist
,
2737 gconstpointer ptr1
, gconstpointer ptr2
)
2739 FolderItem
*item1
= ((GtkCMCListRow
*)ptr1
)->data
;
2740 FolderItem
*item2
= ((GtkCMCListRow
*)ptr2
)->data
;
2742 if (item1
->order
> 0 && item2
->order
> 0) // if we have an order item, use it
2744 return item1
->order
- item2
->order
;
2747 // if only one folder has an order it comes first
2748 if (item1
->order
> 0)
2752 if (item2
->order
> 0)
2758 return (item2
->name
!= NULL
);
2762 return g_utf8_collate(item1
->name
, item2
->name
);
2765 static void folderview_processing_cb(GtkAction
*action
, gpointer data
)
2767 FolderView
*folderview
= (FolderView
*)data
;
2771 if (!folderview
->selected
) return;
2773 item
= folderview_get_selected_item(folderview
);
2774 cm_return_if_fail(item
!= NULL
);
2775 cm_return_if_fail(item
->folder
!= NULL
);
2777 id
= folder_item_get_identifier(item
);
2778 title
= g_strdup_printf (_("Processing configuration for folder %s"), id
);
2781 prefs_filtering_open(&item
->prefs
->processing
, title
,
2782 MANUAL_ANCHOR_PROCESSING
, NULL
, NULL
, FALSE
);
2786 void folderview_set_target_folder_color(GdkRGBA color_op
)
2789 FolderView
*folderview
;
2791 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
) {
2792 folderview
= (FolderView
*)list
->data
;
2793 folderview
->color_op
= color_op
;
2797 static gchar
*last_smallfont
= NULL
;
2798 static gchar
*last_normalfont
= NULL
;
2799 static gchar
*last_boldfont
= NULL
;
2800 static gboolean last_derive
= 0;
2802 void folderview_reinit_fonts(FolderView
*folderview
)
2805 g_free(last_smallfont
);
2806 last_smallfont
= NULL
;
2807 g_free(last_normalfont
);
2808 last_normalfont
= NULL
;
2809 g_free(last_boldfont
);
2810 last_boldfont
= NULL
;
2813 void folderview_reflect_prefs(void)
2815 gboolean update_font
= FALSE
;
2816 FolderView
*folderview
= mainwindow_get_mainwindow()->folderview
;
2817 FolderItem
*item
= folderview_get_selected_item(folderview
);
2818 GtkAdjustment
*pos
= gtk_scrolled_window_get_vadjustment(
2819 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
2820 gint height
= gtk_adjustment_get_value(pos
);
2822 folderview
->color_new
= prefs_common
.color
[COL_NEW
];
2823 folderview
->color_op
= prefs_common
.color
[COL_TGT_FOLDER
];
2825 if (!last_smallfont
|| strcmp(last_smallfont
, SMALL_FONT
) ||
2826 !last_normalfont
|| strcmp(last_normalfont
, NORMAL_FONT
) ||
2827 !last_boldfont
|| strcmp(last_boldfont
, BOLD_FONT
) ||
2828 last_derive
!= prefs_common
.derive_from_normal_font
)
2834 g_free(last_smallfont
);
2835 last_smallfont
= g_strdup(SMALL_FONT
);
2836 g_free(last_normalfont
);
2837 last_normalfont
= g_strdup(NORMAL_FONT
);
2838 g_free(last_boldfont
);
2839 last_boldfont
= g_strdup(BOLD_FONT
);
2840 last_derive
= prefs_common
.derive_from_normal_font
;
2842 folderview_set_fonts(folderview
);
2844 gtk_cmclist_freeze(GTK_CMCLIST(folderview
->ctree
));
2845 folderview_column_set_titles(folderview
);
2846 folderview_set_all();
2848 g_signal_handlers_block_by_func
2849 (G_OBJECT(folderview
->ctree
),
2850 G_CALLBACK(folderview_selected
), folderview
);
2853 GtkCMCTreeNode
*node
= gtk_cmctree_find_by_row_data(
2854 GTK_CMCTREE(folderview
->ctree
), NULL
, item
);
2856 folderview_select(folderview
, item
);
2857 folderview
->open_folder
= FALSE
;
2858 folderview
->selected
= node
;
2861 g_signal_handlers_unblock_by_func
2862 (G_OBJECT(folderview
->ctree
),
2863 G_CALLBACK(folderview_selected
), folderview
);
2865 pos
= gtk_scrolled_window_get_vadjustment(
2866 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
2867 gtk_adjustment_set_value(pos
, height
);
2868 gtk_cmclist_thaw(GTK_CMCLIST(folderview
->ctree
));
2871 static void drag_state_stop(FolderView
*folderview
)
2873 if (folderview
->drag_timer_id
)
2874 g_source_remove(folderview
->drag_timer_id
);
2875 folderview
->drag_timer_id
= 0;
2876 folderview
->drag_node
= NULL
;
2879 static gboolean
folderview_defer_expand(FolderView
*folderview
)
2881 if (folderview
->drag_node
) {
2882 folderview_recollapse_nodes(folderview
, folderview
->drag_node
);
2883 if (folderview
->drag_item
->collapsed
) {
2884 gtk_cmctree_expand(GTK_CMCTREE(folderview
->ctree
), folderview
->drag_node
);
2885 folderview
->nodes_to_recollapse
= g_slist_append
2886 (folderview
->nodes_to_recollapse
, folderview
->drag_node
);
2889 folderview
->drag_item
= NULL
;
2890 folderview
->drag_timer_id
= 0;
2894 static void drag_state_start(FolderView
*folderview
, GtkCMCTreeNode
*node
, FolderItem
*item
)
2896 /* the idea is that we call drag_state_start() whenever we want expansion to
2897 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2898 * we need to call drag_state_stop() */
2899 drag_state_stop(folderview
);
2900 /* request expansion */
2901 if (0 != (folderview
->drag_timer_id
= g_timeout_add
2902 (prefs_common
.hover_timeout
,
2903 (GSourceFunc
)folderview_defer_expand
,
2905 folderview
->drag_node
= node
;
2906 folderview
->drag_item
= item
;
2909 #ifndef GENERIC_UMPC
2910 static void folderview_start_drag(GtkWidget
*widget
, gint button
, GdkEvent
*event
,
2911 FolderView
*folderview
)
2913 GdkDragContext
*context
;
2915 cm_return_if_fail(folderview
!= NULL
);
2916 if (folderview
->selected
== NULL
) return;
2917 if (folderview
->nodes_to_recollapse
)
2918 g_slist_free(folderview
->nodes_to_recollapse
);
2919 folderview
->nodes_to_recollapse
= NULL
;
2920 context
= gtk_drag_begin_with_coordinates(widget
, folderview
->target_list
,
2921 GDK_ACTION_MOVE
|GDK_ACTION_COPY
|GDK_ACTION_DEFAULT
, button
, event
,
2923 gtk_drag_set_icon_default(context
);
2926 static void folderview_drag_data_get(GtkWidget
*widget
,
2927 GdkDragContext
*drag_context
,
2928 GtkSelectionData
*selection_data
,
2931 FolderView
*folderview
)
2935 if (info
== TARGET_DUMMY
) {
2936 sel
= GTK_CMCLIST(folderview
->ctree
)->selection
;
2940 item
= gtk_cmctree_node_get_row_data
2941 (GTK_CMCTREE(folderview
->ctree
),
2942 GTK_CMCTREE_NODE(sel
->data
));
2944 gchar
*source
= NULL
;
2945 gchar
*name
= folder_item_get_identifier(item
);
2946 source
= g_strdup_printf ("FROM_OTHER_FOLDER%s", name
);
2948 gtk_selection_data_set(selection_data
,
2949 gtk_selection_data_get_target(selection_data
), 8,
2950 source
, strlen(source
));
2953 g_warning("unknown info %d", info
);
2957 static gboolean
folderview_update_folder(gpointer source
, gpointer userdata
)
2959 FolderUpdateData
*hookdata
;
2960 FolderView
*folderview
;
2964 folderview
= (FolderView
*) userdata
;
2965 cm_return_val_if_fail(hookdata
!= NULL
, FALSE
);
2966 cm_return_val_if_fail(folderview
!= NULL
, FALSE
);
2968 ctree
= folderview
->ctree
;
2969 cm_return_val_if_fail(ctree
!= NULL
, FALSE
);
2971 if (hookdata
->update_flags
& FOLDER_ADD_FOLDERITEM
)
2972 folderview_create_folder_node(folderview
, hookdata
->item
);
2973 else if (hookdata
->update_flags
& FOLDER_RENAME_FOLDERITEM
) {
2974 GtkCMCTreeNode
*node
= gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree
),
2975 NULL
, folder_item_parent(hookdata
->item
));
2976 folderview_sort_folders(folderview
, node
, hookdata
->folder
);
2977 } else if (hookdata
->update_flags
& FOLDER_REMOVE_FOLDERITEM
) {
2978 GtkCMCTreeNode
*node
;
2980 node
= gtk_cmctree_find_by_row_data(GTK_CMCTREE(ctree
), NULL
, hookdata
->item
);
2982 gtk_cmctree_remove_node(GTK_CMCTREE(ctree
), node
);
2983 if (folderview
->selected
== node
)
2984 folderview
->selected
= NULL
;
2985 if (folderview
->opened
== node
)
2986 folderview
->opened
= NULL
;
2988 } else if (hookdata
->update_flags
& FOLDER_MOVE_FOLDERITEM
) {
2989 /* do nothing, it's done by the ADD and REMOVE) */
2990 } else if (hookdata
->update_flags
& (FOLDER_TREE_CHANGED
| FOLDER_ADD_FOLDER
| FOLDER_REMOVE_FOLDER
))
2991 folderview_set(folderview
);
2996 static gboolean
folderview_dnd_scroll_cb(gpointer data
)
2998 FolderView
*folderview
= (FolderView
*)data
;
2999 GtkAdjustment
*pos
= gtk_scrolled_window_get_vadjustment(
3000 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
3001 gint new_val
= (int)gtk_adjustment_get_value(pos
) + folderview
->scroll_value
;
3002 gint max
= (int)gtk_adjustment_get_upper(pos
) -
3003 (int)gtk_adjustment_get_page_size(pos
);
3005 if (folderview
->scroll_value
== 0) {
3006 folderview
->scroll_timeout_id
= 0;
3010 if (folderview
->scroll_value
> 0 && new_val
> max
) {
3012 } else if (folderview
->scroll_value
< 0 && new_val
< 0) {
3015 gtk_adjustment_set_value(pos
, new_val
);
3020 static gboolean
folderview_drag_motion_cb(GtkWidget
*widget
,
3021 GdkDragContext
*context
,
3025 FolderView
*folderview
)
3028 FolderItem
*item
= NULL
, *src_item
= NULL
;
3029 GtkCMCTreeNode
*node
= NULL
;
3030 gboolean acceptable
= FALSE
;
3031 GtkAdjustment
*pos
= gtk_scrolled_window_get_vadjustment(
3032 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
3033 int height
= (int)gtk_adjustment_get_page_size(pos
);
3034 int total_height
= (int)gtk_adjustment_get_upper(pos
);
3035 int vpos
= (int)gtk_adjustment_get_value(pos
);
3036 int offset
= prefs_common
.show_col_headers
? 24:0;
3039 if (gtk_cmclist_get_selection_info
3040 (GTK_CMCLIST(widget
), x
- offset
, y
- offset
, &row
, &column
)) {
3041 GtkWidget
*srcwidget
;
3043 if (y
> height
- (48 - offset
) && height
+ vpos
< total_height
) {
3044 dist
= -(height
- (48 - offset
) - y
);
3045 folderview
->scroll_value
= 1.41f
* (1+(dist
/ 6));
3046 } else if (y
< 72 - (24 - offset
) && y
>= 0) {
3047 dist
= 72 - (24 - offset
) - y
;
3048 folderview
->scroll_value
= -1.41f
* (1+(dist
/ 6));
3050 folderview
->scroll_value
= 0;
3052 if (folderview
->scroll_value
!= 0 && folderview
->scroll_timeout_id
== 0) {
3053 folderview
->scroll_timeout_id
=
3054 g_timeout_add(30, folderview_dnd_scroll_cb
,
3058 node
= gtk_cmctree_node_nth(GTK_CMCTREE(widget
), row
);
3059 item
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget
), node
);
3060 src_item
= folderview
->summaryview
->folder_item
;
3062 srcwidget
= gtk_drag_get_source_widget(context
);
3063 if (srcwidget
== summary_get_main_widget(folderview
->summaryview
)) {
3064 /* comes from summaryview */
3065 /* we are copying messages, so only accept folder items that are not
3066 the source item, are no root items and can copy messages */
3067 if (item
&& item
->folder
&& folder_item_parent(item
) != NULL
&& src_item
&&
3068 src_item
!= item
&& FOLDER_CLASS(item
->folder
)->copy_msg
!= NULL
&&
3069 FOLDER_TYPE(item
->folder
) != F_UNKNOWN
)
3071 } else if (srcwidget
== folderview
->ctree
) {
3072 /* comes from folderview */
3073 /* we are moving folder items, only accept folders that are not
3074 the source items and can copy messages and create folder items */
3075 if (item
&& item
->folder
&& src_item
&& src_item
!= item
&&
3076 FOLDER_CLASS(item
->folder
)->copy_msg
!= NULL
&&
3077 FOLDER_CLASS(item
->folder
)->create_folder
!= NULL
&&
3078 ((FOLDER_TYPE(item
->folder
) != F_UNKNOWN
&& FOLDER_TYPE(src_item
->folder
) != F_UNKNOWN
)
3079 || item
->folder
== src_item
->folder
))
3082 /* comes from another app */
3083 /* we are adding messages, so only accept folder items that are
3084 no root items and can copy messages */
3085 if (item
&& item
->folder
&& folder_item_parent(item
) != NULL
3086 && FOLDER_CLASS(item
->folder
)->add_msg
!= NULL
&&
3087 FOLDER_TYPE(item
->folder
) != F_UNKNOWN
)
3092 if (acceptable
|| (src_item
&& src_item
== item
))
3093 drag_state_start(folderview
, node
, item
);
3096 g_signal_handlers_block_by_func
3098 G_CALLBACK(folderview_selected
), folderview
);
3099 gtk_cmctree_select(GTK_CMCTREE(widget
), node
);
3100 g_signal_handlers_unblock_by_func
3102 G_CALLBACK(folderview_selected
), folderview
);
3103 gdk_drag_status(context
,
3104 (gdk_drag_context_get_actions(context
) == GDK_ACTION_COPY
?
3105 GDK_ACTION_COPY
: GDK_ACTION_MOVE
) , time
);
3107 if (folderview
->opened
)
3108 gtk_cmctree_select(GTK_CMCTREE(widget
), folderview
->opened
);
3109 gdk_drag_status(context
, 0, time
);
3115 static void folderview_drag_leave_cb(GtkWidget
*widget
,
3116 GdkDragContext
*context
,
3118 FolderView
*folderview
)
3120 drag_state_stop(folderview
);
3121 folderview
->scroll_value
= 0;
3122 gtk_cmctree_select(GTK_CMCTREE(widget
), folderview
->opened
);
3125 static void free_info (gpointer stuff
, gpointer data
)
3130 void folderview_finish_dnd(const gchar
*data
, GdkDragContext
*drag_context
,
3131 guint time
, FolderItem
*item
)
3134 GSList
*msglist
= NULL
;
3135 list
= uri_list_extract_filenames(data
);
3136 if (!(item
&& item
->folder
&& folder_item_parent(item
) != NULL
3137 && FOLDER_CLASS(item
->folder
)->add_msg
!= NULL
))
3139 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3140 debug_print("item doesn't fit\n");
3144 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3145 debug_print("list is empty\n");
3148 for (tmp
= list
; tmp
!= NULL
; tmp
= tmp
->next
) {
3149 MsgFileInfo
*info
= NULL
;
3151 if (file_is_email((gchar
*)tmp
->data
)) {
3152 info
= g_new0(MsgFileInfo
, 1);
3153 info
->msginfo
= NULL
;
3154 info
->file
= (gchar
*)tmp
->data
;
3155 msglist
= g_slist_prepend(msglist
, info
);
3156 debug_print("file is a mail\n");
3158 debug_print("file isn't a mail\n");
3162 msglist
= g_slist_reverse(msglist
);
3163 folder_item_add_msgs(item
, msglist
, FALSE
);
3164 g_slist_foreach(msglist
, free_info
, NULL
);
3165 g_slist_free(msglist
);
3166 gtk_drag_finish(drag_context
, TRUE
, FALSE
, time
);
3168 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3170 list_free_strings_full(list
);
3173 static void folderview_drag_received_cb(GtkWidget
*widget
,
3174 GdkDragContext
*drag_context
,
3177 GtkSelectionData
*data
,
3180 FolderView
*folderview
)
3183 FolderItem
*item
= NULL
, *src_item
;
3184 GtkCMCTreeNode
*node
;
3185 int offset
= prefs_common
.show_col_headers
? 24:0;
3187 folderview
->scroll_value
= 0;
3189 if (info
== TARGET_DUMMY
) {
3190 drag_state_stop(folderview
);
3191 const gchar
*ddata
= (const gchar
*)gtk_selection_data_get_data(data
);
3192 if ((gchar
*)strstr(ddata
, "FROM_OTHER_FOLDER") != ddata
) {
3193 /* comes from summaryview */
3194 if (gtk_cmclist_get_selection_info
3195 (GTK_CMCLIST(widget
), x
- offset
, y
- offset
, &row
, &column
) == 0)
3198 node
= gtk_cmctree_node_nth(GTK_CMCTREE(widget
), row
);
3199 item
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget
), node
);
3200 src_item
= folderview
->summaryview
->folder_item
;
3202 if (item
&& item
->no_select
) {
3203 alertpanel_error(_("The destination folder can only be used to "
3204 "store subfolders."));
3207 /* re-check (due to acceptable possibly set for folder moves */
3208 if (!(item
&& item
->folder
&& item
->path
&& !item
->no_select
&&
3209 src_item
&& src_item
!= item
&& FOLDER_CLASS(item
->folder
)->copy_msg
!= NULL
)) {
3213 switch (gdk_drag_context_get_selected_action(drag_context
)) {
3214 case GDK_ACTION_COPY
:
3215 summary_copy_selected_to(folderview
->summaryview
, item
);
3216 gtk_drag_finish(drag_context
, TRUE
, FALSE
, time
);
3218 case GDK_ACTION_MOVE
:
3219 case GDK_ACTION_DEFAULT
:
3221 if (FOLDER_CLASS(src_item
->folder
)->remove_msg
== NULL
)
3222 summary_copy_selected_to(folderview
->summaryview
, item
);
3224 summary_move_selected_to(folderview
->summaryview
, item
);
3225 gtk_drag_finish(drag_context
, TRUE
, TRUE
, time
);
3228 /* comes from folderview */
3230 gboolean folder_is_normal
= TRUE
;
3231 gboolean copy
= (GDK_ACTION_COPY
==
3232 gdk_drag_context_get_selected_action(drag_context
));
3234 source
= (char *)gtk_selection_data_get_data(data
) + 17;
3235 if (gtk_cmclist_get_selection_info
3236 (GTK_CMCLIST(widget
), x
- offset
, y
- offset
, &row
, &column
) == 0
3238 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3241 node
= gtk_cmctree_node_nth(GTK_CMCTREE(widget
), row
);
3242 item
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget
), node
);
3243 src_item
= folder_find_item_from_identifier(source
);
3247 src_item
->stype
== F_NORMAL
&&
3248 !folder_has_parent_of_type(src_item
, F_OUTBOX
) &&
3249 !folder_has_parent_of_type(src_item
, F_DRAFT
) &&
3250 !folder_has_parent_of_type(src_item
, F_QUEUE
) &&
3251 !folder_has_parent_of_type(src_item
, F_TRASH
);
3252 if (!item
|| !src_item
|| !folder_is_normal
) {
3253 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3257 folderview_move_folder(folderview
, src_item
, item
, copy
);
3258 gtk_drag_finish(drag_context
, TRUE
, TRUE
, time
);
3260 folderview
->nodes_to_recollapse
= NULL
;
3261 } else if (info
== TARGET_MAIL_URI_LIST
) {
3262 if (gtk_cmclist_get_selection_info
3263 (GTK_CMCLIST(widget
), x
- offset
, y
- offset
, &row
, &column
) == 0)
3266 node
= gtk_cmctree_node_nth(GTK_CMCTREE(widget
), row
);
3268 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3269 debug_print("no node\n");
3272 item
= gtk_cmctree_node_get_row_data(GTK_CMCTREE(widget
), node
);
3274 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
3275 debug_print("no item\n");
3278 folderview_finish_dnd(gtk_selection_data_get_data(data
),
3279 drag_context
, time
, item
);
3283 static void folderview_drag_end_cb(GtkWidget
*widget
,
3284 GdkDragContext
*drag_context
,
3285 FolderView
*folderview
)
3287 drag_state_stop(folderview
);
3288 folderview
->scroll_value
= 0;
3289 g_slist_free(folderview
->nodes_to_recollapse
);
3290 folderview
->nodes_to_recollapse
= NULL
;
3293 void folderview_register_popup(FolderViewPopup
*fpopup
)
3297 for (folderviews
= folderview_list
; folderviews
!= NULL
; folderviews
= g_list_next(folderviews
)) {
3298 FolderView
*folderview
= folderviews
->data
;
3299 GtkActionGroup
*factory
;
3301 factory
= create_action_group(folderview
, fpopup
);
3302 g_hash_table_insert(folderview
->popups
, fpopup
->klass
, factory
);
3304 g_hash_table_insert(folderview_popups
, fpopup
->klass
, fpopup
);
3307 void folderview_unregister_popup(FolderViewPopup
*fpopup
)
3312 for (folderviews
= folderview_list
; folderviews
!= NULL
; folderviews
= g_list_next(folderviews
)) {
3313 FolderView
*folderview
= folderviews
->data
;
3315 g_hash_table_remove(folderview
->popups
, fpopup
->klass
);
3317 g_hash_table_remove(folderview_popups
, fpopup
->klass
);
3320 void folderview_remove_item(FolderView
*folderview
, FolderItem
*item
)
3322 g_return_if_fail(folderview
!= NULL
);
3323 g_return_if_fail(item
!= NULL
);
3325 GtkCMCTree
*ctree
= GTK_CMCTREE(folderview
->ctree
);
3326 g_return_if_fail(ctree
!= NULL
);
3328 GtkCMCTreeNode
*node
=
3329 gtk_cmctree_find_by_row_data(ctree
, NULL
, item
);
3330 g_return_if_fail(node
!= NULL
);
3332 gtk_cmctree_remove_node(ctree
, node
);
3335 void folderview_freeze(FolderView
*folderview
)
3338 gtk_cmclist_freeze(GTK_CMCLIST(folderview
->ctree
));
3341 void folderview_thaw(FolderView
*folderview
)
3344 gtk_cmclist_thaw(GTK_CMCLIST(folderview
->ctree
));
3347 void folderview_grab_focus(FolderView
*folderview
)
3350 gtk_widget_grab_focus(folderview
->ctree
);
3353 static void folderview_header_set_displayed_columns_cb(GtkAction
*gaction
,
3356 prefs_folder_column_open();
3359 static gboolean
folderview_header_button_pressed(GtkWidget
*widget
,
3363 GdkEventButton
*event
= (GdkEventButton
*)_event
;
3364 FolderView
*folderview
= (FolderView
*)user_data
;
3366 cm_return_val_if_fail(folderview
!= NULL
, FALSE
);
3368 /* Only handle single button presses. */
3369 if (event
->type
== GDK_2BUTTON_PRESS
||
3370 event
->type
== GDK_3BUTTON_PRESS
)
3373 /* Handle right-click for context menu */
3374 if (event
->button
== 3) {
3375 gtk_menu_popup_at_pointer(GTK_MENU(folderview
->headerpopupmenu
), NULL
);