2005-10-18 [colin] 1.9.15cvs72
[claws.git] / src / folderview.c
index 88f0b32ce4b8720847a1822e5dfbbcab4e530fea..f7b5344a9b2ef66688672a002a24c33d4996856a 100644 (file)
@@ -14,7 +14,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
 #include "defs.h"
@@ -64,6 +64,7 @@
 #include "folderutils.h"
 #include "partial_download.h"
 #include "prefs_folder_column.h"
+#include "filtering.h"
 
 #define COL_FOLDER_WIDTH       150
 #define COL_NUM_WIDTH          32
@@ -639,15 +640,7 @@ void folderview_init(FolderView *folderview)
        }
 
        if (!bold_style) {
-               PangoFontDescription *font_desc;
                bold_style = gtk_style_copy(gtk_widget_get_style(ctree));
-               font_desc = pango_font_description_from_string(BOLD_FONT);
-               if (font_desc) {
-                       if (bold_style->font_desc)
-                               pango_font_description_free
-                                       (bold_style->font_desc);
-                       bold_style->font_desc = font_desc;
-               }
                pango_font_description_set_weight
                        (bold_style->font_desc, PANGO_WEIGHT_BOLD);
                bold_color_style = gtk_style_copy(bold_style);
@@ -710,11 +703,25 @@ static void mark_all_read_cb(FolderView *folderview, guint action,
                              GtkWidget *widget)
 {
        FolderItem *item;
-
+       AlertValue val;
+       
        item = folderview_get_selected_item(folderview);
        if (item == NULL)
                return;
 
+       if (prefs_common.ask_mark_all_read) {
+               val = alertpanel_full(_("Mark all as read"),
+                       _("Do you really want to mark all mails in this "
+                         "folder as read ?"), GTK_STOCK_YES, GTK_STOCK_NO, NULL,
+                         TRUE, NULL, ALERT_QUESTION, G_ALERTDEFAULT);
+
+               if (val == G_ALERTALTERNATE ||
+                   val == (G_ALERTALTERNATE|G_ALERTDISABLE))
+                       return;
+               else if (val == (G_ALERTDEFAULT|G_ALERTDISABLE)) 
+                       prefs_common.ask_mark_all_read = FALSE;
+       }
+       
        summary_lock(folderview->summaryview);
        folder_item_update_freeze();
        if (folderview->summaryview->folder_item == item)
@@ -791,6 +798,44 @@ void folderview_select_next_unread(FolderView *folderview)
                folderview_select_node(folderview, node);
 }
 
+static GtkCTreeNode *folderview_find_next_new(GtkCTree *ctree,
+                                                GtkCTreeNode *node)
+{
+       FolderItem *item;
+
+       if (node)
+               node = gtkut_ctree_node_next(ctree, node);
+       else
+               node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
+
+       for (; node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
+               item = gtk_ctree_node_get_row_data(ctree, node);
+               if (item && item->new_msgs > 0 && item->stype != F_TRASH)
+                       return node;
+       }
+
+       return NULL;
+}
+
+void folderview_select_next_new(FolderView *folderview)
+{
+       GtkCTree *ctree = GTK_CTREE(folderview->ctree);
+       GtkCTreeNode *node = NULL;
+
+       if ((node = folderview_find_next_new(ctree, folderview->opened))
+           != NULL) {
+               folderview_select_node(folderview, node);
+               return;
+       }
+
+       if (!folderview->opened ||
+           folderview->opened == GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list))
+               return;
+       /* search again from the first node */
+       if ((node = folderview_find_next_new(ctree, NULL)) != NULL)
+               folderview_select_node(folderview, node);
+}
+
 FolderItem *folderview_get_selected_item(FolderView *folderview)
 {
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
@@ -850,7 +895,7 @@ void folderview_append_item(FolderItem *item)
                                gtk_clist_freeze(GTK_CLIST(ctree));
 
                                text[col_pos[F_COL_FOLDER]] = item->name;
-                               child = gtk_ctree_insert_node
+                               child = gtk_sctree_insert_node
                                        (ctree, node, NULL, text,
                                         FOLDER_SPACING,
                                         folderxpm, folderxpmmask,
@@ -925,7 +970,7 @@ static GtkWidget *label_window_create(const gchar *str)
        return window;
 }
 
-void folderview_rescan_tree(Folder *folder)
+void folderview_rescan_tree(Folder *folder, gboolean rebuild)
 {
        GtkWidget *window;
 
@@ -933,11 +978,24 @@ void folderview_rescan_tree(Folder *folder)
 
        if (!folder->klass->scan_tree) return;
 
+       if (rebuild && 
+           alertpanel_full(_("Rebuild folder tree"), 
+                        _("Rebuilding the folder tree will remove "
+                          "local caches. Do you want to continue?"),
+                        GTK_STOCK_YES, GTK_STOCK_NO, NULL, FALSE,
+                        NULL, ALERT_WARNING, G_ALERTALTERNATE) 
+               != G_ALERTDEFAULT) {
+               return;
+       }
+
        inc_lock();
-       window = label_window_create(_("Rebuilding folder tree..."));
+       if (rebuild)
+               window = label_window_create(_("Rebuilding folder tree..."));
+       else 
+               window = label_window_create(_("Scanning folder tree..."));
 
        folder_set_ui_func(folder, folderview_scan_tree_func, NULL);
-       folder_scan_tree(folder);
+       folder_scan_tree(folder, rebuild);
        folder_set_ui_func(folder, NULL, NULL);
 
        folderview_set_all();
@@ -969,7 +1027,6 @@ gint folderview_check_new(Folder *folder)
 
                inc_lock();
                main_window_lock(folderview->mainwin);
-               gtk_widget_set_sensitive(folderview->ctree, FALSE);
 
                for (node = GTK_CTREE_NODE(GTK_CLIST(ctree)->row_list);
                     node != NULL; node = gtkut_ctree_node_next(ctree, node)) {
@@ -994,7 +1051,6 @@ gint folderview_check_new(Folder *folder)
                        former_new_msgs += former_new;
                }
 
-               gtk_widget_set_sensitive(folderview->ctree, TRUE);
                main_window_unlock(folderview->mainwin);
                inc_unlock();
        }
@@ -1154,6 +1210,43 @@ static gboolean folderview_have_matching_children(FolderView *folderview,
        return folderview_have_matching_children_sub(folderview, item, FALSE);
 }
 
+static gboolean folderview_have_marked_children_sub(FolderView *folderview,
+                                                   FolderItem *item,
+                                                   gboolean in_sub)
+{
+       GNode *node = NULL;
+       
+       if (!item || !item->folder || !item->folder->node)
+               return FALSE;
+               
+       node = item->folder->node;
+       
+       node = g_node_find(node, G_PRE_ORDER, G_TRAVERSE_ALL, item);
+       node = node->children;
+
+       if (item->marked_msgs != 0) {
+               return TRUE;
+       }
+
+       while (node != NULL) {
+               if (node && node->data) {
+                       FolderItem *next_item = (FolderItem*) node->data;
+                       node = node->next;
+                       if (folderview_have_marked_children_sub(folderview,
+                                                               next_item, TRUE))
+                               return TRUE;
+               }
+       }
+
+       return FALSE;
+}
+
+static gboolean folderview_have_marked_children(FolderView *folderview,
+                                            FolderItem *item)
+{
+       return folderview_have_marked_children_sub(folderview, item, FALSE);
+}
+
 static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
 {
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
@@ -1171,13 +1264,28 @@ static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
        gboolean add_sub_match_mark;
        gboolean use_bold, use_color;
        gint *col_pos = folderview->col_pos;
-
+       SpecialFolderItemType stype;
+       
        item = gtk_ctree_node_get_row_data(ctree, node);
        g_return_if_fail(item != NULL);
 
-       mark = (item->marked_msgs != 0);
-
-       switch (item->stype) {
+       if (!GTK_CTREE_ROW(node)->expanded)
+               mark = folderview_have_marked_children(folderview, item);
+       else
+               mark = (item->marked_msgs != 0);
+
+       stype = item->stype;
+       if (stype == F_NORMAL) {
+               if (folder_has_parent_of_type(item, F_TRASH))
+                       stype = F_TRASH;
+               else if (folder_has_parent_of_type(item, F_DRAFT))
+                       stype = F_DRAFT;
+               else if (folder_has_parent_of_type(item, F_OUTBOX))
+                       stype = F_OUTBOX;
+               else if (folder_has_parent_of_type(item, F_QUEUE))
+                       stype = F_QUEUE;
+       }
+       switch (stype) {
        case F_INBOX:
                if (item->hide_read_msgs) {
                        xpm = mark?m_inboxhrmxpm:inboxhrmxpm;
@@ -1280,7 +1388,7 @@ static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
            prefs_common.display_folder_unread) {
                str = g_strdup_printf("%s (%d%s)", name, item->total_msgs,
                                      add_unread_mark ? "+" : "");
-               gtk_ctree_set_node_info(ctree, node, str, FOLDER_SPACING,
+               gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
                                        xpm, mask, openxpm, openmask,
                                        FALSE, GTK_CTREE_ROW(node)->expanded);
                g_free(str);
@@ -1294,7 +1402,7 @@ static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
                                              item->unreadmarked_msgs > 0 ? "!":"");
                else
                        str = g_strdup_printf("%s (+)", name);
-               gtk_ctree_set_node_info(ctree, node, str, FOLDER_SPACING,
+               gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
                                        xpm, mask, openxpm, openmask,
                                        FALSE, GTK_CTREE_ROW(node)->expanded);
                g_free(str);
@@ -1302,7 +1410,7 @@ static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
                str = g_strdup_printf("%s%s", name, 
                                      item->unreadmarked_msgs > 0 ? " (!)":"");
        
-               gtk_ctree_set_node_info(ctree, node, str, FOLDER_SPACING,
+               gtk_sctree_set_node_info(ctree, node, str, FOLDER_SPACING,
                                        xpm, mask, openxpm, openmask,
                                        FALSE, GTK_CTREE_ROW(node)->expanded);
                g_free(str);
@@ -1328,7 +1436,8 @@ static void folderview_update_node(FolderView *folderview, GtkCTreeNode *node)
                use_bold = use_color = (item->total_msgs > 0);
        } else {
                /* if unread messages exist, print with bold font */
-               use_bold = (item->unread_msgs > 0) || add_unread_mark;
+               use_bold = (item->unread_msgs > 0|| item->new_msgs > 0) 
+                               || add_unread_mark;
                /* if new messages exist, print with colored letter */
                use_color =
                        (item->new_msgs > 0) ||
@@ -1641,11 +1750,13 @@ static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *even
        if (NULL != (ac = account_find_from_item(item)))
                special_trash = account_get_special_folder(ac, F_TRASH);
 
-       if ((item == folder->trash || item == special_trash) &&
+       if ((item == folder->trash || item == special_trash
+            || folder_has_parent_of_type(item, F_TRASH)) &&
            gtk_item_factory_get_item(fpopup_factory, "/Empty trash...") == NULL) {
                gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[0], folderview, 1);
                gtk_item_factory_create_item(fpopup_factory, &folder_view_trash_popup_entries[1], folderview, 1);
-       } else if (item != folder->trash && (special_trash == NULL || item != special_trash)) {
+       } else if (item != folder->trash && (special_trash == NULL || item != special_trash)
+               && !folder_has_parent_of_type(item, F_TRASH)) {
                gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[0]);
                gtk_item_factory_delete_entry(fpopup_factory, &folder_view_trash_popup_entries[1]);
        }
@@ -1658,7 +1769,8 @@ static gboolean folderview_button_pressed(GtkWidget *ctree, GdkEventButton *even
                 folderview->selected == folderview->opened);
        SET_SENS("/Properties...", item->node->parent != NULL);
        SET_SENS("/Processing...", item->node->parent != NULL);
-       if (item == folder->trash || item == special_trash) {
+       if (item == folder->trash || item == special_trash
+           || folder_has_parent_of_type(item, F_TRASH)) {
                GSList *msglist = folder_item_get_msg_list(item);
                SET_SENS("/Empty trash...", msglist != NULL);
                procmsg_msg_list_free(msglist);
@@ -1720,6 +1832,58 @@ static gboolean folderview_key_pressed(GtkWidget *widget, GdkEventKey *event,
        return FALSE;
 }
 
+static void summary_freeze_for_proc(gpointer data)
+{
+       FolderView *folderview = (FolderView *)data;
+       debug_print("freezing during processing...\n");
+       gtk_clist_freeze(GTK_CLIST(folderview->summaryview->ctree));
+}
+
+static void summary_thaw_for_proc(gpointer data)
+{
+       FolderView *folderview = (FolderView *)data;
+       debug_print("thawing after processing\n");
+       gtk_clist_thaw(GTK_CLIST(folderview->summaryview->ctree));
+}
+
+void folderview_process_open(FolderView *folderview, FolderItem *item)
+{
+       if (!item)
+               return;
+
+       folder_item_update_freeze();
+       folder_item_process_open(item, 
+               summary_freeze_for_proc,
+               summary_thaw_for_proc,
+               folderview);
+       folder_item_update_thaw();
+       
+       return; 
+}
+
+#if 0
+gboolean folderview_process_open_cb(gpointer data)
+{
+       FolderView *folderview = (FolderView *)data;
+       FolderItem *item = NULL;
+       
+       if (!folderview || !folderview->opened) {
+               debug_print("opened NULL\n");
+               return FALSE;
+       }
+       item = gtk_ctree_node_get_row_data(
+               GTK_CTREE(folderview->ctree), 
+               folderview->opened);
+       
+       if (!item)
+               return FALSE;
+
+       folderview_process_open(folderview, item);
+       
+       return FALSE;   
+}
+#endif
+
 static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
                                gint column, FolderView *folderview)
 {
@@ -1757,6 +1921,7 @@ static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
                if (olditem) {
                        /* will be null if we just moved the previously opened folder */
                        summary_save_prefs_to_folderitem(folderview->summaryview, olditem);
+                       summary_show(folderview->summaryview, NULL);
                        folder_item_close(olditem);
                }
        }
@@ -1805,6 +1970,8 @@ static void folderview_selected(GtkCTree *ctree, GtkCTreeNode *row,
 
                return;
         }
+       
+       folderview_process_open(folderview, item);
 
        main_window_cursor_normal(folderview->mainwin);
 
@@ -1857,8 +2024,6 @@ static void folderview_popup_close(GtkMenuShell *menu_shell,
 {
        if (!folderview->opened) return;
 
-       gtkut_ctree_set_focus_row(GTK_CTREE(folderview->ctree),
-                                 folderview->opened);
        gtk_ctree_select(GTK_CTREE(folderview->ctree), folderview->opened);
 }
 
@@ -1897,6 +2062,7 @@ void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
        gchar *text[N_FOLDER_COLS] = {NULL, "0", "0", "0"};
        GtkCTreeNode *node, *parent_node;
        gint *col_pos = folderview->col_pos;
+       FolderItemUpdateData hookdata;
 
        parent_node = gtk_ctree_find_by_row_data(ctree, NULL, folder_item_parent(item));
        if (parent_node == NULL)
@@ -1905,7 +2071,7 @@ void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
        gtk_clist_freeze(GTK_CLIST(ctree));
 
        text[col_pos[F_COL_FOLDER]] = item->name;
-       node = gtk_ctree_insert_node(ctree, parent_node, NULL, text,
+       node = gtk_sctree_insert_node(ctree, parent_node, NULL, text,
                                     FOLDER_SPACING,
                                     folderxpm, folderxpmmask,
                                     folderopenxpm, folderopenxpmmask,
@@ -1916,6 +2082,11 @@ void folderview_create_folder_node(FolderView *folderview, FolderItem *item)
                gtk_ctree_node_set_row_style(ctree, node, normal_style);
        folderview_sort_folders(folderview, parent_node, item->folder);
 
+       hookdata.item = item;
+       hookdata.update_flags = F_ITEM_UPDATE_NAME;
+       hookdata.msg = NULL;
+       hooks_invoke(FOLDER_ITEM_UPDATE_HOOKLIST, &hookdata);
+
        gtk_clist_thaw(GTK_CLIST(ctree));
 }
 
@@ -1926,10 +2097,10 @@ static void folderview_empty_trash_cb(FolderView *folderview, guint action,
        FolderItem *item;
        GSList *mlist = NULL;
        GSList *cur = NULL;
-       if (!folderview->selected) return;
        FolderItem *special_trash = NULL;
        PrefsAccount *ac;
 
+       if (!folderview->selected) return;
        item = gtk_ctree_node_get_row_data(ctree, folderview->selected);
        g_return_if_fail(item != NULL);
        g_return_if_fail(item->folder != NULL);
@@ -1937,7 +2108,8 @@ static void folderview_empty_trash_cb(FolderView *folderview, guint action,
        if (NULL != (ac = account_find_from_item(item)))
                special_trash = account_get_special_folder(ac, F_TRASH);
 
-       if (item != item->folder->trash && item != special_trash) return;
+       if (item != item->folder->trash && item != special_trash
+       &&  !folder_has_parent_of_type(item, F_TRASH)) return;
        
        if (prefs_common.ask_on_clean) {
                if (alertpanel(_("Empty trash"),
@@ -2103,6 +2275,7 @@ static void folderview_processing_cb(FolderView *folderview, guint action,
 {
        GtkCTree *ctree = GTK_CTREE(folderview->ctree);
        FolderItem *item;
+       gchar *id, *title;
 
        if (!folderview->selected) return;
 
@@ -2110,8 +2283,12 @@ static void folderview_processing_cb(FolderView *folderview, guint action,
        g_return_if_fail(item != NULL);
        g_return_if_fail(item->folder != NULL);
 
-       prefs_filtering_open(&item->prefs->processing,
-                            _("Processing configuration"), NULL, NULL);
+       id = folder_item_get_identifier(item);
+       title = g_strdup_printf (_("Processing configuration for folder %s"), id);
+       g_free (id);
+
+       prefs_filtering_open(&item->prefs->processing, title, NULL, NULL);
+       g_free (title);
 }
 
 void folderview_set_target_folder_color(gint color_op) 
@@ -2137,15 +2314,47 @@ void folderview_reflect_prefs_pixmap_theme(FolderView *folderview)
 
 void folderview_reflect_prefs(void)
 {
+       static gchar *last_font = NULL;
+       gboolean update_font = TRUE;
        FolderView *folderview = mainwindow_get_mainwindow()->folderview;
-       normal_style = normal_color_style = bold_style = 
-               bold_color_style = bold_tgtfold_style = NULL;
        FolderItem *item = folderview_get_selected_item(folderview);
-       folderview_init(folderview);
+       GtkAdjustment *pos = gtk_scrolled_window_get_vadjustment(
+                               GTK_SCROLLED_WINDOW(folderview->scrolledwin));
+       gint height = pos->value;
+
+       if (last_font && !strcmp(last_font, NORMAL_FONT))
+               update_font = FALSE;
+
+       if (last_font)
+               g_free(last_font);
+       
+       last_font = g_strdup(NORMAL_FONT);
+
+       if (update_font) {              
+               normal_style = normal_color_style = bold_style = 
+                       bold_color_style = bold_tgtfold_style = NULL;
+
+               folderview_init(folderview);
+       }
+       gtk_clist_freeze(GTK_CLIST(folderview->ctree));
        folderview_column_set_titles(folderview);
        folderview_set_all();
+
+       g_signal_handlers_block_by_func
+               (G_OBJECT(folderview->ctree),
+                G_CALLBACK(folderview_selected), folderview);
+
        if (item)
                folderview_select(folderview, item);
+
+       g_signal_handlers_unblock_by_func
+               (G_OBJECT(folderview->ctree),
+                G_CALLBACK(folderview_selected), folderview);
+
+       pos = gtk_scrolled_window_get_vadjustment(
+                               GTK_SCROLLED_WINDOW(folderview->scrolledwin));
+       gtk_adjustment_set_value(pos, height);
+       gtk_clist_thaw(GTK_CLIST(folderview->ctree));
 }
 
 static void drag_state_stop(FolderView *folderview)