2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 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, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include <glib/gi18n.h>
24 #include <gdk/gdkkeysyms.h>
25 #include <gtk/gtkwidget.h>
26 #include <gtk/gtkscrolledwindow.h>
27 #include <gtk/gtkctree.h>
28 #include <gtk/gtkcontainer.h>
29 #include <gtk/gtkclist.h>
30 #include <gtk/gtkstyle.h>
31 #include <gtk/gtksignal.h>
32 #include <gtk/gtkmain.h>
33 #include <gtk/gtkstatusbar.h>
34 #include <gtk/gtkmenu.h>
35 #include <gtk/gtkmenuitem.h>
36 #include <gtk/gtkitemfactory.h>
42 #include "mainwindow.h"
43 #include "folderview.h"
44 #include "summaryview.h"
45 #include "summary_search.h"
46 #include "inputdialog.h"
47 #include "manage_window.h"
48 #include "alertpanel.h"
50 #include "stock_pixmap.h"
54 #include "prefs_common.h"
55 #include "prefs_account.h"
56 #include "prefs_filtering.h"
57 #include "prefs_folder_item.h"
60 #include "foldersel.h"
62 #include "statusbar.h"
64 #include "folderutils.h"
65 #include "partial_download.h"
66 #include "prefs_folder_column.h"
67 #include "filtering.h"
68 #include "quicksearch.h"
73 #define COL_FOLDER_WIDTH 150
74 #define COL_NUM_WIDTH 32
76 static GList
*folderview_list
= NULL
;
78 static GtkStyle
*normal_style
;
79 static GtkStyle
*normal_color_style
;
80 static GtkStyle
*bold_style
;
81 static GtkStyle
*bold_color_style
;
82 static GtkStyle
*bold_tgtfold_style
;
84 static GdkPixmap
*inboxxpm
;
85 static GdkBitmap
*inboxxpmmask
;
86 static GdkPixmap
*inboxhrmxpm
;
87 static GdkBitmap
*inboxhrmxpmmask
;
88 static GdkPixmap
*inboxopenxpm
;
89 static GdkBitmap
*inboxopenxpmmask
;
90 static GdkPixmap
*inboxopenhrmxpm
;
91 static GdkBitmap
*inboxopenhrmxpmmask
;
92 static GdkPixmap
*outboxxpm
;
93 static GdkBitmap
*outboxxpmmask
;
94 static GdkPixmap
*outboxhrmxpm
;
95 static GdkBitmap
*outboxhrmxpmmask
;
96 static GdkPixmap
*outboxopenxpm
;
97 static GdkBitmap
*outboxopenxpmmask
;
98 static GdkPixmap
*outboxopenhrmxpm
;
99 static GdkBitmap
*outboxopenhrmxpmmask
;
100 static GdkPixmap
*folderxpm
;
101 static GdkBitmap
*folderxpmmask
;
102 static GdkPixmap
*folderhrmxpm
;
103 static GdkBitmap
*folderhrmxpmmask
;
104 static GdkPixmap
*folderopenxpm
;
105 static GdkBitmap
*folderopenxpmmask
;
106 static GdkPixmap
*folderopenhrmxpm
;
107 static GdkBitmap
*folderopenhrmxpmmask
;
108 static GdkPixmap
*trashopenxpm
;
109 static GdkBitmap
*trashopenxpmmask
;
110 static GdkPixmap
*trashopenhrmxpm
;
111 static GdkBitmap
*trashopenhrmxpmmask
;
112 static GdkPixmap
*trashxpm
;
113 static GdkBitmap
*trashxpmmask
;
114 static GdkPixmap
*trashhrmxpm
;
115 static GdkBitmap
*trashhrmxpmmask
;
116 static GdkPixmap
*queuexpm
;
117 static GdkBitmap
*queuexpmmask
;
118 static GdkPixmap
*queuehrmxpm
;
119 static GdkBitmap
*queuehrmxpmmask
;
120 static GdkPixmap
*queueopenxpm
;
121 static GdkBitmap
*queueopenxpmmask
;
122 static GdkPixmap
*queueopenhrmxpm
;
123 static GdkBitmap
*queueopenhrmxpmmask
;
124 static GdkPixmap
*draftsxpm
;
125 static GdkBitmap
*draftsxpmmask
;
126 static GdkPixmap
*draftsopenxpm
;
127 static GdkBitmap
*draftsopenxpmmask
;
128 static GdkPixmap
*noselectxpm
;
129 static GdkBitmap
*noselectxpmmask
;
131 static GdkPixmap
*m_inboxxpm
;
132 static GdkBitmap
*m_inboxxpmmask
;
133 static GdkPixmap
*m_inboxhrmxpm
;
134 static GdkBitmap
*m_inboxhrmxpmmask
;
135 static GdkPixmap
*m_inboxopenxpm
;
136 static GdkBitmap
*m_inboxopenxpmmask
;
137 static GdkPixmap
*m_inboxopenhrmxpm
;
138 static GdkBitmap
*m_inboxopenhrmxpmmask
;
139 static GdkPixmap
*m_outboxxpm
;
140 static GdkBitmap
*m_outboxxpmmask
;
141 static GdkPixmap
*m_outboxhrmxpm
;
142 static GdkBitmap
*m_outboxhrmxpmmask
;
143 static GdkPixmap
*m_outboxopenxpm
;
144 static GdkBitmap
*m_outboxopenxpmmask
;
145 static GdkPixmap
*m_outboxopenhrmxpm
;
146 static GdkBitmap
*m_outboxopenhrmxpmmask
;
147 static GdkPixmap
*m_folderxpm
;
148 static GdkBitmap
*m_folderxpmmask
;
149 static GdkPixmap
*m_folderhrmxpm
;
150 static GdkBitmap
*m_folderhrmxpmmask
;
151 static GdkPixmap
*m_folderopenxpm
;
152 static GdkBitmap
*m_folderopenxpmmask
;
153 static GdkPixmap
*m_folderopenhrmxpm
;
154 static GdkBitmap
*m_folderopenhrmxpmmask
;
155 static GdkPixmap
*m_trashopenxpm
;
156 static GdkBitmap
*m_trashopenxpmmask
;
157 static GdkPixmap
*m_trashopenhrmxpm
;
158 static GdkBitmap
*m_trashopenhrmxpmmask
;
159 static GdkPixmap
*m_trashxpm
;
160 static GdkBitmap
*m_trashxpmmask
;
161 static GdkPixmap
*m_trashhrmxpm
;
162 static GdkBitmap
*m_trashhrmxpmmask
;
163 static GdkPixmap
*m_queuexpm
;
164 static GdkBitmap
*m_queuexpmmask
;
165 static GdkPixmap
*m_queuehrmxpm
;
166 static GdkBitmap
*m_queuehrmxpmmask
;
167 static GdkPixmap
*m_queueopenxpm
;
168 static GdkBitmap
*m_queueopenxpmmask
;
169 static GdkPixmap
*m_queueopenhrmxpm
;
170 static GdkBitmap
*m_queueopenhrmxpmmask
;
171 static GdkPixmap
*m_draftsxpm
;
172 static GdkBitmap
*m_draftsxpmmask
;
173 static GdkPixmap
*m_draftsopenxpm
;
174 static GdkBitmap
*m_draftsopenxpmmask
;
176 static GdkPixmap
*newxpm
;
177 static GdkBitmap
*newxpmmask
;
178 static GdkPixmap
*unreadxpm
;
179 static GdkBitmap
*unreadxpmmask
;
180 static GdkPixmap
*readxpm
;
181 static GdkBitmap
*readxpmmask
;
183 static void folderview_select_node (FolderView
*folderview
,
185 static void folderview_set_folders (FolderView
*folderview
);
186 static void folderview_sort_folders (FolderView
*folderview
,
189 static void folderview_append_folder (FolderView
*folderview
,
191 static void folderview_update_node (FolderView
*folderview
,
194 static gint
folderview_clist_compare (GtkCList
*clist
,
198 /* callback functions */
199 static gboolean
folderview_button_pressed (GtkWidget
*ctree
,
200 GdkEventButton
*event
,
201 FolderView
*folderview
);
202 static gboolean
folderview_button_released (GtkWidget
*ctree
,
203 GdkEventButton
*event
,
204 FolderView
*folderview
);
205 static gboolean
folderview_key_pressed (GtkWidget
*widget
,
207 FolderView
*folderview
);
208 static void folderview_selected (GtkCTree
*ctree
,
211 FolderView
*folderview
);
212 static void folderview_tree_expanded (GtkCTree
*ctree
,
214 FolderView
*folderview
);
215 static void folderview_tree_collapsed (GtkCTree
*ctree
,
217 FolderView
*folderview
);
218 static void folderview_popup_close (GtkMenuShell
*menu_shell
,
219 FolderView
*folderview
);
220 static void folderview_col_resized (GtkCList
*clist
,
223 FolderView
*folderview
);
225 static void mark_all_read_cb (FolderView
*folderview
,
229 static void folderview_empty_trash_cb (FolderView
*folderview
,
233 static void folderview_send_queue_cb (FolderView
*folderview
,
237 static void folderview_search_cb (FolderView
*folderview
,
241 static void folderview_property_cb (FolderView
*folderview
,
245 static gboolean
folderview_drag_motion_cb(GtkWidget
*widget
,
246 GdkDragContext
*context
,
250 FolderView
*folderview
);
251 static void folderview_drag_leave_cb (GtkWidget
*widget
,
252 GdkDragContext
*context
,
254 FolderView
*folderview
);
255 static void folderview_drag_received_cb (GtkWidget
*widget
,
256 GdkDragContext
*drag_context
,
259 GtkSelectionData
*data
,
262 FolderView
*folderview
);
263 static void folderview_start_drag (GtkWidget
*widget
, gint button
, GdkEvent
*event
,
264 FolderView
*folderview
);
265 static void folderview_drag_data_get (GtkWidget
*widget
,
266 GdkDragContext
*drag_context
,
267 GtkSelectionData
*selection_data
,
270 FolderView
*folderview
);
271 static void folderview_drag_end_cb (GtkWidget
*widget
,
272 GdkDragContext
*drag_context
,
273 FolderView
*folderview
);
275 static void folderview_create_folder_node (FolderView
*folderview
,
277 static gboolean
folderview_update_folder (gpointer source
,
279 static gboolean
folderview_update_item_claws (gpointer source
,
281 static void folderview_processing_cb(FolderView
*folderview
, guint action
,
283 static void folderview_set_sens_and_popup_menu(FolderView
*folderview
, gint row
,
284 GdkEventButton
*event
);
286 GHashTable
*folderview_popups
;
288 static GtkItemFactoryEntry folderview_common_popup_entries
[] =
290 {N_("/Mark all re_ad"), NULL
, mark_all_read_cb
, 0, NULL
},
291 {"/---", NULL
, NULL
, 0, "<Separator>"},
292 {N_("/_Search folder..."), NULL
, folderview_search_cb
, 0, NULL
},
293 {N_("/_Properties..."), NULL
, folderview_property_cb
, 0, NULL
},
294 {N_("/Process_ing..."), NULL
, folderview_processing_cb
, 0, NULL
},
297 static GtkItemFactoryEntry folder_view_trash_popup_entries
[] = {
298 {"/------trashsep", NULL
, NULL
, 0, "<Separator>"},
299 {N_("/Empty _trash..."), NULL
, folderview_empty_trash_cb
, 0, NULL
},
302 static GtkItemFactoryEntry folder_view_queue_popup_entries
[] = {
303 {"/------queuesep", NULL
, NULL
, 0, "<Separator>"},
304 {N_("/Send _queue..."), NULL
, folderview_send_queue_cb
, 0, NULL
},
308 GtkTargetEntry folderview_drag_types
[] =
310 {"claws-mail/internal", GTK_TARGET_SAME_APP
, TARGET_DUMMY
},
311 {"text/uri-list", 0, TARGET_MAIL_URI_LIST
}
314 void folderview_initialize(void)
316 FolderViewPopup
*fpopup
;
318 GSList
*entries
= NULL
;
320 fpopup
= g_new0(FolderViewPopup
, 1);
322 n_entries
= sizeof(folderview_common_popup_entries
) /
323 sizeof(folderview_common_popup_entries
[0]);
324 for (i
= 0; i
< n_entries
; i
++)
325 entries
= g_slist_append(entries
, &folderview_common_popup_entries
[i
]);
327 fpopup
->klass
= "common";
328 fpopup
->path
= "<CommonFolder>";
329 fpopup
->entries
= entries
;
330 fpopup
->set_sensitivity
= NULL
;
332 folderview_popups
= g_hash_table_new(g_str_hash
, g_str_equal
);
333 g_hash_table_insert(folderview_popups
, "common", fpopup
);
336 static GtkItemFactory
*create_ifactory(FolderView
*folderview
, FolderViewPopup
*fpopup
)
339 GtkItemFactory
*factory
;
340 FolderViewPopup
*fpopup_common
;
343 factory
= gtk_item_factory_new(GTK_TYPE_MENU
, fpopup
->path
, NULL
);
344 gtk_item_factory_set_translate_func(factory
, menu_translate
,
347 for (entries
= fpopup
->entries
; entries
!= NULL
; entries
= g_slist_next(entries
))
348 gtk_item_factory_create_item(factory
, entries
->data
, folderview
, 1);
350 fpopup_common
= g_hash_table_lookup(folderview_popups
, "common");
351 if (fpopup_common
!= fpopup
)
352 for (entries
= fpopup_common
->entries
; entries
!= NULL
; entries
= g_slist_next(entries
))
353 gtk_item_factory_create_item(factory
, entries
->data
, folderview
, 1);
355 popup
= gtk_item_factory_get_widget(factory
, fpopup
->path
);
356 g_signal_connect(G_OBJECT(popup
), "selection_done",
357 G_CALLBACK(folderview_popup_close
),
363 static void create_ifactories(gpointer key
, gpointer value
, gpointer data
)
365 FolderView
*folderview
= data
;
366 FolderViewPopup
*fpopup
= value
;
367 GtkItemFactory
*factory
;
369 factory
= create_ifactory(folderview
, fpopup
);
370 g_hash_table_insert(folderview
->popups
, fpopup
->klass
, factory
);
373 static void folderview_column_set_titles(FolderView
*folderview
)
375 GtkWidget
*ctree
= folderview
->ctree
;
376 GtkWidget
*label_new
;
377 GtkWidget
*label_unread
;
378 GtkWidget
*label_total
;
380 GtkWidget
*hbox_unread
;
381 GtkWidget
*hbox_total
;
382 gint
*col_pos
= folderview
->col_pos
;
384 debug_print("setting titles...\n");
385 gtk_widget_realize(folderview
->ctree
);
386 gtk_widget_show_all(folderview
->scrolledwin
);
388 /* CLAWS: titles for "New" and "Unread" show new & unread pixmaps
389 * instead text (text overflows making them unreadable and ugly) */
390 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_NEW
,
391 &newxpm
, &newxpmmask
);
392 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_UNREAD
,
393 &unreadxpm
, &unreadxpmmask
);
394 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_READ
,
395 &readxpm
, &readxpmmask
);
397 label_new
= gtk_image_new_from_pixmap(newxpm
, newxpmmask
);
398 label_unread
= gtk_image_new_from_pixmap(unreadxpm
, unreadxpmmask
);
399 label_total
= gtk_image_new_from_pixmap(readxpm
, readxpmmask
);
401 gtk_clist_column_titles_active(GTK_CLIST(ctree
));
403 hbox_new
= gtk_hbox_new(FALSE
, 4);
404 hbox_unread
= gtk_hbox_new(FALSE
, 4);
405 hbox_total
= gtk_hbox_new(FALSE
, 4);
408 gtk_box_pack_start(GTK_BOX(hbox_new
), label_new
, TRUE
, TRUE
, 0);
409 gtk_misc_set_alignment (GTK_MISC (label_new
), 1, 0.5);
410 gtk_box_pack_start(GTK_BOX(hbox_unread
), label_unread
, TRUE
, TRUE
, 0);
411 gtk_misc_set_alignment (GTK_MISC (label_unread
), 1, 0.5);
412 gtk_box_pack_start(GTK_BOX(hbox_total
), label_total
, TRUE
, TRUE
, 0);
413 gtk_misc_set_alignment (GTK_MISC (label_total
), 1, 0.5);
415 gtk_widget_show_all(hbox_new
);
416 gtk_widget_show_all(hbox_unread
);
417 gtk_widget_show_all(hbox_total
);
419 gtk_clist_set_column_widget(GTK_CLIST(ctree
),col_pos
[F_COL_NEW
],hbox_new
);
420 gtk_clist_set_column_widget(GTK_CLIST(ctree
),col_pos
[F_COL_UNREAD
],hbox_unread
);
421 gtk_clist_set_column_widget(GTK_CLIST(ctree
),col_pos
[F_COL_TOTAL
],hbox_total
);
423 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree
), col_pos
[F_COL_NEW
], _("New"));
424 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree
), col_pos
[F_COL_UNREAD
], _("Unread"));
425 gtk_sctree_set_column_tooltip(GTK_SCTREE(ctree
), col_pos
[F_COL_TOTAL
], _("Total"));
428 static gboolean
folderview_popup_menu(GtkWidget
*widget
, gpointer data
)
430 FolderView
*folderview
= (FolderView
*)data
;
431 GdkEventButton event
;
432 if (folderview_get_selected_item(folderview
) == NULL
)
436 event
.time
= gtk_get_current_event_time();
438 folderview_set_sens_and_popup_menu(folderview
, -1,
445 static GtkWidget
*folderview_ctree_create(FolderView
*folderview
)
449 FolderColumnState
*col_state
;
450 FolderColumnType type
;
451 gchar
*titles
[N_FOLDER_COLS
];
453 GtkWidget
*scrolledwin
= folderview
->scrolledwin
;
455 debug_print("creating tree...\n");
456 memset(titles
, 0, sizeof(titles
));
458 col_state
= prefs_folder_column_get_config();
459 memset(titles
, 0, sizeof(titles
));
461 col_pos
= folderview
->col_pos
;
463 for (i
= 0; i
< N_FOLDER_COLS
; i
++) {
464 folderview
->col_state
[i
] = col_state
[i
];
465 type
= col_state
[i
].type
;
469 titles
[col_pos
[F_COL_FOLDER
]] = _("Folder");
470 titles
[col_pos
[F_COL_NEW
]] = _("New");
471 titles
[col_pos
[F_COL_UNREAD
]] = _("Unread");
472 /* TRANSLATORS: This in Number sign in American style */
473 titles
[col_pos
[F_COL_TOTAL
]] = _("#");
475 ctree
= gtk_sctree_new_with_titles(N_FOLDER_COLS
, col_pos
[F_COL_FOLDER
],
478 gtk_clist_set_selection_mode(GTK_CLIST(ctree
), GTK_SELECTION_BROWSE
);
479 gtk_clist_set_column_justification(GTK_CLIST(ctree
), col_pos
[F_COL_NEW
],
481 gtk_clist_set_column_justification(GTK_CLIST(ctree
),
482 col_pos
[F_COL_UNREAD
],
484 gtk_clist_set_column_justification(GTK_CLIST(ctree
),
485 col_pos
[F_COL_TOTAL
],
487 if (prefs_common
.enable_dotted_lines
) {
488 gtk_ctree_set_line_style(GTK_CTREE(ctree
), GTK_CTREE_LINES_DOTTED
);
489 gtk_ctree_set_expander_style(GTK_CTREE(ctree
),
490 GTK_CTREE_EXPANDER_SQUARE
);
492 gtk_ctree_set_line_style(GTK_CTREE(ctree
), GTK_CTREE_LINES_NONE
);
493 gtk_ctree_set_expander_style(GTK_CTREE(ctree
),
494 GTK_CTREE_EXPANDER_TRIANGLE
);
497 gtk_sctree_set_stripes(GTK_SCTREE(ctree
), prefs_common
.use_stripes_in_summaries
);
498 gtk_sctree_set_recursive_expand(GTK_SCTREE(ctree
), FALSE
);
500 gtk_ctree_set_indent(GTK_CTREE(ctree
), CTREE_INDENT
);
501 gtk_clist_set_compare_func(GTK_CLIST(ctree
), folderview_clist_compare
);
503 /* don't let title buttons take key focus */
504 for (i
= 0; i
< N_FOLDER_COLS
; i
++) {
505 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(ctree
)->column
[i
].button
,
507 gtk_clist_set_column_width(GTK_CLIST(ctree
), col_pos
[i
],
508 prefs_common
.folder_col_size
[i
]);
509 gtk_clist_set_column_visibility
510 (GTK_CLIST(ctree
), i
, col_state
[i
].visible
);
513 g_signal_connect(G_OBJECT(ctree
), "key_press_event",
514 G_CALLBACK(folderview_key_pressed
),
516 g_signal_connect(G_OBJECT(ctree
), "button_press_event",
517 G_CALLBACK(folderview_button_pressed
),
519 g_signal_connect(G_OBJECT(ctree
), "popup-menu",
520 G_CALLBACK(folderview_popup_menu
), folderview
);
521 g_signal_connect(G_OBJECT(ctree
), "button_release_event",
522 G_CALLBACK(folderview_button_released
),
524 g_signal_connect(G_OBJECT(ctree
), "tree_select_row",
525 G_CALLBACK(folderview_selected
), folderview
);
526 g_signal_connect(G_OBJECT(ctree
), "start_drag",
527 G_CALLBACK(folderview_start_drag
), folderview
);
528 g_signal_connect(G_OBJECT(ctree
), "drag_data_get",
529 G_CALLBACK(folderview_drag_data_get
),
532 g_signal_connect_after(G_OBJECT(ctree
), "tree_expand",
533 G_CALLBACK(folderview_tree_expanded
),
535 g_signal_connect_after(G_OBJECT(ctree
), "tree_collapse",
536 G_CALLBACK(folderview_tree_collapsed
),
539 g_signal_connect(G_OBJECT(ctree
), "resize_column",
540 G_CALLBACK(folderview_col_resized
),
544 gtk_drag_dest_set(ctree
, GTK_DEST_DEFAULT_ALL
& ~GTK_DEST_DEFAULT_HIGHLIGHT
,
545 folderview_drag_types
, 2,
546 GDK_ACTION_MOVE
| GDK_ACTION_COPY
| GDK_ACTION_DEFAULT
);
547 g_signal_connect(G_OBJECT(ctree
), "drag_motion",
548 G_CALLBACK(folderview_drag_motion_cb
),
550 g_signal_connect(G_OBJECT(ctree
), "drag_leave",
551 G_CALLBACK(folderview_drag_leave_cb
),
553 g_signal_connect(G_OBJECT(ctree
), "drag_data_received",
554 G_CALLBACK(folderview_drag_received_cb
),
556 g_signal_connect(G_OBJECT(ctree
), "drag_end",
557 G_CALLBACK(folderview_drag_end_cb
),
560 gtk_container_add(GTK_CONTAINER(scrolledwin
), ctree
);
565 void folderview_set_column_order(FolderView
*folderview
)
568 FolderItem
*item
= folderview_get_selected_item(folderview
);
569 GtkWidget
*scrolledwin
= folderview
->scrolledwin
;
571 debug_print("recreating tree...\n");
572 gtk_widget_destroy(folderview
->ctree
);
574 folderview
->ctree
= ctree
= folderview_ctree_create(folderview
);
575 gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(scrolledwin
),
576 GTK_CLIST(ctree
)->hadjustment
);
577 gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(scrolledwin
),
578 GTK_CLIST(ctree
)->vadjustment
);
579 gtk_widget_show(ctree
);
581 folderview_set(folderview
);
582 folderview_column_set_titles(folderview
);
584 folderview_select(folderview
,item
);
587 FolderView
*folderview_create(void)
589 FolderView
*folderview
;
590 GtkWidget
*scrolledwin
;
593 debug_print("Creating folder view...\n");
594 folderview
= g_new0(FolderView
, 1);
596 scrolledwin
= gtk_scrolled_window_new(NULL
, NULL
);
597 gtk_scrolled_window_set_policy
598 (GTK_SCROLLED_WINDOW(scrolledwin
),
599 GTK_POLICY_AUTOMATIC
,
600 prefs_common
.folderview_vscrollbar_policy
);
601 gtk_widget_set_size_request(scrolledwin
,
602 prefs_common
.folderview_width
,
603 prefs_common
.folderview_height
);
605 folderview
->scrolledwin
= scrolledwin
;
606 ctree
= folderview_ctree_create(folderview
);
608 /* create popup factories */
609 folderview
->popups
= g_hash_table_new(g_str_hash
, g_str_equal
);
610 g_hash_table_foreach(folderview_popups
, create_ifactories
, folderview
);
612 folderview
->ctree
= ctree
;
614 folderview
->folder_update_callback_id
=
615 hooks_register_hook(FOLDER_UPDATE_HOOKLIST
, folderview_update_folder
, (gpointer
) folderview
);
616 folderview
->folder_item_update_callback_id
=
617 hooks_register_hook(FOLDER_ITEM_UPDATE_HOOKLIST
, folderview_update_item_claws
, (gpointer
) folderview
);
619 gtk_widget_show_all(scrolledwin
);
621 folderview
->target_list
= gtk_target_list_new(folderview_drag_types
, 2);
622 folderview_list
= g_list_append(folderview_list
, folderview
);
623 folderview
->deferred_refresh_id
= -1;
628 void folderview_init(FolderView
*folderview
)
630 GtkWidget
*ctree
= folderview
->ctree
;
633 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_INBOX_CLOSE
, &inboxxpm
, &inboxxpmmask
);
634 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_INBOX_CLOSE_HRM
, &inboxhrmxpm
, &inboxhrmxpmmask
);
635 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_INBOX_OPEN
, &inboxopenxpm
, &inboxopenxpmmask
);
636 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_INBOX_OPEN_HRM
, &inboxopenhrmxpm
, &inboxopenhrmxpmmask
);
637 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_OUTBOX_CLOSE
, &outboxxpm
, &outboxxpmmask
);
638 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_OUTBOX_CLOSE_HRM
, &outboxhrmxpm
, &outboxhrmxpmmask
);
639 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_OUTBOX_OPEN
, &outboxopenxpm
, &outboxopenxpmmask
);
640 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_OUTBOX_OPEN_HRM
, &outboxopenhrmxpm
, &outboxopenhrmxpmmask
);
641 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_DIR_CLOSE
, &folderxpm
, &folderxpmmask
);
642 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_DIR_CLOSE_HRM
, &folderhrmxpm
, &folderhrmxpmmask
);
643 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_DIR_OPEN
, &folderopenxpm
, &folderopenxpmmask
);
644 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_DIR_OPEN_HRM
, &folderopenhrmxpm
, &folderopenhrmxpmmask
);
645 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_TRASH_OPEN
, &trashopenxpm
, &trashopenxpmmask
);
646 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_TRASH_OPEN_HRM
, &trashopenhrmxpm
, &trashopenhrmxpmmask
);
647 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_TRASH_CLOSE
, &trashxpm
, &trashxpmmask
);
648 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_TRASH_CLOSE_HRM
, &trashhrmxpm
, &trashhrmxpmmask
);
649 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_QUEUE_CLOSE
, &queuexpm
, &queuexpmmask
);
650 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_QUEUE_CLOSE_HRM
, &queuehrmxpm
, &queuehrmxpmmask
);
651 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_QUEUE_OPEN
, &queueopenxpm
, &queueopenxpmmask
);
652 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_QUEUE_OPEN_HRM
, &queueopenhrmxpm
, &queueopenhrmxpmmask
);
653 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_DRAFTS_CLOSE
, &draftsxpm
, &draftsxpmmask
);
654 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_DRAFTS_OPEN
, &draftsopenxpm
, &draftsopenxpmmask
);
655 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_DIR_NOSELECT
, &noselectxpm
, &noselectxpmmask
);
657 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_INBOX_CLOSE_MARK
, &m_inboxxpm
, &m_inboxxpmmask
);
658 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_INBOX_CLOSE_HRM_MARK
, &m_inboxhrmxpm
, &m_inboxhrmxpmmask
);
659 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_INBOX_OPEN_MARK
, &m_inboxopenxpm
, &m_inboxopenxpmmask
);
660 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_INBOX_OPEN_HRM_MARK
, &m_inboxopenhrmxpm
, &m_inboxopenhrmxpmmask
);
661 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_OUTBOX_CLOSE_MARK
, &m_outboxxpm
, &m_outboxxpmmask
);
662 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_OUTBOX_CLOSE_HRM_MARK
, &m_outboxhrmxpm
, &m_outboxhrmxpmmask
);
663 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_OUTBOX_OPEN_MARK
, &m_outboxopenxpm
, &m_outboxopenxpmmask
);
664 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_OUTBOX_OPEN_HRM_MARK
, &m_outboxopenhrmxpm
, &m_outboxopenhrmxpmmask
);
665 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_DIR_CLOSE_MARK
, &m_folderxpm
, &m_folderxpmmask
);
666 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_DIR_CLOSE_HRM_MARK
, &m_folderhrmxpm
, &m_folderhrmxpmmask
);
667 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_DIR_OPEN_MARK
, &m_folderopenxpm
, &m_folderopenxpmmask
);
668 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_DIR_OPEN_HRM_MARK
, &m_folderopenhrmxpm
, &m_folderopenhrmxpmmask
);
669 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_TRASH_OPEN_MARK
, &m_trashopenxpm
, &m_trashopenxpmmask
);
670 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_TRASH_OPEN_HRM_MARK
, &m_trashopenhrmxpm
, &m_trashopenhrmxpmmask
);
671 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_TRASH_CLOSE_MARK
, &m_trashxpm
, &m_trashxpmmask
);
672 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_TRASH_CLOSE_HRM_MARK
, &m_trashhrmxpm
, &m_trashhrmxpmmask
);
673 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_QUEUE_CLOSE_MARK
, &m_queuexpm
, &m_queuexpmmask
);
674 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_QUEUE_CLOSE_HRM_MARK
, &m_queuehrmxpm
, &m_queuehrmxpmmask
);
675 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_QUEUE_OPEN_MARK
, &m_queueopenxpm
, &m_queueopenxpmmask
);
676 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_QUEUE_OPEN_HRM_MARK
, &m_queueopenhrmxpm
, &m_queueopenhrmxpmmask
);
677 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_DRAFTS_CLOSE_MARK
, &m_draftsxpm
, &m_draftsxpmmask
);
678 stock_pixmap_gdk(ctree
, STOCK_PIXMAP_DRAFTS_OPEN_MARK
, &m_draftsopenxpm
, &m_draftsopenxpmmask
);
681 PangoFontDescription
*font_desc
;
682 normal_style
= gtk_style_copy(gtk_widget_get_style(ctree
));
683 font_desc
= pango_font_description_from_string(NORMAL_FONT
);
685 if (normal_style
->font_desc
)
686 pango_font_description_free
687 (normal_style
->font_desc
);
688 normal_style
->font_desc
= font_desc
;
690 gtkut_convert_int_to_gdk_color(prefs_common
.color_new
, &gdk_color
);
691 normal_color_style
= gtk_style_copy(normal_style
);
692 normal_color_style
->fg
[GTK_STATE_NORMAL
] = gdk_color
;
694 gtk_widget_set_style(ctree
, normal_style
);
698 gtkut_convert_int_to_gdk_color(prefs_common
.color_new
, &gdk_color
);
699 bold_style
= gtk_style_copy(gtk_widget_get_style(ctree
));
700 pango_font_description_set_weight
701 (bold_style
->font_desc
, PANGO_WEIGHT_BOLD
);
702 bold_color_style
= gtk_style_copy(bold_style
);
703 bold_color_style
->fg
[GTK_STATE_NORMAL
] = gdk_color
;
705 bold_tgtfold_style
= gtk_style_copy(bold_style
);
706 bold_tgtfold_style
->fg
[GTK_STATE_NORMAL
] = folderview
->color_op
;
710 static gboolean
folderview_defer_set(gpointer data
)
712 FolderView
*folderview
= (FolderView
*)data
;
713 MainWindow
*mainwin
= folderview
->mainwin
;
717 if (mainwin
->lock_count
)
720 printf("doing deferred folderview_set now\n");
721 folderview_set(folderview
);
723 folderview
->deferred_refresh_id
= -1;
727 void folderview_set(FolderView
*folderview
)
729 GtkCTree
*ctree
= GTK_CTREE(folderview
->ctree
);
730 MainWindow
*mainwin
= folderview
->mainwin
;
731 FolderItem
*sel_item
= NULL
, *op_item
= NULL
;
736 if (mainwin
->lock_count
) {
737 if (folderview
->deferred_refresh_id
== -1)
738 folderview
->deferred_refresh_id
=
739 g_timeout_add(500, folderview_defer_set
, folderview
);
740 printf("deferred folderview_set\n");
745 debug_print("Setting folder info...\n");
746 STATUSBAR_PUSH(mainwin
, _("Setting folder info..."));
748 main_window_cursor_wait(mainwin
);
750 if (folderview
->selected
)
751 sel_item
= gtk_ctree_node_get_row_data(ctree
, folderview
->selected
);
752 if (folderview
->opened
)
753 op_item
= gtk_ctree_node_get_row_data(ctree
, folderview
->opened
);
755 folderview
->selected
= NULL
;
756 folderview
->opened
= NULL
;
758 gtk_clist_freeze(GTK_CLIST(ctree
));
759 gtk_clist_clear(GTK_CLIST(ctree
));
761 folderview_set_folders(folderview
);
764 folderview
->selected
= gtk_ctree_find_by_row_data(ctree
, NULL
, sel_item
);
766 folderview
->opened
= gtk_ctree_find_by_row_data(ctree
, NULL
, op_item
);
768 gtk_clist_thaw(GTK_CLIST(ctree
));
769 main_window_cursor_normal(mainwin
);
770 STATUSBAR_POP(mainwin
);
774 void folderview_set_all(void)
778 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
)
779 folderview_set((FolderView
*)list
->data
);
782 void folderview_select(FolderView
*folderview
, FolderItem
*item
)
784 GtkCTree
*ctree
= GTK_CTREE(folderview
->ctree
);
786 GtkCTreeNode
*old_selected
= folderview
->selected
;
790 node
= gtk_ctree_find_by_row_data(ctree
, NULL
, item
);
791 if (node
) folderview_select_node(folderview
, node
);
793 if (old_selected
!= node
)
794 folder_update_op_count();
797 static void mark_all_read_cb(FolderView
*folderview
, guint action
,
803 item
= folderview_get_selected_item(folderview
);
807 if (folderview
->summaryview
->folder_item
!= item
808 && prefs_common
.ask_mark_all_read
) {
809 val
= alertpanel_full(_("Mark all as read"),
810 _("Do you really want to mark all mails in this "
811 "folder as read ?"), GTK_STOCK_NO
, GTK_STOCK_YES
, NULL
,
812 TRUE
, NULL
, ALERT_QUESTION
, G_ALERTDEFAULT
);
814 if ((val
& ~G_ALERTDISABLE
) != G_ALERTALTERNATE
)
816 else if (val
& G_ALERTDISABLE
)
817 prefs_common
.ask_mark_all_read
= FALSE
;
820 summary_lock(folderview
->summaryview
);
821 folder_item_update_freeze();
822 if (folderview
->summaryview
->folder_item
== item
)
823 summary_freeze(folderview
->summaryview
);
824 folderutils_mark_all_read(item
);
825 if (folderview
->summaryview
->folder_item
== item
)
826 summary_thaw(folderview
->summaryview
);
827 folder_item_update_thaw();
828 summary_unlock(folderview
->summaryview
);
831 static void folderview_select_node(FolderView
*folderview
, GtkCTreeNode
*node
)
833 GtkCTree
*ctree
= GTK_CTREE(folderview
->ctree
);
835 g_return_if_fail(node
!= NULL
);
837 if (folderview
->open_folder
) {
841 folderview
->open_folder
= TRUE
;
842 gtkut_ctree_set_focus_row(ctree
, node
);
843 gtk_ctree_select(ctree
, node
);
844 if (folderview
->summaryview
->folder_item
&&
845 folderview
->summaryview
->folder_item
->total_msgs
> 0)
846 summary_grab_focus(folderview
->summaryview
);
848 gtk_widget_grab_focus(folderview
->ctree
);
850 gtkut_ctree_expand_parent_all(ctree
, node
);
853 void folderview_unselect(FolderView
*folderview
)
855 if (folderview
->opened
&& !GTK_CTREE_ROW(folderview
->opened
)->children
)
857 (GTK_CTREE(folderview
->ctree
), folderview
->opened
);
859 folderview
->selected
= folderview
->opened
= NULL
;
862 static GtkCTreeNode
*folderview_find_next_marked(GtkCTree
*ctree
,
868 node
= gtkut_ctree_node_next(ctree
, node
);
870 node
= GTK_CTREE_NODE(GTK_CLIST(ctree
)->row_list
);
872 for (; node
!= NULL
; node
= gtkut_ctree_node_next(ctree
, node
)) {
873 item
= gtk_ctree_node_get_row_data(ctree
, node
);
874 if (item
&& item
->marked_msgs
> 0 && item
->stype
!= F_TRASH
)
881 void folderview_select_next_marked(FolderView
*folderview
)
883 GtkCTree
*ctree
= GTK_CTREE(folderview
->ctree
);
884 GtkCTreeNode
*node
= NULL
;
885 SelectOnEntry last_sel
= prefs_common
.select_on_entry
;
886 gboolean last_open
= prefs_common
.always_show_msg
;
888 prefs_common
.select_on_entry
= SELECTONENTRY_MNU
;
889 prefs_common
.always_show_msg
= TRUE
;
891 if ((node
= folderview_find_next_marked(ctree
, folderview
->opened
))
893 folderview_select_node(folderview
, node
);
897 if (!folderview
->opened
||
898 folderview
->opened
== GTK_CTREE_NODE(GTK_CLIST(ctree
)->row_list
)) {
901 /* search again from the first node */
902 if ((node
= folderview_find_next_marked(ctree
, NULL
)) != NULL
)
903 folderview_select_node(folderview
, node
);
906 prefs_common
.select_on_entry
= last_sel
;
907 prefs_common
.always_show_msg
= last_open
;
910 static GtkCTreeNode
*folderview_find_next_unread(GtkCTree
*ctree
,
916 node
= gtkut_ctree_node_next(ctree
, node
);
918 node
= GTK_CTREE_NODE(GTK_CLIST(ctree
)->row_list
);
920 for (; node
!= NULL
; node
= gtkut_ctree_node_next(ctree
, node
)) {
921 item
= gtk_ctree_node_get_row_data(ctree
, node
);
922 if (item
&& item
->unread_msgs
> 0 && item
->stype
!= F_TRASH
)
929 void folderview_select_next_unread(FolderView
*folderview
, gboolean force_open
)
931 GtkCTree
*ctree
= GTK_CTREE(folderview
->ctree
);
932 GtkCTreeNode
*node
= NULL
;
933 SelectOnEntry last_sel
= prefs_common
.select_on_entry
;
934 gboolean last_open
= prefs_common
.always_show_msg
;
936 prefs_common
.select_on_entry
= SELECTONENTRY_UNM
;
937 prefs_common
.always_show_msg
= force_open
? TRUE
: last_open
;
939 if ((node
= folderview_find_next_unread(ctree
, folderview
->opened
))
941 folderview_select_node(folderview
, node
);
945 if (!folderview
->opened
||
946 folderview
->opened
== GTK_CTREE_NODE(GTK_CLIST(ctree
)->row_list
)) {
949 /* search again from the first node */
950 if ((node
= folderview_find_next_unread(ctree
, NULL
)) != NULL
)
951 folderview_select_node(folderview
, node
);
954 prefs_common
.select_on_entry
= last_sel
;
955 prefs_common
.always_show_msg
= last_open
;
958 static GtkCTreeNode
*folderview_find_next_new(GtkCTree
*ctree
,
964 node
= gtkut_ctree_node_next(ctree
, node
);
966 node
= GTK_CTREE_NODE(GTK_CLIST(ctree
)->row_list
);
968 for (; node
!= NULL
; node
= gtkut_ctree_node_next(ctree
, node
)) {
969 item
= gtk_ctree_node_get_row_data(ctree
, node
);
970 if (item
&& item
->new_msgs
> 0 && item
->stype
!= F_TRASH
)
977 void folderview_select_next_new(FolderView
*folderview
)
979 GtkCTree
*ctree
= GTK_CTREE(folderview
->ctree
);
980 GtkCTreeNode
*node
= NULL
;
981 SelectOnEntry last_sel
= prefs_common
.select_on_entry
;
982 gboolean last_open
= prefs_common
.always_show_msg
;
984 prefs_common
.select_on_entry
= SELECTONENTRY_NUM
;
985 prefs_common
.always_show_msg
= TRUE
;
987 if ((node
= folderview_find_next_new(ctree
, folderview
->opened
))
989 folderview_select_node(folderview
, node
);
993 if (!folderview
->opened
||
994 folderview
->opened
== GTK_CTREE_NODE(GTK_CLIST(ctree
)->row_list
)) {
997 /* search again from the first node */
998 if ((node
= folderview_find_next_new(ctree
, NULL
)) != NULL
)
999 folderview_select_node(folderview
, node
);
1002 prefs_common
.select_on_entry
= last_sel
;
1003 prefs_common
.always_show_msg
= last_open
;
1006 FolderItem
*folderview_get_selected_item(FolderView
*folderview
)
1008 GtkCTree
*ctree
= GTK_CTREE(folderview
->ctree
);
1010 if (!folderview
->selected
) return NULL
;
1011 return gtk_ctree_node_get_row_data(ctree
, folderview
->selected
);
1014 static void folderview_set_folders(FolderView
*folderview
)
1017 list
= folder_get_list();
1019 for (; list
!= NULL
; list
= list
->next
) {
1020 folderview_append_folder(folderview
, FOLDER(list
->data
));
1024 static gchar
*get_scan_str(FolderItem
*item
)
1027 return g_strdup_printf(_("Scanning folder %s%c%s ..."),
1028 item
->folder
->name
, G_DIR_SEPARATOR
,
1031 return g_strdup_printf(_("Scanning folder %s ..."),
1032 item
->folder
->name
);
1034 static void folderview_scan_tree_func(Folder
*folder
, FolderItem
*item
,
1038 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
) {
1039 FolderView
*folderview
= (FolderView
*)list
->data
;
1040 MainWindow
*mainwin
= folderview
->mainwin
;
1041 gchar
*str
= get_scan_str(item
);
1043 STATUSBAR_PUSH(mainwin
, str
);
1044 STATUSBAR_POP(mainwin
);
1049 void folderview_rescan_tree(Folder
*folder
, gboolean rebuild
)
1052 MainWindow
*mainwin
= mainwindow_get_mainwindow();
1053 FolderView
*folderview
= NULL
;
1054 GtkAdjustment
*pos
= NULL
;
1057 g_return_if_fail(folder
!= NULL
);
1059 if (!folder
->klass
->scan_tree
) return;
1062 alertpanel_full(_("Rebuild folder tree"),
1063 _("Rebuilding the folder tree will remove "
1064 "local caches. Do you want to continue?"),
1065 GTK_STOCK_NO
, GTK_STOCK_YES
, NULL
, FALSE
,
1066 NULL
, ALERT_WARNING
, G_ALERTDEFAULT
)
1067 != G_ALERTALTERNATE
) {
1073 window
= label_window_create(_("Rebuilding folder tree..."));
1075 window
= label_window_create(_("Scanning folder tree..."));
1078 folderview
= mainwin
->folderview
;
1081 pos
= gtk_scrolled_window_get_vadjustment(
1082 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
1083 height
= pos
->value
;
1086 folder_set_ui_func(folder
, folderview_scan_tree_func
, NULL
);
1087 folder_scan_tree(folder
, rebuild
);
1088 folder_set_ui_func(folder
, NULL
, NULL
);
1090 folderview_set_all();
1093 pos
= gtk_scrolled_window_get_vadjustment(
1094 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
1095 gtk_adjustment_set_value(pos
, height
);
1097 gtk_widget_destroy(window
);
1101 void folderview_fast_rescan_tree(Folder
*folder
)
1104 MainWindow
*mainwin
= mainwindow_get_mainwindow();
1105 FolderView
*folderview
= NULL
;
1106 GtkAdjustment
*pos
= NULL
;
1109 g_return_if_fail(folder
!= NULL
);
1111 if (!folder
->klass
->scan_tree
) return;
1115 window
= label_window_create(_("Scanning folder tree..."));
1118 folderview
= mainwin
->folderview
;
1121 pos
= gtk_scrolled_window_get_vadjustment(
1122 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
1123 height
= pos
->value
;
1126 folder_set_ui_func(folder
, folderview_scan_tree_func
, NULL
);
1127 folder_fast_scan_tree(folder
);
1128 folder_set_ui_func(folder
, NULL
, NULL
);
1130 folderview_set_all();
1133 pos
= gtk_scrolled_window_get_vadjustment(
1134 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
1135 gtk_adjustment_set_value(pos
, height
);
1137 gtk_widget_destroy(window
);
1141 /** folderview_check_new()
1142 * Scan and update the folder and return the
1143 * count the number of new messages since last check.
1144 * \param folder the folder to check for new messages
1145 * \return the number of new messages since last check
1147 gint
folderview_check_new(Folder
*folder
)
1151 FolderView
*folderview
;
1155 gint former_new_msgs
= 0;
1156 gint former_new
= 0, former_unread
= 0, former_total
;
1158 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
) {
1159 folderview
= (FolderView
*)list
->data
;
1160 ctree
= GTK_CTREE(folderview
->ctree
);
1163 main_window_lock(folderview
->mainwin
);
1165 for (node
= GTK_CTREE_NODE(GTK_CLIST(ctree
)->row_list
);
1166 node
!= NULL
; node
= gtkut_ctree_node_next(ctree
, node
)) {
1168 item
= gtk_ctree_node_get_row_data(ctree
, node
);
1169 if (!item
|| !item
->path
|| !item
->folder
) continue;
1170 if (item
->no_select
) continue;
1171 if (folder
&& folder
!= item
->folder
) continue;
1172 if (!folder
&& !FOLDER_IS_LOCAL(item
->folder
)) continue;
1173 if (!item
->prefs
->newmailcheck
) continue;
1174 if (item
->processing_pending
== TRUE
) {
1175 debug_print("skipping %s, processing pending\n",
1176 item
->path
? item
->path
: item
->name
);
1180 str
= get_scan_str(item
);
1182 STATUSBAR_PUSH(folderview
->mainwin
, str
);
1186 folderview_scan_tree_func(item
->folder
, item
, NULL
);
1187 former_new
= item
->new_msgs
;
1188 former_unread
= item
->unread_msgs
;
1189 former_total
= item
->total_msgs
;
1191 if (item
->folder
->klass
->scan_required
&&
1192 (item
->folder
->klass
->scan_required(item
->folder
, item
) ||
1193 item
->folder
->inbox
== item
||
1194 item
->opened
== TRUE
||
1195 item
->processing_pending
== TRUE
)) {
1196 if (folder_item_scan(item
) < 0) {
1198 summaryview_unlock(folderview
->summaryview
, item
);
1199 if (FOLDER_TYPE(item
->folder
) == F_NEWS
|| FOLDER_IS_LOCAL(folder
)) {
1200 log_error(LOG_PROTOCOL
, _("Couldn't scan folder %s\n"),
1201 item
->path
? item
->path
:item
->name
);
1203 } else if (!FOLDER_IS_LOCAL(folder
)) {
1204 STATUSBAR_POP(folderview
->mainwin
);
1209 } else if (!item
->folder
->klass
->scan_required
) {
1210 if (folder_item_scan(item
) < 0) {
1211 summaryview_unlock(folderview
->summaryview
, item
);
1212 if (folder
&& !FOLDER_IS_LOCAL(folder
)) {
1213 STATUSBAR_POP(folderview
->mainwin
);
1218 if (former_new
!= item
->new_msgs
||
1219 former_unread
!= item
->unread_msgs
||
1220 former_total
!= item
->total_msgs
)
1221 folderview_update_node(folderview
, node
);
1223 new_msgs
+= item
->new_msgs
;
1224 former_new_msgs
+= former_new
;
1225 STATUSBAR_POP(folderview
->mainwin
);
1228 main_window_unlock(folderview
->mainwin
);
1232 folder_write_list();
1233 /* Number of new messages since last check is the just the difference
1234 * between former_new_msgs and new_msgs. If new_msgs is less than
1235 * former_new_msgs, that would mean another session accessed the folder
1236 * and the result is not well defined.
1238 new_msgs
= (former_new_msgs
< new_msgs
? new_msgs
- former_new_msgs
: 0);
1242 void folderview_check_new_all(void)
1246 FolderView
*folderview
;
1248 folderview
= (FolderView
*)folderview_list
->data
;
1251 main_window_lock(folderview
->mainwin
);
1252 window
= label_window_create
1253 (_("Checking for new messages in all folders..."));
1255 list
= folder_get_list();
1256 for (; list
!= NULL
; list
= list
->next
) {
1257 Folder
*folder
= list
->data
;
1259 folderview_check_new(folder
);
1262 folder_write_list();
1263 folderview_set_all();
1265 gtk_widget_destroy(window
);
1266 main_window_unlock(folderview
->mainwin
);
1270 static gboolean
folderview_have_new_children_sub(FolderView
*folderview
,
1276 if (!item
|| !item
->folder
|| !item
->folder
->node
)
1279 node
= item
->folder
->node
;
1281 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1282 node
= node
->children
;
1285 (item
->new_msgs
> 0 ||
1286 (folder_has_parent_of_type(item
, F_QUEUE
) && item
->total_msgs
> 0))) {
1290 while (node
!= NULL
) {
1291 if (node
&& node
->data
) {
1292 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1294 if (folderview_have_new_children_sub(folderview
,
1303 static gboolean
folderview_have_new_children(FolderView
*folderview
,
1306 return folderview_have_new_children_sub(folderview
, item
, FALSE
);
1309 static gboolean
folderview_have_unread_children_sub(FolderView
*folderview
,
1315 if (!item
|| !item
->folder
|| !item
->folder
->node
)
1318 node
= item
->folder
->node
;
1320 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1321 node
= node
->children
;
1324 (item
->unread_msgs
> 0 ||
1325 (folder_has_parent_of_type(item
, F_QUEUE
) && item
->total_msgs
> 0))) {
1329 while (node
!= NULL
) {
1330 if (node
&& node
->data
) {
1331 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1333 if (folderview_have_unread_children_sub(folderview
,
1343 static gboolean
folderview_have_unread_children(FolderView
*folderview
,
1346 return folderview_have_unread_children_sub(folderview
, item
, FALSE
);
1349 static gboolean
folderview_have_matching_children_sub(FolderView
*folderview
,
1355 if (!item
|| !item
->folder
|| !item
->folder
->node
)
1358 node
= item
->folder
->node
;
1360 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1361 node
= node
->children
;
1363 if (in_sub
&& item
->search_match
){
1367 while (node
!= NULL
) {
1368 if (node
&& node
->data
) {
1369 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1371 if (folderview_have_matching_children_sub(folderview
,
1381 static gboolean
folderview_have_matching_children(FolderView
*folderview
,
1384 return folderview_have_matching_children_sub(folderview
, item
, FALSE
);
1387 static gboolean
folderview_have_marked_children_sub(FolderView
*folderview
,
1393 if (!item
|| !item
->folder
|| !item
->folder
->node
)
1396 node
= item
->folder
->node
;
1398 node
= g_node_find(node
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
1399 node
= node
->children
;
1401 if (item
->marked_msgs
!= 0) {
1405 while (node
!= NULL
) {
1406 if (node
&& node
->data
) {
1407 FolderItem
*next_item
= (FolderItem
*) node
->data
;
1409 if (folderview_have_marked_children_sub(folderview
,
1418 static gboolean
folderview_have_marked_children(FolderView
*folderview
,
1421 return folderview_have_marked_children_sub(folderview
, item
, FALSE
);
1424 static void folderview_update_node(FolderView
*folderview
, GtkCTreeNode
*node
)
1426 GtkCTree
*ctree
= GTK_CTREE(folderview
->ctree
);
1427 GtkStyle
*style
= NULL
;
1428 GtkStyle
*color_style
= NULL
;
1430 GdkPixmap
*xpm
, *openxpm
;
1431 GdkBitmap
*mask
, *openmask
;
1432 static GdkPixmap
*searchicon
;
1433 static GdkBitmap
*searchmask
;
1434 gboolean mark
= FALSE
;
1437 gboolean add_unread_mark
;
1438 gboolean add_sub_match_mark
;
1439 gboolean use_bold
, use_color
;
1440 gint
*col_pos
= folderview
->col_pos
;
1441 SpecialFolderItemType stype
;
1443 item
= gtk_ctree_node_get_row_data(ctree
, node
);
1444 g_return_if_fail(item
!= NULL
);
1446 if (!GTK_CTREE_ROW(node
)->expanded
)
1447 mark
= folderview_have_marked_children(folderview
, item
);
1449 mark
= (item
->marked_msgs
!= 0);
1451 stype
= item
->stype
;
1452 if (stype
== F_NORMAL
) {
1453 if (folder_has_parent_of_type(item
, F_TRASH
))
1455 else if (folder_has_parent_of_type(item
, F_DRAFT
))
1457 else if (folder_has_parent_of_type(item
, F_OUTBOX
))
1459 else if (folder_has_parent_of_type(item
, F_QUEUE
))
1464 if (item
->hide_read_msgs
) {
1465 xpm
= mark
?m_inboxhrmxpm
:inboxhrmxpm
;
1466 mask
= mark
?m_inboxhrmxpmmask
:inboxhrmxpmmask
;
1467 openxpm
= mark
?m_inboxopenhrmxpm
:inboxopenhrmxpm
;
1468 openmask
= mark
?m_inboxopenhrmxpmmask
:inboxopenhrmxpmmask
;
1470 xpm
= mark
?m_inboxxpm
:inboxxpm
;
1471 mask
= mark
?m_inboxxpmmask
:inboxxpmmask
;
1472 openxpm
= mark
?m_inboxopenxpm
:inboxopenxpm
;
1473 openmask
= mark
?m_inboxopenxpmmask
:inboxopenxpmmask
;
1477 if (item
->hide_read_msgs
) {
1478 xpm
= mark
?m_outboxhrmxpm
:outboxhrmxpm
;
1479 mask
= mark
?m_outboxhrmxpmmask
:outboxhrmxpmmask
;
1480 openxpm
= mark
?m_outboxopenhrmxpm
:outboxopenhrmxpm
;
1481 openmask
= mark
?m_outboxopenhrmxpmmask
:outboxopenhrmxpmmask
;
1483 xpm
= mark
?m_outboxxpm
:outboxxpm
;
1484 mask
= mark
?m_outboxxpmmask
:outboxxpmmask
;
1485 openxpm
= mark
?m_outboxopenxpm
:outboxopenxpm
;
1486 openmask
= mark
?m_outboxopenxpmmask
:outboxopenxpmmask
;
1490 if (item
->hide_read_msgs
) {
1491 xpm
= mark
?m_queuehrmxpm
:queuehrmxpm
;
1492 mask
= mark
?m_queuehrmxpmmask
:queuehrmxpmmask
;
1493 openxpm
= mark
?m_queueopenhrmxpm
:queueopenhrmxpm
;
1494 openmask
= mark
?m_queueopenhrmxpmmask
:queueopenhrmxpmmask
;
1496 xpm
= mark
?m_queuexpm
:queuexpm
;
1497 mask
= mark
?m_queuexpmmask
:queuexpmmask
;
1498 openxpm
= mark
?m_queueopenxpm
:queueopenxpm
;
1499 openmask
= mark
?m_queueopenxpmmask
:queueopenxpmmask
;
1503 if (item
->hide_read_msgs
) {
1504 xpm
= mark
?m_trashhrmxpm
:trashhrmxpm
;
1505 mask
= mark
?m_trashhrmxpmmask
:trashhrmxpmmask
;
1506 openxpm
= mark
?m_trashopenhrmxpm
:trashopenhrmxpm
;
1507 openmask
= mark
?m_trashopenhrmxpmmask
:trashopenhrmxpmmask
;
1509 xpm
= mark
?m_trashxpm
:trashxpm
;
1510 mask
= mark
?m_trashxpmmask
:trashxpmmask
;
1511 openxpm
= mark
?m_trashopenxpm
:trashopenxpm
;
1512 openmask
= mark
?m_trashopenxpmmask
:trashopenxpmmask
;
1516 xpm
= mark
?m_draftsxpm
:draftsxpm
;
1517 mask
= mark
?m_draftsxpmmask
:draftsxpmmask
;
1518 openxpm
= mark
?m_draftsopenxpm
:draftsopenxpm
;
1519 openmask
= mark
?m_draftsopenxpmmask
:draftsopenxpmmask
;
1522 if (item
->hide_read_msgs
) {
1523 xpm
= mark
?m_folderhrmxpm
:folderhrmxpm
;
1524 mask
= mark
?m_folderhrmxpmmask
:folderhrmxpmmask
;
1525 openxpm
= mark
?m_folderopenhrmxpm
:folderopenhrmxpm
;
1526 openmask
= mark
?m_folderopenhrmxpmmask
:folderopenhrmxpmmask
;
1528 xpm
= mark
?m_folderxpm
:folderxpm
;
1529 mask
= mark
?m_folderxpmmask
:folderxpmmask
;
1530 openxpm
= mark
?m_folderopenxpm
:folderopenxpm
;
1531 openmask
= mark
?m_folderopenxpmmask
:folderopenxpmmask
;
1535 if (item
->no_select
) {
1536 xpm
= openxpm
= noselectxpm
;
1537 mask
= openmask
= noselectxpmmask
;
1540 name
= folder_item_get_name(item
);
1542 if (!GTK_CTREE_ROW(node
)->expanded
) {
1543 add_unread_mark
= folderview_have_unread_children(
1545 add_sub_match_mark
= folderview_have_matching_children(
1548 add_unread_mark
= FALSE
;
1549 add_sub_match_mark
= FALSE
;
1552 if (item
->search_match
) {
1554 stock_pixmap_gdk(folderview
->ctree
, STOCK_PIXMAP_QUICKSEARCH
,
1555 &searchicon
, &searchmask
);
1557 xpm
= openxpm
= searchicon
;
1558 mask
= openmask
= searchmask
;
1562 if (prefs_common
.display_folder_unread
) {
1563 if (folder_has_parent_of_type(item
, F_QUEUE
)) {
1564 /* only total_msgs matters here */
1565 if (item
->total_msgs
> 0) {
1566 /* show total number (should be equal to the unread number)
1568 str
= g_strdup_printf("%s (%d%s%s)",
1569 name
, item
->total_msgs
,
1570 (add_unread_mark
|| add_sub_match_mark
) ? "+" : "",
1571 (item
->unreadmarked_msgs
> 0) ? "!" : "");
1574 if (prefs_common
.display_folder_unread
== 1) {
1575 if (item
->unread_msgs
> 0) {
1576 /* show unread number and signs */
1577 str
= g_strdup_printf("%s (%d%s%s)",
1578 name
, item
->unread_msgs
,
1579 (add_unread_mark
|| add_sub_match_mark
) ? "+" : "",
1580 (item
->unreadmarked_msgs
> 0) ? "!" : "");
1583 if (item
->total_msgs
> 0) {
1584 /* show unread number, total number and signs if any */
1585 str
= g_strdup_printf("%s (%d/%d%s%s)",
1586 name
, item
->unread_msgs
, item
->total_msgs
,
1587 (add_unread_mark
|| add_sub_match_mark
) ? "+" : "",
1588 (item
->unreadmarked_msgs
> 0) ? "!" : "");
1592 if ((str
== NULL
) &&
1593 (add_unread_mark
|| add_sub_match_mark
|| (item
->unreadmarked_msgs
> 0))) {
1594 /* no unread/total numbers, but at least one sign */
1595 str
= g_strdup_printf("%s (%s%s)",
1597 (add_unread_mark
|| add_sub_match_mark
) ? "+" : "",
1598 (item
->unreadmarked_msgs
> 0) ? "!" : "");
1602 /* last fallback, folder name only or with ! sign */
1603 str
= g_strdup_printf("%s%s",
1604 name
, (item
->unreadmarked_msgs
> 0) ? " (!)" : "");
1606 gtk_sctree_set_node_info(ctree
, node
, str
, FOLDER_SPACING
,
1607 xpm
, mask
, openxpm
, openmask
,
1608 FALSE
, GTK_CTREE_ROW(node
)->expanded
);
1612 if (!folder_item_parent(item
)) {
1613 gtk_ctree_node_set_text(ctree
, node
, col_pos
[F_COL_NEW
], "-");
1614 gtk_ctree_node_set_text(ctree
, node
, col_pos
[F_COL_UNREAD
], "-");
1615 gtk_ctree_node_set_text(ctree
, node
, col_pos
[F_COL_TOTAL
], "-");
1617 gtk_ctree_node_set_text(ctree
, node
, col_pos
[F_COL_NEW
], itos(item
->new_msgs
));
1618 gtk_ctree_node_set_text(ctree
, node
, col_pos
[F_COL_UNREAD
], itos(item
->unread_msgs
));
1619 gtk_ctree_node_set_text(ctree
, node
, col_pos
[F_COL_TOTAL
], itos(item
->total_msgs
));
1622 if (folder_has_parent_of_type(item
, F_OUTBOX
) ||
1623 folder_has_parent_of_type(item
, F_DRAFT
) ||
1624 folder_has_parent_of_type(item
, F_TRASH
)) {
1625 use_bold
= use_color
= FALSE
;
1626 } else if (folder_has_parent_of_type(item
, F_QUEUE
)) {
1627 /* highlight queue folder if there are any messages */
1628 use_bold
= use_color
= (item
->total_msgs
> 0);
1630 /* if unread messages exist, print with bold font */
1631 use_bold
= (item
->unread_msgs
> 0|| item
->new_msgs
> 0)
1633 /* if new messages exist, print with colored letter */
1635 (item
->new_msgs
> 0) ||
1637 folderview_have_new_children(folderview
, item
));
1640 gtk_ctree_node_set_foreground(ctree
, node
, NULL
);
1645 if (item
->prefs
->color
> 0 && !use_color
) {
1646 gtkut_convert_int_to_gdk_color(item
->prefs
->color
, &gdk_color
);
1647 color_style
= gtk_style_copy(bold_style
);
1648 color_style
->fg
[GTK_STATE_NORMAL
] = gdk_color
;
1649 style
= color_style
;
1650 } else if (use_color
) {
1651 style
= bold_color_style
;
1654 if (item
->op_count
> 0) {
1655 style
= bold_tgtfold_style
;
1657 } else if (use_color
) {
1658 style
= normal_color_style
;
1659 gtk_ctree_node_set_foreground(ctree
, node
,
1660 &folderview
->color_new
);
1661 } else if (item
->op_count
> 0) {
1662 style
= bold_tgtfold_style
;
1663 } else if (item
->prefs
->color
> 0) {
1665 gtkut_convert_int_to_gdk_color(item
->prefs
->color
, &gdk_color
);
1666 color_style
= gtk_style_copy(normal_style
);
1667 color_style
->fg
[GTK_STATE_NORMAL
] = gdk_color
;
1668 style
= color_style
;
1670 style
= normal_style
;
1673 gtk_ctree_node_set_row_style(ctree
, node
, style
);
1675 if ((node
= gtkut_ctree_find_collapsed_parent(ctree
, node
)) != NULL
)
1676 folderview_update_node(folderview
, node
);
1679 void folderview_update_search_icon(FolderItem
*item
, gboolean matches
)
1682 FolderView
*folderview
;
1686 g_return_if_fail(item
!= NULL
);
1688 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
) {
1689 folderview
= (FolderView
*)list
->data
;
1690 ctree
= GTK_CTREE(folderview
->ctree
);
1692 node
= gtk_ctree_find_by_row_data(ctree
, NULL
, item
);
1694 item
->search_match
= matches
;
1695 folderview_update_node(folderview
, node
);
1700 static gboolean
folderview_update_item_claws(gpointer source
, gpointer data
)
1702 FolderItemUpdateData
*update_info
= (FolderItemUpdateData
*)source
;
1703 FolderView
*folderview
= (FolderView
*)data
;
1706 g_return_val_if_fail(update_info
!= NULL
, TRUE
);
1707 g_return_val_if_fail(update_info
->item
!= NULL
, TRUE
);
1708 g_return_val_if_fail(folderview
!= NULL
, FALSE
);
1710 ctree
= GTK_CTREE(folderview
->ctree
);
1712 node
= gtk_ctree_find_by_row_data(ctree
, NULL
, update_info
->item
);
1715 if (update_info
->update_flags
& (F_ITEM_UPDATE_MSGCNT
| F_ITEM_UPDATE_NAME
))
1716 folderview_update_node(folderview
, node
);
1718 if ((update_info
->update_flags
& F_ITEM_UPDATE_CONTENT
) &&
1719 update_info
->item
== folderview
->summaryview
->folder_item
&&
1720 update_info
->item
!= NULL
)
1721 if (!quicksearch_is_active(folderview
->summaryview
->quicksearch
))
1722 summary_show(folderview
->summaryview
, update_info
->item
);
1728 static gboolean
folderview_gnode_func(GtkCTree
*ctree
, guint depth
,
1729 GNode
*gnode
, GtkCTreeNode
*cnode
,
1732 FolderView
*folderview
= (FolderView
*)data
;
1733 FolderItem
*item
= FOLDER_ITEM(gnode
->data
);
1735 g_return_val_if_fail(item
!= NULL
, FALSE
);
1737 gtk_ctree_node_set_row_data(ctree
, cnode
, item
);
1738 folderview_update_node(folderview
, cnode
);
1743 static void folderview_expand_func(GtkCTree
*ctree
, GtkCTreeNode
*node
,
1746 FolderView
*folderview
= (FolderView
*)data
;
1749 if (GTK_CTREE_ROW(node
)->children
) {
1750 item
= gtk_ctree_node_get_row_data(ctree
, node
);
1751 g_return_if_fail(item
!= NULL
);
1753 if (!item
->collapsed
)
1754 gtk_ctree_expand(ctree
, node
);
1756 folderview_update_node(folderview
, node
);
1760 static void set_special_folder(GtkCTree
*ctree
, FolderItem
*item
,
1761 GtkCTreeNode
*root
, GtkCTreeNode
**prev
)
1764 GtkCTreeNode
*node
, *parent
, *sibling
;
1766 node
= gtk_ctree_find_by_row_data(ctree
, root
, item
);
1768 g_warning("%s not found.\n", item
->path
);
1770 parent
= GTK_CTREE_ROW(node
)->parent
;
1771 if (*prev
&& parent
== GTK_CTREE_ROW(*prev
)->parent
)
1772 sibling
= GTK_CTREE_ROW(*prev
)->sibling
;
1774 sibling
= GTK_CTREE_ROW(parent
)->children
;
1778 tmp
= gtk_ctree_node_get_row_data
1780 if (tmp
->stype
!= F_NORMAL
)
1781 sibling
= GTK_CTREE_ROW(sibling
)->sibling
;
1785 if (node
!= sibling
)
1786 gtk_ctree_move(ctree
, node
, parent
, sibling
);
1793 static void folderview_sort_folders(FolderView
*folderview
, GtkCTreeNode
*root
,
1796 GtkCTree
*ctree
= GTK_CTREE(folderview
->ctree
);
1797 GtkCTreeNode
*prev
= NULL
;
1799 gtk_clist_freeze(GTK_CLIST(ctree
));
1800 gtk_sctree_sort_recursive(ctree
, root
);
1801 if (root
&& GTK_CTREE_ROW(root
)->parent
) {
1802 gtk_clist_thaw(GTK_CLIST(ctree
));
1805 set_special_folder(ctree
, folder
->inbox
, root
, &prev
);
1806 set_special_folder(ctree
, folder
->outbox
, root
, &prev
);
1807 set_special_folder(ctree
, folder
->draft
, root
, &prev
);
1808 set_special_folder(ctree
, folder
->queue
, root
, &prev
);
1809 set_special_folder(ctree
, folder
->trash
, root
, &prev
);
1810 gtk_clist_thaw(GTK_CLIST(ctree
));
1813 static void folderview_append_folder(FolderView
*folderview
, Folder
*folder
)
1815 GtkCTree
*ctree
= GTK_CTREE(folderview
->ctree
);
1818 g_return_if_fail(folder
!= NULL
);
1820 root
= gtk_sctree_insert_gnode(ctree
, NULL
, NULL
, folder
->node
,
1821 folderview_gnode_func
, folderview
);
1822 gtk_ctree_pre_recursive(ctree
, root
, folderview_expand_func
,
1824 folderview_sort_folders(folderview
, root
, folder
);
1827 /* callback functions */
1828 static void folderview_set_sens_and_popup_menu(FolderView
*folderview
, gint row
,
1829 GdkEventButton
*event
)
1831 GtkCList
*clist
= GTK_CLIST(folderview
->ctree
);
1834 FolderViewPopup
*fpopup
;
1835 GtkItemFactory
*fpopup_factory
;
1837 FolderItem
*special_trash
= NULL
, *special_queue
= NULL
;
1841 item
= gtk_clist_get_row_data(clist
, row
);
1843 item
= folderview_get_selected_item(folderview
);
1845 g_return_if_fail(item
!= NULL
);
1846 g_return_if_fail(item
->folder
!= NULL
);
1847 folder
= item
->folder
;
1849 fpopup
= g_hash_table_lookup(folderview_popups
, folder
->klass
->idstr
);
1851 fpopup_factory
= g_hash_table_lookup(folderview
->popups
, folder
->klass
->idstr
);
1853 fpopup
= g_hash_table_lookup(folderview_popups
, "common");
1854 fpopup_factory
= g_hash_table_lookup(folderview
->popups
, "common");
1857 if (fpopup
->set_sensitivity
!= NULL
)
1858 fpopup
->set_sensitivity(fpopup_factory
, item
);
1860 if (NULL
!= (ac
= account_find_from_item(item
))) {
1861 special_trash
= account_get_special_folder(ac
, F_TRASH
);
1862 special_queue
= account_get_special_folder(ac
, F_QUEUE
);
1865 if ((item
== folder
->trash
|| item
== special_trash
1866 || folder_has_parent_of_type(item
, F_TRASH
)) &&
1867 gtk_item_factory_get_item(fpopup_factory
, "/Empty trash...") == NULL
) {
1868 gtk_item_factory_create_item(fpopup_factory
, &folder_view_trash_popup_entries
[0], folderview
, 1);
1869 gtk_item_factory_create_item(fpopup_factory
, &folder_view_trash_popup_entries
[1], folderview
, 1);
1870 } else if (item
!= folder
->trash
&& (special_trash
== NULL
|| item
!= special_trash
)
1871 && !folder_has_parent_of_type(item
, F_TRASH
)) {
1872 gtk_item_factory_delete_entry(fpopup_factory
, &folder_view_trash_popup_entries
[0]);
1873 gtk_item_factory_delete_entry(fpopup_factory
, &folder_view_trash_popup_entries
[1]);
1876 if ((item
== folder
->queue
|| item
== special_queue
1877 || folder_has_parent_of_type(item
, F_QUEUE
)) &&
1878 gtk_item_factory_get_item(fpopup_factory
, "/Send queue...") == NULL
) {
1879 gtk_item_factory_create_item(fpopup_factory
, &folder_view_queue_popup_entries
[0], folderview
, 1);
1880 gtk_item_factory_create_item(fpopup_factory
, &folder_view_queue_popup_entries
[1], folderview
, 1);
1881 } else if (item
!= folder
->queue
&& (special_queue
== NULL
|| item
!= special_queue
)
1882 && !folder_has_parent_of_type(item
, F_QUEUE
)) {
1883 gtk_item_factory_delete_entry(fpopup_factory
, &folder_view_queue_popup_entries
[0]);
1884 gtk_item_factory_delete_entry(fpopup_factory
, &folder_view_queue_popup_entries
[1]);
1887 #define SET_SENS(name, sens) \
1888 menu_set_sensitive(fpopup_factory, name, sens)
1890 SET_SENS("/Mark all read", item
->unread_msgs
>= 1);
1891 SET_SENS("/Search folder...", item
->total_msgs
>= 1 &&
1892 folderview
->selected
== folderview
->opened
);
1893 SET_SENS("/Properties...", TRUE
);
1894 SET_SENS("/Processing...", item
->node
->parent
!= NULL
);
1895 if (item
== folder
->trash
|| item
== special_trash
1896 || folder_has_parent_of_type(item
, F_TRASH
)) {
1897 GSList
*msglist
= folder_item_get_msg_list(item
);
1898 SET_SENS("/Empty trash...", msglist
!= NULL
);
1899 procmsg_msg_list_free(msglist
);
1901 if (item
== folder
->queue
|| item
== special_queue
1902 || folder_has_parent_of_type(item
, F_QUEUE
)) {
1903 GSList
*msglist
= folder_item_get_msg_list(item
);
1904 SET_SENS("/Send queue...", msglist
!= NULL
);
1905 procmsg_msg_list_free(msglist
);
1909 popup
= gtk_item_factory_get_widget(fpopup_factory
, fpopup
->path
);
1910 gtk_menu_popup(GTK_MENU(popup
), NULL
, NULL
, NULL
, NULL
,
1911 event
->button
, event
->time
);
1916 static gboolean
folderview_button_pressed(GtkWidget
*ctree
, GdkEventButton
*event
,
1917 FolderView
*folderview
)
1919 GtkCList
*clist
= GTK_CLIST(ctree
);
1920 gint prev_row
= -1, row
= -1, column
= -1;
1922 if (!event
) return FALSE
;
1924 if (event
->button
== 1 || event
->button
== 2) {
1925 if (!gtk_ctree_is_hot_spot (GTK_CTREE(clist
), event
->x
, event
->y
))
1926 folderview
->open_folder
= TRUE
;
1928 if (event
->type
== GDK_2BUTTON_PRESS
) {
1929 if (clist
->selection
) {
1932 node
= GTK_CTREE_NODE(clist
->selection
->data
);
1934 gtk_ctree_toggle_expansion(
1937 folderview
->open_folder
= FALSE
;
1944 if (event
->button
== 2 || event
->button
== 3) {
1946 if (clist
->selection
) {
1949 node
= GTK_CTREE_NODE(clist
->selection
->data
);
1951 prev_row
= gtkut_ctree_get_nth_from_node
1952 (GTK_CTREE(ctree
), node
);
1955 if (!gtk_clist_get_selection_info(clist
, event
->x
, event
->y
,
1958 if (prev_row
!= row
) {
1959 gtk_clist_unselect_all(clist
);
1960 if (event
->button
== 2)
1961 folderview_select_node
1963 gtk_ctree_node_nth(GTK_CTREE(ctree
),
1966 gtk_clist_select_row(clist
, row
, column
);
1970 if (event
->button
!= 3) return FALSE
;
1972 folderview_set_sens_and_popup_menu(folderview
, row
, event
);
1976 static gboolean
folderview_button_released(GtkWidget
*ctree
, GdkEventButton
*event
,
1977 FolderView
*folderview
)
1979 if (!event
) return FALSE
;
1981 if (event
->button
== 1 && folderview
->open_folder
== FALSE
&&
1982 folderview
->opened
!= NULL
) {
1983 gtkut_ctree_set_focus_row(GTK_CTREE(ctree
),
1984 folderview
->opened
);
1985 gtk_ctree_select(GTK_CTREE(ctree
), folderview
->opened
);
1991 static gboolean
folderview_key_pressed(GtkWidget
*widget
, GdkEventKey
*event
,
1992 FolderView
*folderview
)
1994 if (!event
) return FALSE
;
1996 if (quicksearch_has_focus(folderview
->summaryview
->quicksearch
))
1999 switch (event
->keyval
) {
2001 if (folderview
->selected
) {
2002 folderview_select_node(folderview
,
2003 folderview
->selected
);
2007 if (folderview
->selected
) {
2008 if (folderview
->opened
== folderview
->selected
&&
2009 (!folderview
->summaryview
->folder_item
||
2010 folderview
->summaryview
->folder_item
->total_msgs
== 0))
2011 folderview_select_next_unread(folderview
, TRUE
);
2013 folderview_select_node(folderview
,
2014 folderview
->selected
);
2024 typedef struct _PostponedSelectData
2029 FolderView
*folderview
;
2030 } PostponedSelectData
;
2032 static gboolean
postpone_select(void *data
)
2034 PostponedSelectData
*psdata
= (PostponedSelectData
*)data
;
2035 debug_print("trying again\n");
2036 psdata
->folderview
->open_folder
= TRUE
;
2037 main_window_cursor_normal(psdata
->folderview
->mainwin
);
2038 STATUSBAR_POP(psdata
->folderview
->mainwin
);
2039 folderview_selected(psdata
->ctree
, psdata
->row
,
2040 psdata
->column
, psdata
->folderview
);
2045 void folderview_close_opened(FolderView
*folderview
)
2047 if (folderview
->opened
) {
2048 FolderItem
*olditem
;
2050 olditem
= gtk_ctree_node_get_row_data(folderview
->ctree
, folderview
->opened
);
2052 gchar
*buf
= g_strdup_printf(_("Closing Folder %s..."),
2053 olditem
->path
? olditem
->path
:olditem
->name
);
2054 /* will be null if we just moved the previously opened folder */
2055 STATUSBAR_PUSH(folderview
->mainwin
, buf
);
2056 main_window_cursor_wait(folderview
->mainwin
);
2058 summary_save_prefs_to_folderitem(folderview
->summaryview
, olditem
);
2059 summary_show(folderview
->summaryview
, NULL
);
2060 folder_item_close(olditem
);
2061 main_window_cursor_normal(folderview
->mainwin
);
2062 STATUSBAR_POP(folderview
->mainwin
);
2065 folderview
->opened
= NULL
;
2067 static void folderview_selected(GtkCTree
*ctree
, GtkCTreeNode
*row
,
2068 gint column
, FolderView
*folderview
)
2070 static gboolean can_select
= TRUE
; /* exclusive lock */
2076 folderview
->selected
= row
;
2078 debug_print("newly selected %p, opened %p\n", folderview
->selected
,
2079 folderview
->opened
);
2080 if (folderview
->opened
== row
) {
2081 folderview
->open_folder
= FALSE
;
2086 if (!can_select
|| summary_is_locked(folderview
->summaryview
)) {
2087 if (folderview
->opened
) {
2088 gtkut_ctree_set_focus_row(ctree
, folderview
->opened
);
2089 gtk_ctree_select(ctree
, folderview
->opened
);
2091 folderview
->open_folder
= FALSE
;
2096 if (!folderview
->open_folder
) {
2100 item
= gtk_ctree_node_get_row_data(ctree
, row
);
2101 if (!item
|| item
->no_select
) {
2103 folderview
->open_folder
= FALSE
;
2109 /* Save cache for old folder */
2110 /* We don't want to lose all caches if sylpheed crashed */
2111 folderview_close_opened(folderview
);
2113 /* CLAWS: set compose button type: news folder items
2114 * always have a news folder as parent */
2116 toolbar_set_compose_button
2117 (folderview
->mainwin
->toolbar
,
2118 FOLDER_TYPE(item
->folder
) == F_NEWS
?
2119 COMPOSEBUTTON_NEWS
: COMPOSEBUTTON_MAIL
);
2122 debug_print("Folder %s is selected\n", item
->path
);
2124 if (!GTK_CTREE_ROW(row
)->children
)
2125 gtk_ctree_expand(ctree
, row
);
2126 if (folderview
->opened
&&
2127 !GTK_CTREE_ROW(folderview
->opened
)->children
)
2128 gtk_ctree_collapse(ctree
, folderview
->opened
);
2130 /* ungrab the mouse event */
2131 if (GTK_WIDGET_HAS_GRAB(ctree
)) {
2132 gtk_grab_remove(GTK_WIDGET(ctree
));
2133 if (gdk_pointer_is_grabbed())
2134 gdk_pointer_ungrab(GDK_CURRENT_TIME
);
2138 buf
= g_strdup_printf(_("Opening Folder %s..."), item
->path
?
2139 item
->path
: "(null)");
2140 debug_print("%s\n", buf
);
2141 STATUSBAR_PUSH(folderview
->mainwin
, buf
);
2144 main_window_cursor_wait(folderview
->mainwin
);
2146 res
= folder_item_open(item
);
2148 main_window_cursor_normal(folderview
->mainwin
);
2149 STATUSBAR_POP(folderview
->mainwin
);
2151 alertpanel_error(_("Folder could not be opened."));
2153 folderview
->open_folder
= FALSE
;
2157 } else if (res
== -2) {
2158 PostponedSelectData
*data
= g_new0(PostponedSelectData
, 1);
2159 data
->ctree
= ctree
;
2161 data
->column
= column
;
2162 data
->folderview
= folderview
;
2163 debug_print("postponing open of %s till end of scan\n",
2164 item
->path
? item
->path
:item
->name
);
2165 folderview
->open_folder
= FALSE
;
2167 g_timeout_add(500, postpone_select
, data
);
2172 main_window_cursor_normal(folderview
->mainwin
);
2175 summary_set_prefs_from_folderitem(folderview
->summaryview
, item
);
2176 opened
= summary_show(folderview
->summaryview
, item
);
2178 folder_clean_cache_memory(item
);
2181 gtkut_ctree_set_focus_row(ctree
, folderview
->opened
);
2182 gtk_ctree_select(ctree
, folderview
->opened
);
2184 folderview
->opened
= row
;
2185 if (gtk_ctree_node_is_visible(ctree
, row
)
2186 != GTK_VISIBILITY_FULL
)
2187 gtk_ctree_node_moveto(ctree
, row
, -1, 0.5, 0);
2190 STATUSBAR_POP(folderview
->mainwin
);
2192 folderview
->open_folder
= FALSE
;
2197 static void folderview_tree_expanded(GtkCTree
*ctree
, GtkCTreeNode
*node
,
2198 FolderView
*folderview
)
2202 item
= gtk_ctree_node_get_row_data(ctree
, node
);
2203 g_return_if_fail(item
!= NULL
);
2204 item
->collapsed
= FALSE
;
2205 folderview_update_node(folderview
, node
);
2208 static void folderview_tree_collapsed(GtkCTree
*ctree
, GtkCTreeNode
*node
,
2209 FolderView
*folderview
)
2213 item
= gtk_ctree_node_get_row_data(ctree
, node
);
2214 g_return_if_fail(item
!= NULL
);
2215 item
->collapsed
= TRUE
;
2216 folderview_update_node(folderview
, node
);
2219 static void folderview_popup_close(GtkMenuShell
*menu_shell
,
2220 FolderView
*folderview
)
2222 if (!folderview
->opened
) return;
2224 gtk_ctree_select(GTK_CTREE(folderview
->ctree
), folderview
->opened
);
2227 static void folderview_col_resized(GtkCList
*clist
, gint column
, gint width
,
2228 FolderView
*folderview
)
2230 FolderColumnType type
= folderview
->col_state
[column
].type
;
2232 prefs_common
.folder_col_size
[type
] = width
;
2235 static void folderview_create_folder_node_recursive(FolderView
*folderview
, FolderItem
*item
)
2239 folderview_create_folder_node(folderview
, item
);
2241 if (!item
|| !item
->folder
|| !item
->folder
->node
)
2244 srcnode
= item
->folder
->node
;
2245 srcnode
= g_node_find(srcnode
, G_PRE_ORDER
, G_TRAVERSE_ALL
, item
);
2246 srcnode
= srcnode
->children
;
2247 while (srcnode
!= NULL
) {
2248 if (srcnode
&& srcnode
->data
) {
2249 FolderItem
*next_item
= (FolderItem
*) srcnode
->data
;
2250 folderview_create_folder_node_recursive(folderview
, next_item
);
2252 srcnode
= srcnode
->next
;
2256 static void folderview_create_folder_node(FolderView
*folderview
, FolderItem
*item
)
2258 GtkCTree
*ctree
= GTK_CTREE(folderview
->ctree
);
2259 gchar
*text
[N_FOLDER_COLS
] = {NULL
, "0", "0", "0"};
2260 GtkCTreeNode
*node
, *parent_node
;
2261 gint
*col_pos
= folderview
->col_pos
;
2262 FolderItemUpdateData hookdata
;
2264 parent_node
= gtk_ctree_find_by_row_data(ctree
, NULL
, folder_item_parent(item
));
2265 if (parent_node
== NULL
)
2268 gtk_clist_freeze(GTK_CLIST(ctree
));
2270 text
[col_pos
[F_COL_FOLDER
]] = item
->name
;
2271 node
= gtk_sctree_insert_node(ctree
, parent_node
, NULL
, text
,
2273 folderxpm
, folderxpmmask
,
2274 folderopenxpm
, folderopenxpmmask
,
2276 gtk_ctree_expand(ctree
, parent_node
);
2277 gtk_ctree_node_set_row_data(ctree
, node
, item
);
2279 gtk_ctree_node_set_row_style(ctree
, node
, normal_style
);
2280 folderview_sort_folders(folderview
, parent_node
, item
->folder
);
2282 hookdata
.item
= item
;
2283 hookdata
.update_flags
= F_ITEM_UPDATE_NAME
;
2284 hookdata
.msg
= NULL
;
2285 hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST
, &hookdata
);
2287 gtk_clist_thaw(GTK_CLIST(ctree
));
2290 static void folderview_empty_trash_cb(FolderView
*folderview
, guint action
,
2293 GtkCTree
*ctree
= GTK_CTREE(folderview
->ctree
);
2295 GSList
*mlist
= NULL
;
2297 FolderItem
*special_trash
= NULL
;
2300 if (!folderview
->selected
) return;
2301 item
= gtk_ctree_node_get_row_data(ctree
, folderview
->selected
);
2302 g_return_if_fail(item
!= NULL
);
2303 g_return_if_fail(item
->folder
!= NULL
);
2305 if (NULL
!= (ac
= account_find_from_item(item
)))
2306 special_trash
= account_get_special_folder(ac
, F_TRASH
);
2308 if (item
!= item
->folder
->trash
&& item
!= special_trash
2309 && !folder_has_parent_of_type(item
, F_TRASH
)) return;
2311 if (prefs_common
.ask_on_clean
) {
2312 if (alertpanel(_("Empty trash"),
2313 _("Delete all messages in trash?"),
2314 GTK_STOCK_CANCEL
, _("+_Empty trash"), NULL
) != G_ALERTALTERNATE
)
2318 mlist
= folder_item_get_msg_list(item
);
2320 for (cur
= mlist
; cur
!= NULL
; cur
= cur
->next
) {
2321 MsgInfo
* msginfo
= (MsgInfo
*) cur
->data
;
2322 if (MSG_IS_LOCKED(msginfo
->flags
))
2324 /* is it partially received? (partial_recv isn't cached) */
2325 if (msginfo
->total_size
!= 0 &&
2326 msginfo
->size
!= (off_t
)msginfo
->total_size
)
2327 partial_mark_for_delete(msginfo
);
2329 procmsg_msg_list_free(mlist
);
2331 folder_item_remove_all_msg(item
);
2334 static void folderview_send_queue_cb(FolderView
*folderview
, guint action
,
2337 GtkCTree
*ctree
= GTK_CTREE(folderview
->ctree
);
2339 FolderItem
*special_queue
= NULL
;
2341 gchar
*errstr
= NULL
;
2343 if (!folderview
->selected
) return;
2344 item
= gtk_ctree_node_get_row_data(ctree
, folderview
->selected
);
2345 g_return_if_fail(item
!= NULL
);
2346 g_return_if_fail(item
->folder
!= NULL
);
2348 if (NULL
!= (ac
= account_find_from_item(item
)))
2349 special_queue
= account_get_special_folder(ac
, F_QUEUE
);
2351 if (item
!= item
->folder
->queue
&& item
!= special_queue
2352 && !folder_has_parent_of_type(item
, F_QUEUE
)) return;
2354 if (procmsg_queue_is_empty(item
))
2357 if (prefs_common
.work_offline
)
2358 if (alertpanel(_("Offline warning"),
2359 _("You're working offline. Override?"),
2360 GTK_STOCK_NO
, GTK_STOCK_YES
,
2361 NULL
) != G_ALERTALTERNATE
)
2364 /* ask for confirmation before sending queued messages only
2365 in online mode and if there is at least one message queued
2366 in any of the folder queue
2368 if (prefs_common
.confirm_send_queued_messages
) {
2369 if (!prefs_common
.work_offline
) {
2370 if (alertpanel(_("Send queued messages"),
2371 _("Send all queued messages?"),
2372 GTK_STOCK_CANCEL
, _("_Send"),
2373 NULL
) != G_ALERTALTERNATE
)
2378 if (procmsg_send_queue(item
, prefs_common
.savemsg
, &errstr
) < 0) {
2380 alertpanel_error_log(_("Some errors occurred while "
2381 "sending queued messages."));
2383 gchar
*tmp
= g_strdup_printf(_("Some errors occurred "
2384 "while sending queued messages:\n%s"), errstr
);
2386 alertpanel_error_log(tmp
);
2392 static void folderview_search_cb(FolderView
*folderview
, guint action
,
2395 summary_search(folderview
->summaryview
);
2398 static void folderview_property_cb(FolderView
*folderview
, guint action
,
2401 GtkCTree
*ctree
= GTK_CTREE(folderview
->ctree
);
2404 if (!folderview
->selected
) return;
2406 item
= gtk_ctree_node_get_row_data(ctree
, folderview
->selected
);
2407 g_return_if_fail(item
!= NULL
);
2408 g_return_if_fail(item
->folder
!= NULL
);
2410 prefs_folder_item_open(item
);
2413 static void folderview_recollapse_nodes(FolderView
*folderview
, GtkCTreeNode
*node
)
2415 GSList
*list
= NULL
;
2416 GSList
*done
= NULL
;
2417 GtkCTree
*ctree
= GTK_CTREE(folderview
->ctree
);
2419 for (list
= folderview
->nodes_to_recollapse
; list
!= NULL
; list
= g_slist_next(list
)) {
2420 if (!gtkut_ctree_node_is_parent(GTK_CTREE_NODE(list
->data
), node
)
2421 && list
->data
!= node
) {
2422 gtk_ctree_collapse(ctree
, GTK_CTREE_NODE(list
->data
));
2423 done
= g_slist_append(done
, GTK_CTREE_NODE(list
->data
));
2426 for (list
= done
; list
!= NULL
; list
= g_slist_next(list
)) {
2427 folderview
->nodes_to_recollapse
= g_slist_remove(folderview
->nodes_to_recollapse
,
2433 void folderview_move_folder(FolderView
*folderview
, FolderItem
*from_folder
,
2434 FolderItem
*to_folder
, gboolean copy
)
2436 FolderItem
*from_parent
= NULL
;
2437 FolderItem
*new_folder
= NULL
;
2438 GtkCTreeNode
*src_node
= NULL
;
2442 g_return_if_fail(folderview
!= NULL
);
2443 g_return_if_fail(from_folder
!= NULL
);
2444 g_return_if_fail(to_folder
!= NULL
);
2446 src_node
= gtk_ctree_find_by_row_data(GTK_CTREE(folderview
->ctree
), NULL
, from_folder
);
2447 from_parent
= folder_item_parent(from_folder
);
2449 if (prefs_common
.warn_dnd
) {
2450 buf
= g_strdup_printf(copy
? _("Do you really want to copy folder '%s' in '%s' ?"):
2451 _("Do you really want to make folder '%s' a sub-folder of '%s' ?"),
2452 from_folder
->name
, to_folder
->name
);
2453 status
= alertpanel_full(copy
? _("Copy folder"):_("Move folder"), buf
,
2454 GTK_STOCK_NO
, GTK_STOCK_YES
, NULL
, TRUE
,
2455 NULL
, ALERT_QUESTION
, G_ALERTDEFAULT
);
2458 if ((status
& ~G_ALERTDISABLE
) != G_ALERTALTERNATE
)
2460 else if (status
& G_ALERTDISABLE
)
2461 prefs_common
.warn_dnd
= FALSE
;
2464 buf
= g_strdup_printf(copy
? _("Copying %s to %s..."):_("Moving %s to %s..."),
2465 from_folder
->name
, to_folder
->name
);
2466 STATUSBAR_PUSH(folderview
->mainwin
, buf
);
2468 summary_clear_all(folderview
->summaryview
);
2469 folderview
->opened
= NULL
;
2470 folderview
->selected
= NULL
;
2471 gtk_widget_set_sensitive(GTK_WIDGET(folderview
->ctree
), FALSE
);
2473 main_window_cursor_wait(folderview
->mainwin
);
2475 statusbar_verbosity_set(FALSE
);
2476 folder_item_update_freeze();
2477 if ((status
= folder_item_move_to(from_folder
, to_folder
, &new_folder
, copy
)) == F_MOVE_OK
) {
2478 statusbar_verbosity_set(FALSE
);
2479 main_window_cursor_normal(folderview
->mainwin
);
2480 STATUSBAR_POP(folderview
->mainwin
);
2481 folder_item_update_thaw();
2482 folder_item_update_recursive(new_folder
, F_ITEM_UPDATE_MSGCNT
);
2484 folderview_sort_folders(folderview
,
2485 gtk_ctree_find_by_row_data(GTK_CTREE(folderview
->ctree
),
2486 NULL
, to_folder
), new_folder
->folder
);
2487 folderview_select(folderview
, new_folder
);
2489 statusbar_verbosity_set(FALSE
);
2490 main_window_cursor_normal(folderview
->mainwin
);
2491 STATUSBAR_POP(folderview
->mainwin
);
2492 folder_item_update_thaw();
2494 case F_MOVE_FAILED_DEST_IS_PARENT
:
2495 alertpanel_error(_("Source and destination are the same."));
2497 case F_MOVE_FAILED_DEST_IS_CHILD
:
2498 alertpanel_error(copy
? _("Can't copy a folder to one of its children."):
2499 _("Can't move a folder to one of its children."));
2501 case F_MOVE_FAILED_DEST_OUTSIDE_MAILBOX
:
2502 alertpanel_error(_("Folder moving cannot be done between different mailboxes."));
2505 alertpanel_error(copy
? _("Copy failed!"):_("Move failed!"));
2510 gtk_widget_set_sensitive(GTK_WIDGET(folderview
->ctree
), TRUE
);
2513 static gint
folderview_clist_compare(GtkCList
*clist
,
2514 gconstpointer ptr1
, gconstpointer ptr2
)
2516 FolderItem
*item1
= ((GtkCListRow
*)ptr1
)->data
;
2517 FolderItem
*item2
= ((GtkCListRow
*)ptr2
)->data
;
2520 return (item2
->name
!= NULL
);
2524 return g_utf8_collate(item1
->name
, item2
->name
);
2527 static void folderview_processing_cb(FolderView
*folderview
, guint action
,
2530 GtkCTree
*ctree
= GTK_CTREE(folderview
->ctree
);
2534 if (!folderview
->selected
) return;
2536 item
= gtk_ctree_node_get_row_data(ctree
, folderview
->selected
);
2537 g_return_if_fail(item
!= NULL
);
2538 g_return_if_fail(item
->folder
!= NULL
);
2540 id
= folder_item_get_identifier(item
);
2541 title
= g_strdup_printf (_("Processing configuration for folder %s"), id
);
2544 prefs_filtering_open(&item
->prefs
->processing
, title
,
2545 MANUAL_ANCHOR_PROCESSING
, NULL
, NULL
, FALSE
);
2549 void folderview_set_target_folder_color(gint color_op
)
2553 FolderView
*folderview
;
2555 for (list
= folderview_list
; list
!= NULL
; list
= list
->next
) {
2556 folderview
= (FolderView
*)list
->data
;
2557 gtkut_convert_int_to_gdk_color(color_op
, &folderview
->color_op
);
2559 bold_tgtfold_style
->fg
[GTK_STATE_NORMAL
] =
2560 folderview
->color_op
;
2566 static gchar
*last_font
= NULL
;
2567 void folderview_reflect_prefs_pixmap_theme(FolderView
*folderview
)
2575 void folderview_reflect_prefs(void)
2577 gboolean update_font
= TRUE
;
2578 FolderView
*folderview
= mainwindow_get_mainwindow()->folderview
;
2579 FolderItem
*item
= folderview_get_selected_item(folderview
);
2580 GtkAdjustment
*pos
= gtk_scrolled_window_get_vadjustment(
2581 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
2582 gint height
= pos
->value
;
2584 if (last_font
&& !strcmp(last_font
, NORMAL_FONT
))
2585 update_font
= FALSE
;
2588 last_font
= g_strdup(NORMAL_FONT
);
2591 normal_style
= normal_color_style
= bold_style
=
2592 bold_color_style
= bold_tgtfold_style
= NULL
;
2594 folderview_init(folderview
);
2596 gtk_clist_freeze(GTK_CLIST(folderview
->ctree
));
2597 folderview_column_set_titles(folderview
);
2598 folderview_set_all();
2600 g_signal_handlers_block_by_func
2601 (G_OBJECT(folderview
->ctree
),
2602 G_CALLBACK(folderview_selected
), folderview
);
2605 GtkCTreeNode
*node
= gtk_ctree_find_by_row_data(
2606 GTK_CTREE(folderview
->ctree
), NULL
, item
);
2608 folderview_select(folderview
, item
);
2609 folderview
->open_folder
= FALSE
;
2610 folderview
->selected
= node
;
2613 g_signal_handlers_unblock_by_func
2614 (G_OBJECT(folderview
->ctree
),
2615 G_CALLBACK(folderview_selected
), folderview
);
2617 pos
= gtk_scrolled_window_get_vadjustment(
2618 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
2619 gtk_adjustment_set_value(pos
, height
);
2620 gtk_clist_thaw(GTK_CLIST(folderview
->ctree
));
2623 static void drag_state_stop(FolderView
*folderview
)
2625 if (folderview
->drag_timer
)
2626 g_source_remove(folderview
->drag_timer
);
2627 folderview
->drag_timer
= 0;
2628 folderview
->drag_node
= NULL
;
2631 static gint
folderview_defer_expand(FolderView
*folderview
)
2633 if (folderview
->drag_node
) {
2634 folderview_recollapse_nodes(folderview
, folderview
->drag_node
);
2635 if (folderview
->drag_item
->collapsed
) {
2636 gtk_ctree_expand(GTK_CTREE(folderview
->ctree
), folderview
->drag_node
);
2637 folderview
->nodes_to_recollapse
= g_slist_append
2638 (folderview
->nodes_to_recollapse
, folderview
->drag_node
);
2641 folderview
->drag_item
= NULL
;
2642 folderview
->drag_timer
= 0;
2646 static void drag_state_start(FolderView
*folderview
, GtkCTreeNode
*node
, FolderItem
*item
)
2648 /* the idea is that we call drag_state_start() whenever we want expansion to
2649 * start after 'prefs_common.hover_time' msecs. if we want to cancel expansion,
2650 * we need to call drag_state_stop() */
2651 drag_state_stop(folderview
);
2652 /* request expansion */
2653 if (0 != (folderview
->drag_timer
= g_timeout_add
2654 (prefs_common
.hover_timeout
,
2655 (GtkFunction
)folderview_defer_expand
,
2657 folderview
->drag_node
= node
;
2658 folderview
->drag_item
= item
;
2662 static void folderview_start_drag(GtkWidget
*widget
, gint button
, GdkEvent
*event
,
2663 FolderView
*folderview
)
2665 GdkDragContext
*context
;
2667 g_return_if_fail(folderview
!= NULL
);
2668 if (folderview
->selected
== NULL
) return;
2669 if (folderview
->nodes_to_recollapse
)
2670 g_slist_free(folderview
->nodes_to_recollapse
);
2671 folderview
->nodes_to_recollapse
= NULL
;
2672 context
= gtk_drag_begin(widget
, folderview
->target_list
,
2673 GDK_ACTION_MOVE
|GDK_ACTION_COPY
|GDK_ACTION_DEFAULT
, button
, event
);
2674 gtk_drag_set_icon_default(context
);
2677 static void folderview_drag_data_get(GtkWidget
*widget
,
2678 GdkDragContext
*drag_context
,
2679 GtkSelectionData
*selection_data
,
2682 FolderView
*folderview
)
2686 gchar
*source
= NULL
;
2687 if (info
== TARGET_DUMMY
) {
2688 for (cur
= GTK_CLIST(folderview
->ctree
)->selection
;
2689 cur
!= NULL
; cur
= cur
->next
) {
2690 item
= gtk_ctree_node_get_row_data
2691 (GTK_CTREE(folderview
->ctree
),
2692 GTK_CTREE_NODE(cur
->data
));
2694 source
= g_strdup_printf ("FROM_OTHER_FOLDER%s", folder_item_get_identifier(item
));
2695 gtk_selection_data_set(selection_data
,
2696 selection_data
->target
, 8,
2697 source
, strlen(source
));
2703 g_warning("unknown info %d\n", info
);
2707 static gboolean
folderview_update_folder(gpointer source
, gpointer userdata
)
2709 FolderUpdateData
*hookdata
;
2710 FolderView
*folderview
;
2714 folderview
= (FolderView
*) userdata
;
2715 g_return_val_if_fail(hookdata
!= NULL
, FALSE
);
2716 g_return_val_if_fail(folderview
!= NULL
, FALSE
);
2718 ctree
= folderview
->ctree
;
2719 g_return_val_if_fail(ctree
!= NULL
, FALSE
);
2721 if (hookdata
->update_flags
& FOLDER_ADD_FOLDERITEM
)
2722 folderview_create_folder_node(folderview
, hookdata
->item
);
2723 else if (hookdata
->update_flags
& FOLDER_RENAME_FOLDERITEM
) {
2724 GtkCTreeNode
*node
= gtk_ctree_find_by_row_data(GTK_CTREE(ctree
),
2725 NULL
, folder_item_parent(hookdata
->item
));
2726 folderview_sort_folders(folderview
, node
, hookdata
->folder
);
2727 } else if (hookdata
->update_flags
& FOLDER_REMOVE_FOLDERITEM
) {
2730 node
= gtk_ctree_find_by_row_data(GTK_CTREE(ctree
), NULL
, hookdata
->item
);
2732 gtk_ctree_remove_node(GTK_CTREE(ctree
), node
);
2733 if (folderview
->selected
== node
)
2734 folderview
->selected
= NULL
;
2735 if (folderview
->opened
== node
)
2736 folderview
->opened
= NULL
;
2738 } else if (hookdata
->update_flags
& (FOLDER_TREE_CHANGED
| FOLDER_ADD_FOLDER
| FOLDER_REMOVE_FOLDER
))
2739 folderview_set(folderview
);
2744 static gboolean
folderview_drag_motion_cb(GtkWidget
*widget
,
2745 GdkDragContext
*context
,
2749 FolderView
*folderview
)
2752 FolderItem
*item
= NULL
, *src_item
= NULL
;
2753 GtkCTreeNode
*node
= NULL
;
2754 gboolean acceptable
= FALSE
;
2755 GtkAdjustment
*pos
= gtk_scrolled_window_get_vadjustment(
2756 GTK_SCROLLED_WINDOW(folderview
->scrolledwin
));
2757 int height
= (int)pos
->page_size
;
2758 int total_height
= (int)pos
->upper
;
2759 int vpos
= (int) pos
->value
;
2761 if (gtk_clist_get_selection_info
2762 (GTK_CLIST(widget
), x
- 24, y
- 24, &row
, &column
)) {
2763 GtkWidget
*srcwidget
;
2765 if (y
> height
- 24 && height
+ vpos
< total_height
)
2766 gtk_adjustment_set_value(pos
, (vpos
+5 > height
? height
: vpos
+5));
2768 if (y
< 48 && y
> 0)
2769 gtk_adjustment_set_value(pos
, (vpos
-5 < 0 ? 0 : vpos
-5));
2771 node
= gtk_ctree_node_nth(GTK_CTREE(widget
), row
);
2772 item
= gtk_ctree_node_get_row_data(GTK_CTREE(widget
), node
);
2773 src_item
= folderview
->summaryview
->folder_item
;
2775 srcwidget
= gtk_drag_get_source_widget(context
);
2776 if (srcwidget
== summary_get_main_widget(folderview
->summaryview
)) {
2777 /* comes from summaryview */
2778 /* we are copying messages, so only accept folder items that are not
2779 the source item, are no root items and can copy messages */
2780 if (item
&& item
->folder
&& folder_item_parent(item
) != NULL
&& src_item
&&
2781 src_item
!= item
&& FOLDER_CLASS(item
->folder
)->copy_msg
!= NULL
&&
2782 FOLDER_TYPE(item
->folder
) != F_UNKNOWN
)
2784 } else if (srcwidget
== folderview
->ctree
) {
2785 /* comes from folderview */
2786 /* we are moving folder items, only accept folders that are not
2787 the source items and can copy messages and create folder items */
2788 if (item
&& item
->folder
&& src_item
&& src_item
!= item
&&
2789 FOLDER_CLASS(item
->folder
)->copy_msg
!= NULL
&&
2790 FOLDER_CLASS(item
->folder
)->create_folder
!= NULL
&&
2791 ((FOLDER_TYPE(item
->folder
) != F_UNKNOWN
&& FOLDER_TYPE(src_item
->folder
) != F_UNKNOWN
)
2792 || item
->folder
== src_item
->folder
))
2795 /* comes from another app */
2796 /* we are adding messages, so only accept folder items that are
2797 no root items and can copy messages */
2798 if (item
&& item
->folder
&& folder_item_parent(item
) != NULL
2799 && FOLDER_CLASS(item
->folder
)->add_msg
!= NULL
&&
2800 FOLDER_TYPE(item
->folder
) != F_UNKNOWN
)
2805 if (acceptable
|| (src_item
&& src_item
== item
))
2806 drag_state_start(folderview
, node
, item
);
2809 g_signal_handlers_block_by_func
2811 G_CALLBACK(folderview_selected
), folderview
);
2812 gtk_ctree_select(GTK_CTREE(widget
), node
);
2813 g_signal_handlers_unblock_by_func
2815 G_CALLBACK(folderview_selected
), folderview
);
2816 gdk_drag_status(context
,
2817 (context
->actions
== GDK_ACTION_COPY
?
2818 GDK_ACTION_COPY
: GDK_ACTION_MOVE
) , time
);
2820 if (folderview
->opened
)
2821 gtk_ctree_select(GTK_CTREE(widget
), folderview
->opened
);
2822 gdk_drag_status(context
, 0, time
);
2828 static void folderview_drag_leave_cb(GtkWidget
*widget
,
2829 GdkDragContext
*context
,
2831 FolderView
*folderview
)
2833 drag_state_stop(folderview
);
2834 gtk_ctree_select(GTK_CTREE(widget
), folderview
->opened
);
2837 static void free_info (gpointer stuff
, gpointer data
)
2842 void folderview_finish_dnd(const gchar
*data
, GdkDragContext
*drag_context
,
2843 guint time
, FolderItem
*item
)
2846 GSList
*msglist
= NULL
;
2847 list
= uri_list_extract_filenames(data
);
2848 if (!(item
&& item
->folder
&& folder_item_parent(item
) != NULL
2849 && FOLDER_CLASS(item
->folder
)->add_msg
!= NULL
))
2851 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
2852 debug_print("item doesn't fit\n");
2856 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
2857 debug_print("list is empty\n");
2860 for (tmp
= list
; tmp
!= NULL
; tmp
= tmp
->next
) {
2861 MsgFileInfo
*info
= NULL
;
2863 if (file_is_email((gchar
*)tmp
->data
)) {
2864 info
= g_new0(MsgFileInfo
, 1);
2865 info
->msginfo
= NULL
;
2866 info
->file
= (gchar
*)tmp
->data
;
2867 msglist
= g_slist_prepend(msglist
, info
);
2868 debug_print("file is a mail\n");
2870 debug_print("file isn't a mail\n");
2874 msglist
= g_slist_reverse(msglist
);
2875 folder_item_add_msgs(item
, msglist
, FALSE
);
2876 g_slist_foreach(msglist
, free_info
, NULL
);
2877 g_slist_free(msglist
);
2878 gtk_drag_finish(drag_context
, TRUE
, FALSE
, time
);
2880 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
2882 list_free_strings(list
);
2886 static void folderview_drag_received_cb(GtkWidget
*widget
,
2887 GdkDragContext
*drag_context
,
2890 GtkSelectionData
*data
,
2893 FolderView
*folderview
)
2896 FolderItem
*item
= NULL
, *src_item
;
2899 if (info
== TARGET_DUMMY
) {
2900 drag_state_stop(folderview
);
2901 if ((void *)strstr(data
->data
, "FROM_OTHER_FOLDER") != (void *)data
->data
) {
2902 /* comes from summaryview */
2903 if (gtk_clist_get_selection_info
2904 (GTK_CLIST(widget
), x
- 24, y
- 24, &row
, &column
) == 0)
2907 node
= gtk_ctree_node_nth(GTK_CTREE(widget
), row
);
2908 item
= gtk_ctree_node_get_row_data(GTK_CTREE(widget
), node
);
2909 src_item
= folderview
->summaryview
->folder_item
;
2911 /* re-check (due to acceptable possibly set for folder moves */
2912 if (!(item
&& item
->folder
&& item
->path
&& !item
->no_select
&&
2913 src_item
&& src_item
!= item
&& FOLDER_CLASS(item
->folder
)->copy_msg
!= NULL
)) {
2916 if (item
&& src_item
) {
2917 switch (drag_context
->action
) {
2918 case GDK_ACTION_COPY
:
2919 summary_copy_selected_to(folderview
->summaryview
, item
);
2920 gtk_drag_finish(drag_context
, TRUE
, FALSE
, time
);
2922 case GDK_ACTION_MOVE
:
2923 case GDK_ACTION_DEFAULT
:
2925 if (FOLDER_CLASS(src_item
->folder
)->remove_msg
== NULL
)
2926 summary_copy_selected_to(folderview
->summaryview
, item
);
2928 summary_move_selected_to(folderview
->summaryview
, item
);
2929 gtk_drag_finish(drag_context
, TRUE
, TRUE
, time
);
2932 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
2934 /* comes from folderview */
2936 gboolean folder_is_normal
= TRUE
;
2937 gboolean copy
= (drag_context
->action
== GDK_ACTION_COPY
);
2939 source
= data
->data
+ 17;
2940 if (gtk_clist_get_selection_info
2941 (GTK_CLIST(widget
), x
- 24, y
- 24, &row
, &column
) == 0
2943 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
2946 node
= gtk_ctree_node_nth(GTK_CTREE(widget
), row
);
2947 item
= gtk_ctree_node_get_row_data(GTK_CTREE(widget
), node
);
2948 src_item
= folder_find_item_from_identifier(source
);
2952 src_item
->stype
== F_NORMAL
&&
2953 !folder_has_parent_of_type(src_item
, F_OUTBOX
) &&
2954 !folder_has_parent_of_type(src_item
, F_DRAFT
) &&
2955 !folder_has_parent_of_type(src_item
, F_QUEUE
) &&
2956 !folder_has_parent_of_type(src_item
, F_TRASH
);
2957 if (!item
|| item
->no_select
|| !src_item
2958 || !folder_is_normal
) {
2959 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
2963 folderview_move_folder(folderview
, src_item
, item
, copy
);
2964 gtk_drag_finish(drag_context
, TRUE
, TRUE
, time
);
2966 folderview
->nodes_to_recollapse
= NULL
;
2967 } else if (info
== TARGET_MAIL_URI_LIST
) {
2968 if (gtk_clist_get_selection_info
2969 (GTK_CLIST(widget
), x
- 24, y
- 24, &row
, &column
) == 0)
2972 node
= gtk_ctree_node_nth(GTK_CTREE(widget
), row
);
2974 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
2975 debug_print("no node\n");
2978 item
= gtk_ctree_node_get_row_data(GTK_CTREE(widget
), node
);
2980 gtk_drag_finish(drag_context
, FALSE
, FALSE
, time
);
2981 debug_print("no item\n");
2984 folderview_finish_dnd(data
->data
, drag_context
, time
, item
);
2988 static void folderview_drag_end_cb(GtkWidget
*widget
,
2989 GdkDragContext
*drag_context
,
2990 FolderView
*folderview
)
2992 drag_state_stop(folderview
);
2993 g_slist_free(folderview
->nodes_to_recollapse
);
2994 folderview
->nodes_to_recollapse
= NULL
;
2997 void folderview_register_popup(FolderViewPopup
*fpopup
)
3001 for (folderviews
= folderview_list
; folderviews
!= NULL
; folderviews
= g_list_next(folderviews
)) {
3002 FolderView
*folderview
= folderviews
->data
;
3003 GtkItemFactory
*factory
;
3005 factory
= create_ifactory(folderview
, fpopup
);
3006 g_hash_table_insert(folderview
->popups
, fpopup
->klass
, factory
);
3008 g_hash_table_insert(folderview_popups
, fpopup
->klass
, fpopup
);
3011 void folderview_unregister_popup(FolderViewPopup
*fpopup
)
3015 for (folderviews
= folderview_list
; folderviews
!= NULL
; folderviews
= g_list_next(folderviews
)) {
3016 FolderView
*folderview
= folderviews
->data
;
3018 g_hash_table_remove(folderview
->popups
, fpopup
->klass
);
3020 g_hash_table_remove(folderview_popups
, fpopup
->klass
);