2007-11-27 [colin] 3.1.0cvs40
[claws.git] / src / summaryview.c
index b116357a5abf8e89fdb663290a793cc452f96077..796d8c3d2502471edbaae243bba2feb80443db69 100644 (file)
@@ -313,6 +313,7 @@ static void summary_col_resized             (GtkCList               *clist,
 static void summary_reply_cb           (SummaryView            *summaryview,
                                         guint                   action,
                                         GtkWidget              *widget);
+#ifndef MAEMO
 static void summary_show_all_header_cb (SummaryView            *summaryview,
                                         guint                   action,
                                         GtkWidget              *widget);
@@ -320,13 +321,15 @@ static void summary_show_all_header_cb    (SummaryView            *summaryview,
 static void summary_add_address_cb     (SummaryView            *summaryview,
                                         guint                   action,
                                         GtkWidget              *widget);
+#endif
 static void summary_create_filter_cb   (SummaryView            *summaryview,
                                         guint                   action,
                                         GtkWidget              *widget);
+#ifndef MAEMO
 static void summary_create_processing_cb(SummaryView           *summaryview,
                                         guint                   action,
                                         GtkWidget              *widget);
-
+#endif
 static void summary_mark_clicked       (GtkWidget              *button,
                                         SummaryView            *summaryview);
 static void summary_status_clicked     (GtkWidget              *button,
@@ -441,6 +444,10 @@ static void summary_find_answers   (SummaryView    *summaryview,
 static gboolean summary_update_msg     (gpointer source, gpointer data);
 static gboolean summary_update_folder_item_hook(gpointer source, gpointer data);
 static gboolean summary_update_folder_hook(gpointer source, gpointer data);
+static void summary_set_colorlabel_color (GtkCTree             *ctree,
+                                  GtkCTreeNode         *node,
+                                  guint                 labelcolor);
+static void summary_thread_build(SummaryView *summaryview);
 
 GtkTargetEntry summary_drag_types[2] =
 {
@@ -574,11 +581,13 @@ GtkWidget *summary_get_main_widget(SummaryView *summaryview)
 }
 
 #define START_LONG_OPERATION(summaryview,force_freeze) {       \
+       if (summary_is_locked(summaryview))                     \
+               return;                                         \
        summary_lock(summaryview);                              \
        main_window_cursor_wait(summaryview->mainwin);          \
        if (force_freeze || sc_g_list_bigger(GTK_CLIST(summaryview->ctree)->selection, 1)) {\
-               froze = TRUE;                                           \
-               summary_freeze(summaryview);    \
+               froze = TRUE;                                   \
+               summary_freeze(summaryview);                    \
        }                                                       \
        folder_item_update_freeze();                            \
        inc_lock();                                             \
@@ -588,8 +597,9 @@ GtkWidget *summary_get_main_widget(SummaryView *summaryview)
 #define END_LONG_OPERATION(summaryview) {                      \
        inc_unlock();                                           \
        folder_item_update_thaw();                              \
-       if (froze)                                              \
-               summary_thaw(summaryview);      \
+       if (froze) {                                            \
+               summary_thaw(summaryview);                      \
+       }                                                       \
        main_window_cursor_normal(summaryview->mainwin);        \
        summary_unlock(summaryview);                            \
        summaryview->msginfo_update_callback_id =               \
@@ -1127,7 +1137,9 @@ gboolean summary_show(SummaryView *summaryview, FolderItem *item)
                }
        }
        if (!prefs_common.summary_quicksearch_sticky
-        && !prefs_common.summary_quicksearch_recurse
+        && (!prefs_common.summary_quicksearch_recurse
+         || !quicksearch_is_active(summaryview->quicksearch)
+         || (item && !quicksearch_is_in_subfolder(summaryview->quicksearch, item)))
         && !quicksearch_is_running(summaryview->quicksearch)
         && !is_refresh) {
                quicksearch_set(summaryview->quicksearch, prefs_common.summary_quicksearch_type, "");
@@ -1177,7 +1189,7 @@ gboolean summary_show(SummaryView *summaryview, FolderItem *item)
                g_free(buf);
                debug_print("empty folder (%p %s %p %d)\n\n",
                                item, 
-                               item?item->path:"NULL",
+                               (item && item->path)?item->path:"(null)",
                                item?folder_item_parent(item):0x0,
                                item?item->no_select:FALSE);
                summary_set_hide_read_msgs_menu(summaryview, FALSE);
@@ -1410,6 +1422,14 @@ gboolean summary_show(SummaryView *summaryview, FolderItem *item)
                                                 ? 0 : GTK_CLIST(ctree)->rows - 1);
                                }
                                break;
+                       case ACTION_FIRST_LIST:
+                               if (GTK_CLIST(ctree)->row_list != NULL) {
+                                       node = gtk_ctree_node_nth
+                                               (ctree,
+                                                item->sort_type == SORT_ASCENDING
+                                                ? 0 : GTK_CLIST(ctree)->rows - 1);
+                               }
+                               break;
                        case ACTION_NOTHING:
                        case ACTION_UNSET:
                                node = NULL;
@@ -1507,8 +1527,9 @@ void summary_lock(SummaryView *summaryview)
 
 void summary_unlock(SummaryView *summaryview)
 {
-       if (summaryview->lock_count)
+       if (summaryview->lock_count) {
                summaryview->lock_count--;
+       }
 }
 
 gboolean summary_is_locked(SummaryView *summaryview)
@@ -1571,7 +1592,9 @@ void summary_set_menu_sensitive(SummaryView *summaryview)
        GtkItemFactory *ifactory = summaryview->popupfactory;
        SensitiveCond state;
        gboolean sensitive;
+#ifndef MAEMO
        GtkWidget *menuitem;
+#endif
        gint i;
 
        static const struct {
@@ -2493,6 +2516,7 @@ static void summary_status_show(SummaryView *summaryview)
                g_free(str);
        }
 
+       summary_set_menu_sensitive(summaryview);
        toolbar_main_set_sensitive(summaryview->mainwin);
 }
 
@@ -4010,13 +4034,10 @@ void summary_delete(SummaryView *summaryview)
        if (!prefs_common.live_dangerously) {
                gchar *buf = NULL;
                int num = g_list_length(GTK_CLIST(summaryview->ctree)->selection);
-               if (num == 1)
-                       buf = g_strdup_printf(_(
-                               "Do you really want to delete the selected message?"));
-               else
-                       buf = g_strdup_printf(_(
-                               "Do you really want to delete the %d selected messages?"), 
-                               num);
+               buf = g_strdup_printf(ngettext(
+                       "Do you really want to delete the selected message?",
+                       "Do you really want to delete the %d selected messages?", num), 
+                       num);
                aval = alertpanel(_("Delete message(s)"),
                                  buf,
                                  GTK_STOCK_CANCEL, "+"GTK_STOCK_DELETE, NULL);
@@ -4176,6 +4197,12 @@ void summary_move_selected_to(SummaryView *summaryview, FolderItem *to_folder)
                return;
        }
 
+       if (to_folder->no_select) {
+               alertpanel_error(_("The destination folder can only be used to "
+                                  "store subfolders."));
+               return;
+       }
+
        START_LONG_OPERATION(summaryview, FALSE); 
 
        for (cur = GTK_CLIST(summaryview->ctree)->selection;
@@ -4267,6 +4294,12 @@ void summary_copy_selected_to(SummaryView *summaryview, FolderItem *to_folder)
                return;
        }
 
+       if (to_folder->no_select) {
+               alertpanel_error(_("The destination folder can only be used to "
+                                  "store subfolders."));
+               return;
+       }
+
        START_LONG_OPERATION(summaryview, FALSE);
 
        for (cur = GTK_CLIST(summaryview->ctree)->selection;
@@ -4296,17 +4329,43 @@ void summary_copy_to(SummaryView *summaryview)
 
 void summary_add_address(SummaryView *summaryview)
 {
-       MsgInfo *msginfo;
+       MsgInfo *msginfo, *full_msginfo;
        gchar *from;
+       GtkWidget *image = NULL;
+       GdkPixbuf *picture = NULL;
 
        msginfo = gtk_ctree_node_get_row_data(GTK_CTREE(summaryview->ctree),
                                              summaryview->selected);
-       if (!msginfo) return;
+       if (!msginfo || !msginfo->from) 
+               return;
 
        Xstrdup_a(from, msginfo->from, return);
        eliminate_address_comment(from);
        extract_address(from);
-       addressbook_add_contact(msginfo->fromname, from, NULL);
+       
+       full_msginfo = procmsg_msginfo_get_full_info(msginfo);
+       if (full_msginfo &&
+           full_msginfo->extradata &&
+           full_msginfo->extradata->face) {
+               image = face_get_from_header(full_msginfo->extradata->face);
+       } 
+#if HAVE_LIBCOMPFACE
+       else if (full_msginfo &&
+                full_msginfo->extradata &&
+                full_msginfo->extradata->xface) {
+               image = xface_get_from_header(full_msginfo->extradata->xface,
+                               &summaryview->ctree->style->white,
+                               summaryview->mainwin->window->window);  
+       }
+#endif
+       procmsg_msginfo_free(full_msginfo);
+       if (image)
+               picture = gtk_image_get_pixbuf(GTK_IMAGE(image));
+
+       addressbook_add_contact(msginfo->fromname, from, NULL, picture);
+
+       if (image)
+               gtk_widget_destroy(image);
 }
 
 void summary_select_all(SummaryView *summaryview)
@@ -4438,7 +4497,7 @@ void summary_save_as(SummaryView *summaryview)
 void summary_print(SummaryView *summaryview)
 {
        GtkCList *clist = GTK_CLIST(summaryview->ctree);
-#ifndef USE_GNOMEPRINT
+#if !defined(USE_GNOMEPRINT) && !GTK_CHECK_VERSION(2,10,0)
        GtkCTree *ctree = GTK_CTREE(summaryview->ctree);
        MsgInfo *msginfo;
        gchar *cmdline = NULL;
@@ -4458,7 +4517,7 @@ void summary_print(SummaryView *summaryview)
        g_free(msg);
 
        if (clist->selection == NULL) return;
-#ifndef USE_GNOMEPRINT
+#if !defined(USE_GNOMEPRINT) && !GTK_CHECK_VERSION(2,10,0)
        cmdline = input_dialog(_("Print"),
                               _("Enter the print command line:\n"
                                 "('%s' will be replaced with file name)"),
@@ -4754,7 +4813,7 @@ static void summary_execute_delete_func(GtkCTree *ctree, GtkCTreeNode *node,
 
 /* thread functions */
 
-void summary_thread_build(SummaryView *summaryview)
+static void summary_thread_build(SummaryView *summaryview)
 {
        GtkCTree *ctree = GTK_CTREE(summaryview->ctree);
        GtkCTreeNode *node;
@@ -5069,10 +5128,15 @@ void summary_filter(SummaryView *summaryview, gboolean selected_only)
        } else {
                mlist = folder_item_get_msg_list(summaryview->folder_item);
        }
+       
+       folder_item_set_batch(summaryview->folder_item, TRUE);
        for (cur_list = mlist; cur_list; cur_list = cur_list->next) {
                summary_filter_func((MsgInfo *)cur_list->data);
        }
+       folder_item_set_batch(summaryview->folder_item, FALSE);
+       
        filtering_move_and_copy_msgs(mlist);
+       
        for (cur_list = mlist; cur_list; cur_list = cur_list->next) {
                procmsg_msginfo_free((MsgInfo *)cur_list->data);
        }
@@ -5256,7 +5320,6 @@ static gboolean summary_set_row_tag(SummaryView *summaryview, GtkCTreeNode *row,
 
        procmsg_msginfo_update_tags(msginfo, set, id);
        
-       
        if (summaryview->col_state[summaryview->col_pos[S_COL_TAGS]].visible) {
                tags_str = procmsg_msginfo_get_tags_str(msginfo);
                gtk_ctree_node_set_text(ctree, row, 
@@ -5282,10 +5345,12 @@ void summary_set_tag(SummaryView *summaryview, gint tag_id,
        gboolean froze = FALSE;
        gboolean redisplay = FALSE;
        START_LONG_OPERATION(summaryview, FALSE);
+       folder_item_set_batch(summaryview->folder_item, TRUE);
        for (cur = GTK_CLIST(ctree)->selection; cur != NULL && cur->data != NULL; cur = cur->next) {
                redisplay |= summary_set_row_tag(summaryview,
                                           GTK_CTREE_NODE(cur->data), FALSE, set, real_id);
        }
+       folder_item_set_batch(summaryview->folder_item, FALSE);
        END_LONG_OPERATION(summaryview);
        if (redisplay)
                summary_redisplay_msg(summaryview);
@@ -5536,15 +5601,32 @@ static void summary_tags_menu_item_apply_tags_activate_cb(GtkWidget *widget,
        tag_apply_open(summary_get_selection(summaryview));     
 }
 
+static gint summary_tag_cmp_list(gconstpointer a, gconstpointer b)
+{
+       gint id_a = GPOINTER_TO_INT(a);
+       gint id_b = GPOINTER_TO_INT(b);
+       const gchar *tag_a = tags_get_tag(id_a);
+       const gchar *tag_b = tags_get_tag(id_b);
+       
+       if (tag_a == NULL)
+               return tag_b == NULL ? 0:1;
+       
+       if (tag_b == NULL)
+               return tag_a == NULL ? 0:1;
+
+       return g_utf8_collate(tag_a, tag_b);
+}
+
 static void summary_tags_menu_create(SummaryView *summaryview, gboolean refresh)
 {
        GtkWidget *label_menuitem;
        GtkWidget *menu;
        GtkWidget *item;
        GSList *cur = tags_get_list();
-       GSList *orig = cur;
+       GSList *orig = NULL;
        gboolean existing_tags = FALSE;
 
+       cur = orig = g_slist_sort(cur, summary_tag_cmp_list);
        label_menuitem = gtk_item_factory_get_item(summaryview->popupfactory,
                                                   "/Tags");
        g_signal_connect(G_OBJECT(label_menuitem), "activate",
@@ -5608,6 +5690,137 @@ static gboolean summary_popup_menu(GtkWidget *widget, gpointer data)
        return TRUE;
 }
 
+#if GTK_CHECK_VERSION(2,12,0) && !MAEMO
+static gchar *summaryview_get_tooltip_text(SummaryView *summaryview, MsgInfo *info, gint column)
+{
+       MsgFlags flags;
+
+       if (!info)
+               return NULL;
+
+       flags = info->flags;
+
+       switch(summaryview->col_state[column].type) {
+               case S_COL_STATUS:
+                       if (MSG_IS_IGNORE_THREAD(flags)) {
+                               return _("Ignored thread");
+                       } else if (MSG_IS_WATCH_THREAD(flags)) {
+                               return _("Watched thread");
+                       } else if (MSG_IS_SPAM(flags)) {
+                               return _("Spam");
+                       } else if (MSG_IS_NEW(flags)) {
+                               return _("New");
+                       } else if (MSG_IS_UNREAD(flags)) {
+                               return _("Unread");
+                       } else if (MSG_IS_REPLIED(flags)) {
+                               return _("Replied");
+                       } else if (MSG_IS_FORWARDED(flags)) {
+                               return _("Forwarded");
+                       } else {
+                               return NULL;
+                       }
+               case S_COL_MARK:
+                       if (MSG_IS_DELETED(flags)) {
+                               return _("Deleted");
+                       } else if (MSG_IS_MARKED(flags)) {
+                               return _("Marked");
+                       } else if (MSG_IS_MOVE(flags)) {
+                               return _("To be moved");
+                       } else if (MSG_IS_COPY(flags)) {
+                               return _("To be copied");
+                       } else {
+                               return NULL;
+                       }
+               case S_COL_LOCKED:
+                       if (MSG_IS_LOCKED(flags)) {
+                               return _("Locked");
+                       } else {
+                               return NULL;
+                       }
+               case S_COL_MIME:
+                       if (MSG_IS_WITH_ATTACHMENT(flags) && MSG_IS_SIGNED(flags)) {
+                               return _("Signed, has attachment(s)");
+                       } else if (MSG_IS_SIGNED(flags)) {
+                               return _("Signed");
+                       } else if (MSG_IS_WITH_ATTACHMENT(flags) && MSG_IS_ENCRYPTED(flags)) {
+                               return _("Encrypted, has attachment(s)");
+                       } else if (MSG_IS_ENCRYPTED(flags)) {
+                               return _("Encrypted");
+                       } else if (MSG_IS_WITH_ATTACHMENT(flags)) {
+                               return _("Has attachment(s)");
+                       } else {
+                               return NULL;
+                       }
+               default:
+                       return NULL;
+       }
+}
+static gboolean tooltip_cb (GtkWidget  *widget,
+                            gint        x,
+                            gint        y,
+                            gboolean    keyboard_mode,
+                            GtkTooltip *tooltip,
+                            gpointer    user_data) 
+{
+       GtkCTree *ctree = GTK_CTREE(widget);
+       SummaryView *summaryview = (SummaryView *)user_data;
+       gint row = -1, column = -1;
+       int offset = prefs_common.show_col_headers ? 24:0;
+       GtkCTreeNode *node = NULL;
+       gchar *text = NULL;
+       gchar *formatted = NULL;
+       MsgInfo *info = NULL;
+       GdkRectangle rect;
+
+       if (!prefs_common.show_tooltips)
+               return FALSE;
+
+       if (y - offset < 0)
+               return FALSE;
+
+       if (!gtk_clist_get_selection_info(GTK_CLIST(ctree), x, y - offset,
+                                         &row, &column))
+               return FALSE;
+
+       if ((node = gtk_ctree_node_nth(ctree, row)) == NULL)
+               return FALSE;
+
+       if ((info = gtk_ctree_node_get_row_data(ctree, node)) == NULL)
+               return FALSE;
+
+       switch (gtk_ctree_node_get_cell_type(ctree, node, column)) {
+               case GTK_CELL_TEXT:
+                       if (gtk_ctree_node_get_text(ctree, node, column, &text) != TRUE)
+                               return FALSE;
+                       break;
+               case GTK_CELL_PIXTEXT:
+                       if (gtk_ctree_node_get_pixtext(ctree, node, column, &text, 
+                               NULL, NULL, NULL) != TRUE)
+                               return FALSE;
+                       break;
+               default: 
+                       if ((text = summaryview_get_tooltip_text(summaryview, info, column)) == NULL)
+                               return FALSE;
+       }
+       
+       if (!text || !*text)
+               return FALSE;
+
+       formatted = g_strdup(text);
+       g_strstrip(formatted);
+       
+       gtk_tooltip_set_text (tooltip, formatted);
+       g_free(formatted);
+       
+       rect.x = x - 2;
+       rect.y = y - 2;
+       rect.width = 12;
+       rect.height= 12;        
+       gtk_tooltip_set_tip_area(tooltip, &rect);
+       
+       return TRUE;
+}
+#endif
 static GtkWidget *summary_ctree_create(SummaryView *summaryview)
 {
        GtkWidget *ctree;
@@ -5716,7 +5929,7 @@ static GtkWidget *summary_ctree_create(SummaryView *summaryview)
        CLIST_BUTTON_SIGNAL_CONNECT(S_COL_SCORE,   summary_score_clicked);
        CLIST_BUTTON_SIGNAL_CONNECT(S_COL_LOCKED,  summary_locked_clicked);
        CLIST_BUTTON_SIGNAL_CONNECT(S_COL_TAGS,    summary_tags_clicked);
-
+       
 #undef CLIST_BUTTON_SIGNAL_CONNECT
 
        g_signal_connect(G_OBJECT(ctree), "tree_select_row",
@@ -5774,6 +5987,12 @@ static GtkWidget *summary_ctree_create(SummaryView *summaryview)
                         G_CALLBACK(summary_drag_motion_cb),
                         summaryview);
 
+#if GTK_CHECK_VERSION(2,12,0) && !MAEMO
+       g_object_set (G_OBJECT(ctree), "has-tooltip", TRUE, NULL);
+       g_signal_connect(G_OBJECT(ctree), "query-tooltip", 
+                        G_CALLBACK(tooltip_cb),
+                       summaryview);
+#endif
        return ctree;
 }
 
@@ -5929,8 +6148,12 @@ static gboolean summary_key_pressed(GtkWidget *widget, GdkEventKey *event,
                case GDK_KP_Enter:
                        handled = TRUE;
                        if (summaryview->displayed != summaryview->selected) {
+#ifndef MAEMO
                                summary_display_msg(summaryview,
                                                    summaryview->selected);
+#else
+                               summary_open_row(NULL, summaryview);
+#endif
                                break;
                        }
                        mimeview_scroll_one_line(messageview->mimeview, mod_pressed);
@@ -6245,7 +6468,7 @@ static void summary_reply_cb(SummaryView *summaryview, guint action,
        compose_reply_from_messageview(msgview, msginfo_list, action);
        g_slist_free(msginfo_list);
 }
-
+#ifndef MAEMO
 static void summary_show_all_header_cb(SummaryView *summaryview,
                                       guint action, GtkWidget *widget)
 {
@@ -6260,19 +6483,19 @@ static void summary_add_address_cb(SummaryView *summaryview,
 {
        summary_add_address(summaryview);
 }
-
+#endif
 static void summary_create_filter_cb(SummaryView *summaryview,
                                     guint action, GtkWidget *widget)
 {
        summary_filter_open(summaryview, (PrefsFilterType)action, 0);
 }
-
+#ifndef MAEMO
 static void summary_create_processing_cb(SummaryView *summaryview,
                                         guint action, GtkWidget *widget)
 {
        summary_filter_open(summaryview, (PrefsFilterType)action, 1);
 }
-
+#endif
 static void summary_sort_by_column_click(SummaryView *summaryview,
                                         FolderSortKey sort_key)
 {
@@ -7201,7 +7424,9 @@ gint summaryview_export_mbox_list(SummaryView *summaryview)
        gchar *mbox = filesel_select_file_save(_("Export to mbox file"), NULL);
        gint ret;
        
-       if (mbox == NULL || list == NULL)
+       if (mbox == NULL)
+               return -2;
+       if (list == NULL)
                return -1;
                
        ret = export_list_to_mbox(list, mbox);