2007-10-24 [colin] 3.0.2cvs101
authorColin Leroy <colin@colino.net>
Wed, 24 Oct 2007 20:45:39 +0000 (20:45 +0000)
committerColin Leroy <colin@colino.net>
Wed, 24 Oct 2007 20:45:39 +0000 (20:45 +0000)
* src/edittags.c
* src/mainwindow.c
* src/summaryview.c
* src/textview.c
Add tags sorting (alphabetical); allow deletion of
tags from the Apply Tags window

ChangeLog
PATCHSETS
configure.ac
src/edittags.c
src/mainwindow.c
src/summaryview.c
src/textview.c

index d201418..68c46a4 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2007-10-24 [colin]     3.0.2cvs101
+
+       * src/edittags.c
+       * src/mainwindow.c
+       * src/summaryview.c
+       * src/textview.c
+               Add tags sorting (alphabetical); allow deletion of
+               tags from the Apply Tags window
+
 2007-10-24 [colin]     3.0.2cvs100
 
        * src/editaddress.c
index 83c762b..44be716 100644 (file)
--- a/PATCHSETS
+++ b/PATCHSETS
 ( cvs diff -u -r 1.13.2.17 -r 1.13.2.18 src/common/socket.h;  cvs diff -u -r 1.9.2.24 -r 1.9.2.25 src/common/ssl.c;  ) > 3.0.2cvs98.patchset
 ( cvs diff -u -r 1.101.2.43 -r 1.101.2.44 src/news.c;  ) > 3.0.2cvs99.patchset
 ( cvs diff -u -r 1.14.2.41 -r 1.14.2.42 src/editaddress.c;  cvs diff -u -r 1.1.2.5 -r 1.1.2.6 src/editaddress_other_attributes_ldap.c;  cvs diff -u -r 1.1.2.6 -r 1.1.2.7 src/editaddress_other_attributes_ldap.h;  cvs diff -u -r 1.2.2.15 -r 1.2.2.16 src/ldapctrl.c;  cvs diff -u -r 1.3.2.27 -r 1.3.2.28 src/ldapquery.c;  cvs diff -u -r 1.1.2.15 -r 1.1.2.16 src/ldapupdate.c;  ) > 3.0.2cvs100.patchset
+( cvs diff -u -r 1.1.2.7 -r 1.1.2.8 src/edittags.c;  cvs diff -u -r 1.274.2.218 -r 1.274.2.219 src/mainwindow.c;  cvs diff -u -r 1.395.2.332 -r 1.395.2.333 src/summaryview.c;  cvs diff -u -r 1.96.2.189 -r 1.96.2.190 src/textview.c;  ) > 3.0.2cvs101.patchset
index b6e2fcc..1ea8fd8 100644 (file)
@@ -11,7 +11,7 @@ MINOR_VERSION=0
 MICRO_VERSION=2
 INTERFACE_AGE=0
 BINARY_AGE=0
-EXTRA_VERSION=100
+EXTRA_VERSION=101
 EXTRA_RELEASE=
 EXTRA_GTK2_VERSION=
 
index a1a0105..a3d0bdc 100644 (file)
@@ -32,6 +32,7 @@
 #include <string.h>
 #include <errno.h>
 
+#include "menu.h"
 #include "edittags.h"
 #include "prefs_gtk.h"
 #include "utils.h"
@@ -56,6 +57,15 @@ enum {
        N_PREFS_TAGS_COLUMNS
 };
 
+       
+enum {
+       TAG_SELECTED,
+       TAG_SELECTED_INCONSISTENT,
+       TAG_NAME,
+       TAG_DATA,
+       N_TAG_EDIT_COLUMNS
+};
+
 static struct Tags
 {
        GtkWidget *window;
@@ -303,9 +313,6 @@ static void prefs_tags_set_dialog(void)
                                (GTK_TREE_VIEW(tags.tags_list_view)));
        gtk_list_store_clear(store);
 
-       prefs_tags_list_view_insert_tag(tags.tags_list_view,
-                                             NULL, _("(New)"), -1);
-
        for (orig = cur = tags_get_list(); cur != NULL; cur = cur->next) {
                gint id = GPOINTER_TO_INT(cur->data);
                gchar *tag = (gchar *) tags_get_tag(id);
@@ -449,12 +456,37 @@ static void prefs_tags_ok(GtkWidget *widget, gpointer data)
        gtk_widget_hide(tags.window);
 }
 
+gint tag_cmp_func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer userdata)
+ {
+       gchar *name1, *name2;
+
+       if (GPOINTER_TO_INT(userdata) == 0) {
+               gtk_tree_model_get(model, a, PREFS_TAGS_STRING, &name1, -1);
+               gtk_tree_model_get(model, b, PREFS_TAGS_STRING, &name2, -1);
+       } else {
+               gtk_tree_model_get(model, a, TAG_NAME, &name1, -1);
+               gtk_tree_model_get(model, b, TAG_NAME, &name2, -1);
+       }
+       if (name1 == NULL)
+               return name2 == NULL ? 0:1;
+       
+       if (name2 == NULL)
+               return name1 == NULL ? 0:1;
+       
+       return g_utf8_collate(name1,name2);
+}
+
 static GtkListStore* prefs_tags_create_data_store(void)
 {
-       return gtk_list_store_new(N_PREFS_TAGS_COLUMNS,
+       GtkListStore *store = gtk_list_store_new(N_PREFS_TAGS_COLUMNS,
                                  G_TYPE_STRING,        
                                  G_TYPE_INT,
                                  -1);
+       GtkTreeSortable *sortable = GTK_TREE_SORTABLE(store);
+
+       gtk_tree_sortable_set_sort_func(sortable, 0, tag_cmp_func,
+                                    GINT_TO_POINTER(0), NULL);
+       return store;
 }
 
 static void prefs_tags_list_view_insert_tag(GtkWidget *list_view,
@@ -493,6 +525,8 @@ static GtkWidget *prefs_tags_list_view_create(void)
        GtkTreeModel *model;
 
        model = GTK_TREE_MODEL(prefs_tags_create_data_store());
+       gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model), PREFS_TAGS_STRING, GTK_SORT_ASCENDING);
+
        list_view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(model));
        g_object_unref(model);  
        
@@ -556,14 +590,6 @@ static gboolean prefs_tags_selected(GtkTreeSelection *selector,
        return TRUE;
 }
 
-enum {
-       TAG_SELECTED,
-       TAG_SELECTED_INCONSISTENT,
-       TAG_NAME,
-       TAG_DATA,
-       N_TAG_EDIT_COLUMNS
-};
-
 static void apply_window_create(void);
 
 static struct TagApplyWindow
@@ -601,12 +627,18 @@ void tag_apply_open(GSList *msglist)
 
 static GtkListStore* apply_window_create_data_store(void)
 {
-       return gtk_list_store_new(N_TAG_EDIT_COLUMNS,
+       GtkListStore *store = gtk_list_store_new(N_TAG_EDIT_COLUMNS,
                                  G_TYPE_BOOLEAN,
                                  G_TYPE_BOOLEAN,
                                  G_TYPE_STRING,
                                  G_TYPE_POINTER,
                                  -1);
+       GtkTreeSortable *sortable = GTK_TREE_SORTABLE(store);
+
+       gtk_tree_sortable_set_sort_func(sortable, 0, tag_cmp_func,
+                                    GINT_TO_POINTER(1), NULL);
+
+       return store;
 }
 
 static void tag_apply_selected_toggled(GtkCellRendererToggle *widget,
@@ -648,6 +680,66 @@ static void apply_window_create_list_view_columns(GtkWidget *list_view)
                                        TAG_NAME);
 }
 
+static GtkItemFactory *apply_popup_factory = NULL;
+static GtkWidget *apply_popup_menu = NULL;
+
+static void apply_popup_delete (void *obj, guint action, void *data)
+{
+       GtkTreeIter sel;
+       GtkTreeModel *model;
+       gint id;
+       SummaryView *summaryview = NULL;
+       
+       if (!gtk_tree_selection_get_selected(gtk_tree_view_get_selection
+                               (GTK_TREE_VIEW(applywindow.taglist)),
+                               &model, &sel))
+               return;                         
+
+       if (alertpanel(_("Delete tag"),
+                      _("Do you really want to delete this tag?"),
+                      GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL) != G_ALERTALTERNATE)
+               return;
+
+       /* XXX: Here's the reason why we need to store the original 
+        * pointer: we search the slist for it. */
+       gtk_tree_model_get(model, &sel,
+                          TAG_DATA, &id,
+                          -1);
+       gtk_list_store_remove(GTK_LIST_STORE(model), &sel);
+       if (mainwindow_get_mainwindow() != NULL)
+               summaryview = mainwindow_get_mainwindow()->summaryview;
+       if (summaryview)
+               summary_set_tag(summaryview, -id, NULL);
+       tags_remove_tag(id);
+       tags_write_tags();
+}
+
+static GtkItemFactoryEntry apply_popup_entries[] =
+{
+       {N_("/_Delete"),                NULL, apply_popup_delete, 0, NULL, NULL},
+};
+
+
+static gint apply_list_btn_pressed(GtkWidget *widget, GdkEventButton *event,
+                                   GtkTreeView *list_view)
+{
+       if (event && event->button == 3) {
+               if (!apply_popup_menu) {
+                       gint n_entries = sizeof(apply_popup_entries) /
+                               sizeof(apply_popup_entries[0]);
+                       apply_popup_menu = menu_create_items(apply_popup_entries, n_entries,
+                                                     "<TagPopupMenu>", &apply_popup_factory,
+                                                     list_view);
+               }
+               gtk_menu_popup(GTK_MENU(apply_popup_menu), 
+                              NULL, NULL, NULL, NULL, 
+                              event->button, event->time);
+
+               return FALSE;
+       }
+       return FALSE;
+}
+
 static GtkWidget *apply_window_list_view_create        (void)
 {
        GtkTreeView *list_view;
@@ -657,7 +749,8 @@ static GtkWidget *apply_window_list_view_create     (void)
        model = GTK_TREE_MODEL(apply_window_create_data_store());
        list_view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(model));
        g_object_unref(model);  
-       
+       gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(model), TAG_NAME, GTK_SORT_ASCENDING);
+
        gtk_tree_view_set_rules_hint(list_view, prefs_common.use_stripes_everywhere);
        
        selector = gtk_tree_view_get_selection(list_view);
@@ -666,6 +759,8 @@ static GtkWidget *apply_window_list_view_create     (void)
        /* create the columns */
        apply_window_create_list_view_columns(GTK_WIDGET(list_view));
 
+       g_signal_connect(G_OBJECT(list_view), "button-press-event",
+                       G_CALLBACK(apply_list_btn_pressed), list_view);
        return GTK_WIDGET(list_view);
 
 }
@@ -675,6 +770,7 @@ static void apply_window_close(void)
        g_slist_free(applywindow.msglist);
        applywindow.msglist = NULL;
        gtk_widget_hide(applywindow.window);
+       main_window_reflect_tags_changes(mainwindow_get_mainwindow());
 }
 
 static void apply_window_close_cb(GtkWidget *widget,
index 66d1af0..50ec4c8 100644 (file)
@@ -1229,15 +1229,26 @@ static void mainwindow_tags_menu_item_apply_tags_activate_cb(GtkWidget *widget,
        tag_apply_open(summary_get_selection(mainwin->summaryview));    
 }
 
+static gint 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);
+       
+       return strcmp2(tag_a, tag_b);
+}
 static void mainwindow_tags_menu_create(MainWindow *mainwin, 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, tag_cmp_list);
+
        label_menuitem = gtk_item_factory_get_item(mainwin->menu_factory,
                                                   "/Message/Tags");
        g_signal_connect(G_OBJECT(label_menuitem), "activate",
index 06ad94f..fb0fedc 100644 (file)
@@ -5582,15 +5582,26 @@ 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);
+       
+       return strcmp2(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",
index eb97a00..96d8d18 100644 (file)
@@ -2012,18 +2012,21 @@ static void textview_show_tags(TextView *textview)
                "header_title", "header", "tags", NULL);
 
        for (cur = msginfo->tags; cur; cur = cur->next) {
+               const gchar *cur_tag = tags_get_tag(GPOINTER_TO_INT(cur->data));
+               if (!cur_tag)
+                       continue;
                uri = g_new0(ClickableText, 1);
                uri->uri = g_strdup("");
                uri->start = gtk_text_iter_get_offset(&iter);
                gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, 
-                       tags_get_tag(GPOINTER_TO_INT(cur->data)), -1,
+                       cur_tag, -1,
                        "link", "header", "tags", NULL);
                uri->end = gtk_text_iter_get_offset(&iter);
-               uri->filename = g_strdup_printf("sc://search_tags:%s", tags_get_tag(GPOINTER_TO_INT(cur->data)));
+               uri->filename = g_strdup_printf("sc://search_tags:%s", cur_tag);
                uri->data = NULL;
                textview->uri_list =
                        g_slist_prepend(textview->uri_list, uri);
-               if (cur->next)
+               if (cur->next && tags_get_tag(GPOINTER_TO_INT(cur->next->data)))
                        gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, ", ", 2,
                                "header", "tags", NULL);
                else