2004-12-30 [colin] 0.9.13cvs22.3
authorColin Leroy <colin@colino.net>
Thu, 30 Dec 2004 14:24:30 +0000 (14:24 +0000)
committerColin Leroy <colin@colino.net>
Thu, 30 Dec 2004 14:24:30 +0000 (14:24 +0000)
* src/account.c
Sync with HEAD
* src/prefs_actions.c
* src/prefs_customheader.c
* src/prefs_filtering.c
* src/prefs_msg_colors.c
* src/prefs_summary_column.c
* src/gtk/prefswindow.c
Use GtkTreeView instead of deprecated
widgets. Patches by Alfons.

ChangeLog-gtk2.claws
PATCHSETS
configure.ac
src/account.c
src/gtk/prefswindow.c
src/prefs_actions.c
src/prefs_customheader.c
src/prefs_filtering.c
src/prefs_msg_colors.c
src/prefs_summary_column.c

index 55dad1b3310f9d71a78601465d482644ebb53af5..18135008f8bff207a45f29c20179ca21b6e23a5e 100644 (file)
@@ -1,3 +1,16 @@
+2004-12-30 [colin]     0.9.13cvs22.3
+
+       * src/account.c
+               Sync with HEAD
+       * src/prefs_actions.c
+       * src/prefs_customheader.c
+       * src/prefs_filtering.c
+       * src/prefs_msg_colors.c
+       * src/prefs_summary_column.c
+       * src/gtk/prefswindow.c
+               Use GtkTreeView instead of deprecated 
+               widgets. Patches by Alfons.
+
 2004-12-30 [paul]      0.9.13cvs22.2
 
        * src/foldersel.c
index 6e1cbea4e04b0389d6ee9054a5b5ba0ee84010ce..c24e0d1ee672ac73f965e7b4f25cb498361e3412 100644 (file)
--- a/PATCHSETS
+++ b/PATCHSETS
 ( cvs diff -u -r 1.12.2.16 -r 1.12.2.17 src/action.c; ) > 0.9.13cvs21.2.patchset
 ( cvs diff -u -r 1.396.2.17 -r 1.396.2.18 ChangeLog; cvs diff -u -r 1.2504.2.40 -r 1.2504.2.41 ChangeLog.claws; cvs diff -u -r 1.391.2.17 -r 1.391.2.18 ChangeLog.jp; cvs diff -u -r 1.42.2.7 -r 1.42.2.8 NEWS; cvs diff -u -r 1.654.2.326 -r 1.654.2.327 configure.ac; cvs diff -u -r 1.61.2.15 -r 1.61.2.16 src/account.c; ) > 0.9.13cvs22.1.patchset
 ( cvs diff -u -r 1.26.2.6 -r 1.26.2.7 src/foldersel.c; ) > 0.9.13cvs22.2.patchset
+( cvs diff -u -r 1.61.2.16 -r 1.61.2.17 src/account.c; cvs diff -u -r 1.60.2.5 -r 1.60.2.6 src/prefs_actions.c; cvs diff -u -r 1.16.2.4 -r 1.16.2.5 src/prefs_customheader.c; cvs diff -u -r 1.59.2.10 -r 1.59.2.11 src/prefs_filtering.c; cvs diff -u -r 1.1.2.6 -r 1.1.2.7 src/prefs_msg_colors.c; cvs diff -u -r 1.10.2.2 -r 1.10.2.3 src/prefs_summary_column.c; cvs diff -u -r 1.12.2.11 -r 1.12.2.12 src/gtk/prefswindow.c; ) > 0.9.13cvs22.3.patchset
index 916a56988412907ec1a80303b9e1ac1a9cbd7b66..9b54b2468276d4957fb167573c4251db92925b6f 100644 (file)
@@ -13,7 +13,7 @@ INTERFACE_AGE=0
 BINARY_AGE=0
 EXTRA_VERSION=22
 EXTRA_RELEASE=
-EXTRA_GTK2_VERSION=.2
+EXTRA_GTK2_VERSION=.3
 
 if test \( $EXTRA_VERSION -eq 0 \) -o \( "x$EXTRA_RELEASE" != "x" \); then
     VERSION=${MAJOR_VERSION}.${MINOR_VERSION}.${MICRO_VERSION}${EXTRA_RELEASE}${EXTRA_GTK2_VERSION}
index 79812ab6a2181b8c7a01a9089eb9f585ec72c684..de12078ffd975553b478fa471293f949bd57fccf 100644 (file)
 #include "customheader.h"
 #include "remotefolder.h"
 
+enum {
+       ACCOUNT_IS_DEFAULT,             /* GDK_TYPE_PIXMAP! */
+       ACCOUNT_ENABLE_GET_ALL, 
+       ACCOUNT_NAME,
+       ACCOUNT_PROTOCOL,
+       ACCOUNT_SERVER,
+       ACCOUNT_DATA,
+       N_ACCOUNT_COLUMNS
+};
+
+
 typedef enum
 {
        COL_DEFAULT     = 0,
@@ -68,51 +79,85 @@ static GList *account_list = NULL;
 
 static struct EditAccount {
        GtkWidget *window;
-       GtkWidget *clist;
+       GtkWidget *list_view;
        GtkWidget *close_btn;
 } edit_account;
 
-static GdkPixmap *markxpm;
-static GdkBitmap *markxpmmask;
-static GdkPixmap *checkboxonxpm;
-static GdkPixmap *checkboxonxpmmask;
-static GdkPixmap *checkboxoffxpm;
-static GdkPixmap *checkboxoffxpmmask;
+static GdkPixbuf *mark_pixbuf;
 
 static void account_edit_create                (void);
 
-static void account_edit_prefs         (void);
-static void account_delete             (void);
-static void account_clone              (void);
+static void account_edit_prefs         (GtkWidget *widget, gpointer data);
+static void account_delete             (GtkWidget *widget, gpointer data);
+static void account_clone              (GtkWidget *widget, gpointer data);
 
-static void account_up                 (void);
-static void account_down               (void);
+static void account_up                 (GtkWidget *widget, gpointer data);
+static void account_down               (GtkWidget *widget, gpointer data);
 
-static void account_set_default                (void);
+static void account_set_default                (GtkWidget *widget, gpointer data);
 
-static void account_edit_close         (void);
+static void account_edit_close         (GtkWidget *widget, gpointer data);
 
 static gint account_delete_event       (GtkWidget      *widget,
                                         GdkEventAny    *event,
                                         gpointer        data);
-static void account_selected           (GtkCList       *clist,
-                                        gint            row,
-                                        gint            column,
-                                        GdkEvent       *event,
-                                        gpointer        data);
-static void account_row_moved          (GtkCList       *clist,
-                                        gint            source_row,
-                                        gint            dest_row);
 static gboolean account_key_pressed    (GtkWidget      *widget,
                                         GdkEventKey    *event,
                                         gpointer        data);
 
-static gint account_clist_set_row      (PrefsAccount   *ac_prefs,
-                                        gint            row);
-static void account_clist_set          (void);
+static void account_list_view_add      (PrefsAccount   *ac_prefs);
+static void account_list_view_set      (void);
 
 static void account_list_set           (void);
 
+typedef struct FindAccountInStore {
+       gint             account_id;
+       GtkTreePath     *path;
+       GtkTreeIter      iter;
+} FindAccountInStore;
+
+static GtkListStore* account_create_data_store (void);
+
+static void account_list_view_insert_account_item (GtkListStore        *list_store, 
+                                                  const gchar  *account_name,
+                                                  const gchar  *protocol, 
+                                                  const gchar  *server_name,
+                                                  gboolean      is_default, 
+                                                  gboolean      is_get_all,
+                                                  PrefsAccount *account_data);
+
+static GtkWidget *account_list_view_create     (void);
+static void account_create_list_view_images    (GtkWidget *list_view);
+static void account_create_list_view_columns   (GtkWidget *list_view);
+
+static gint account_list_view_get_selected_account_id          (GtkWidget *list_view);
+GtkTreePath *account_list_view_get_selected_account_path       (GtkWidget *list_view);
+PrefsAccount *account_list_view_get_selected_account           (GtkWidget *list_view);
+gboolean account_list_view_select_account                      (GtkWidget *list_view, 
+                                                                gint       account_id);
+
+static void account_list_view_set_default_by_id(GtkWidget *list_view,
+                                               gint account_id);
+
+static gboolean set_new_default_account                (GtkTreeModel *model,
+                                                GtkTreePath  *path,
+                                                GtkTreeIter  *iter,
+                                                gint         *account_id);
+
+static gboolean find_account_in_store          (GtkTreeModel *model,
+                                                GtkTreePath  *path,
+                                                GtkTreeIter  *iter,
+                                                FindAccountInStore *data);
+
+static void account_get_all_toggled            (GtkCellRendererToggle  *widget, 
+                                                gchar                  *path, 
+                                                GtkWidget              *list_view);
+                                                
+static void account_double_clicked             (GtkTreeView            *list_view,
+                                                GtkTreePath            *path,
+                                                GtkTreeViewColumn      *column,
+                                                gpointer                data);
+
 void account_read_config_all(void)
 {
        GSList *ac_label_list = NULL, *cur;
@@ -318,7 +363,7 @@ void account_edit_open(void)
        if (!edit_account.window)
                account_edit_create();
 
-       account_clist_set();
+       account_list_view_set();
 
        manage_window_set_transient(GTK_WINDOW(edit_account.window));
        gtk_widget_grab_focus(edit_account.close_btn);
@@ -340,7 +385,7 @@ void account_add(void)
        if (ac_prefs->is_default)
                account_set_as_default(ac_prefs);
 
-       account_clist_set();
+       account_list_view_set();
 
        if (ac_prefs->protocol == A_IMAP4 || ac_prefs->protocol == A_NNTP) {
                Folder *folder;
@@ -536,7 +581,7 @@ static void account_edit_create(void)
        GtkWidget *label;
        GtkWidget *hbox;
        GtkWidget *scrolledwin;
-       GtkWidget *clist;
+       GtkWidget *list_view;
        gchar *titles[N_EDIT_ACCOUNT_COLS];
        gint i;
 
@@ -594,34 +639,9 @@ static void account_edit_create(void)
                                        GTK_POLICY_AUTOMATIC,
                                        GTK_POLICY_AUTOMATIC);
 
-       titles[COL_DEFAULT]  = "D";
-       titles[COL_GETALL]   = "G";
-       titles[COL_NAME]     = _("Name");
-       titles[COL_PROTOCOL] = _("Protocol");
-       titles[COL_SERVER]   = _("Server");
-
-       clist = gtk_clist_new_with_titles (N_EDIT_ACCOUNT_COLS, titles);
-       gtk_widget_show (clist);
-       gtk_container_add (GTK_CONTAINER (scrolledwin), clist);
-       gtk_clist_set_column_width (GTK_CLIST(clist), COL_DEFAULT , 10);
-       gtk_clist_set_column_width (GTK_CLIST(clist), COL_GETALL  , 11);
-       gtk_clist_set_column_width (GTK_CLIST(clist), COL_NAME    , 100);
-       gtk_clist_set_column_width (GTK_CLIST(clist), COL_PROTOCOL, 100);
-       gtk_clist_set_column_width (GTK_CLIST(clist), COL_SERVER  , 100);
-       gtk_clist_set_column_justification (GTK_CLIST(clist), COL_DEFAULT,
-                                           GTK_JUSTIFY_CENTER);
-       gtk_clist_set_column_justification (GTK_CLIST(clist), COL_GETALL,
-                                           GTK_JUSTIFY_CENTER);
-       gtk_clist_set_selection_mode (GTK_CLIST(clist), GTK_SELECTION_BROWSE);
-
-       for (i = 0; i < N_EDIT_ACCOUNT_COLS; i++)
-               GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button,
-                                      GTK_CAN_FOCUS);
-
-       g_signal_connect (G_OBJECT (clist), "select_row",
-                         G_CALLBACK (account_selected), NULL);
-       g_signal_connect_after (G_OBJECT (clist), "row_move",
-                               G_CALLBACK (account_row_moved), NULL);
+       list_view = account_list_view_create();
+       gtk_widget_show(list_view);
+       gtk_container_add(GTK_CONTAINER(scrolledwin), list_view);
 
        vbox2 = gtk_vbox_new (FALSE, 0);
        gtk_widget_show (vbox2);
@@ -687,30 +707,22 @@ static void account_edit_create(void)
                          G_CALLBACK (account_edit_close),
                          NULL);
 
-       stock_pixmap_gdk(clist, STOCK_PIXMAP_MARK, &markxpm, &markxpmmask);
-       stock_pixmap_gdk(clist, STOCK_PIXMAP_CHECKBOX_ON,
-                        &checkboxonxpm, &checkboxonxpmmask);
-       stock_pixmap_gdk(clist, STOCK_PIXMAP_CHECKBOX_OFF,
-                        &checkboxoffxpm, &checkboxoffxpmmask);
 
        edit_account.window    = window;
-       edit_account.clist     = clist;
+       edit_account.list_view = list_view;
        edit_account.close_btn = close_btn;
 }
 
-static void account_edit_prefs(void)
+static void account_edit_prefs(GtkWidget *widget, gpointer data)
 {
-       GtkCList *clist = GTK_CLIST(edit_account.clist);
        PrefsAccount *ac_prefs;
-       gint row;
-
-       if (!clist->selection) return;
 
-       row = GPOINTER_TO_INT(clist->selection->data);
-       ac_prefs = gtk_clist_get_row_data(clist, row);
-       account_open(ac_prefs);
+       ac_prefs = account_list_view_get_selected_account(edit_account.list_view);
        
-       account_clist_set();
+       if (ac_prefs) {
+               account_open(ac_prefs);
+               account_list_view_set();
+       }               
 }
 
 static gboolean account_delete_references_func(GNode *node, gpointer data)
@@ -739,18 +751,15 @@ static gboolean account_delete_references_func(GNode *node, gpointer data)
 #define ACP_FDUP(fld) ac_clon->fld = ((ac_prefs->fld) != NULL)?\
                                     g_strdup(ac_prefs->fld): NULL
 #define ACP_FASSIGN(fld) ac_clon->fld = ac_prefs->fld
-static void account_clone(void)
+static void account_clone(GtkWidget *widget, gpointer data)
 {
-       GtkCList *clist = GTK_CLIST(edit_account.clist);
-       gint row;
        PrefsAccount *ac_prefs, *ac_clon;
        GSList *hdrs = NULL;
        CustomHeader *cch = NULL, *ch = NULL;
-
-       if (!clist->selection) return;
-
-       row = GPOINTER_TO_INT(clist->selection->data);
-       ac_prefs = gtk_clist_get_row_data(clist, row);
+       
+       ac_prefs = account_list_view_get_selected_account(edit_account.list_view);
+       if (ac_prefs == NULL)
+               return;
 
        if (ac_prefs->protocol == A_IMAP4 || ac_prefs->protocol == A_NNTP) {
                alertpanel_error(_("Accounts with remote folders cannot be cloned"));
@@ -881,28 +890,27 @@ static void account_clone(void)
        ACP_FASSIGN(folder);
 
        account_list = g_list_append(account_list, ac_clon);
-       account_clist_set();
+       account_list_view_set();
 }
 #undef ACP_FDUP
 #undef ACP_FASSIGN
 
-static void account_delete(void)
+static void account_delete(GtkWidget *widget, gpointer data)
 {
-       GtkCList *clist = GTK_CLIST(edit_account.clist);
        PrefsAccount *ac_prefs;
-       gint row;
+       gint account_id;
        GList *list;
        Folder *folder;
-       
-       if (!clist->selection) return;
+       ac_prefs = account_list_view_get_selected_account(edit_account.list_view);
+       if (ac_prefs == NULL)
+               return;
 
        if (alertpanel(_("Delete account"),
                       _("Do you really want to delete this account?"),
                       _("Yes"), _("+No"), NULL) != G_ALERTDEFAULT)
                return;
 
-       row = GPOINTER_TO_INT(clist->selection->data);
-       ac_prefs = gtk_clist_get_row_data(clist, row);
        if (ac_prefs->folder) {
                FolderItem *item;
 
@@ -913,7 +921,7 @@ static void account_delete(void)
                folderview_set_all();
        }
        account_destroy(ac_prefs);
-       account_clist_set();
+       account_list_view_set();
 
        debug_print("Removing deleted account references for all the folders...\n");
        list = folder_get_list();
@@ -927,49 +935,105 @@ static void account_delete(void)
        }
 }
 
-static void account_up(void)
+static void account_up(GtkWidget *widget, gpointer data)
 {
-       GtkCList *clist = GTK_CLIST(edit_account.clist);
-       gint row;
+       GtkTreePath *sel = account_list_view_get_selected_account_path
+                               (edit_account.list_view),
+                   *up;
+       GtkTreeIter isel, iup;
+       GtkTreeModel *model = gtk_tree_view_get_model
+                               (GTK_TREE_VIEW(edit_account.list_view));
+       
+       if (!sel) 
+               return;
+
+       up = gtk_tree_path_copy(sel);
+       if (!up) {
+               gtk_tree_path_free(sel);
+               return;
+       }
 
-       if (!clist->selection) return;
+       if (!gtk_tree_path_prev(up)) {
+               gtk_tree_path_free(up);
+               gtk_tree_path_free(sel);
+               return;
+       }
 
-       row = GPOINTER_TO_INT(clist->selection->data);
-       if (row > 0)
-               gtk_clist_row_move(clist, row, row - 1);
+       if (!gtk_tree_model_get_iter(model, &isel, sel)
+       ||  !gtk_tree_model_get_iter(model, &iup,  up)) {
+               gtk_tree_path_free(up);
+               gtk_tree_path_free(sel);
+               return;
+       }
+
+       gtk_list_store_swap(GTK_LIST_STORE(model), &isel, &iup);
+
+       account_list_set();
+       
+       gtk_tree_path_free(up);
+       gtk_tree_path_free(sel);
 }
 
-static void account_down(void)
+static void account_down(GtkWidget *widget, gpointer data)
 {
-       GtkCList *clist = GTK_CLIST(edit_account.clist);
-       gint row;
+       GtkTreePath *sel = account_list_view_get_selected_account_path
+                               (edit_account.list_view),
+                   *dn;
+       GtkTreeIter isel, idn;
+       GtkTreeModel *model = gtk_tree_view_get_model
+                               (GTK_TREE_VIEW(edit_account.list_view));
+       
+       if (!sel) 
+               return;
+
+       dn = gtk_tree_path_copy(sel);
+       if (!dn) {
+               gtk_tree_path_free(sel);
+               return;
+       }
 
-       if (!clist->selection) return;
+       /* XXX no check possible??? however, if down but at bottom, then 
+        * nothing seems to happen much anyway, so the following seems to 
+        * be okay */
+       gtk_tree_path_next(dn);
 
-       row = GPOINTER_TO_INT(clist->selection->data);
-       if (row < clist->rows - 1)
-               gtk_clist_row_move(clist, row, row + 1);
+       if (!gtk_tree_model_get_iter(model, &isel, sel)
+       ||  !gtk_tree_model_get_iter(model, &idn,  dn)) {
+               gtk_tree_path_free(dn);
+               gtk_tree_path_free(sel);
+               return;
+       }
+
+       gtk_list_store_swap(GTK_LIST_STORE(model), &isel, &idn);
+
+       account_list_set();
+       
+       gtk_tree_path_free(dn);
+       gtk_tree_path_free(sel);
 }
 
-static void account_set_default(void)
+static void account_set_default(GtkWidget *widget, gpointer data)
 {
-       GtkCList *clist = GTK_CLIST(edit_account.clist);
-       gint row;
        PrefsAccount *ac_prefs;
 
-       if (!clist->selection) return;
+       if (NULL == (ac_prefs = account_list_view_get_selected_account
+                                       (edit_account.list_view))) 
+               return; 
 
-       row = GPOINTER_TO_INT(clist->selection->data);
-       ac_prefs = gtk_clist_get_row_data(clist, row);
+       /* we need to change the store variables by resetting everything
+        * and setting the new default one */
+       account_list_view_set_default_by_id(edit_account.list_view,
+                                           ac_prefs->account_id);               
+       
        account_set_as_default(ac_prefs);
-       account_clist_set();
-
+       account_list_view_set();
+       
        cur_account = ac_prefs;
        account_set_menu();
        main_window_reflect_prefs_all();
 }
 
-static void account_edit_close(void)
+static void account_edit_close(GtkWidget *widget, gpointer data)
 {
        account_list_set();
        account_write_config_all();
@@ -991,158 +1055,120 @@ static void account_edit_close(void)
 static gint account_delete_event(GtkWidget *widget, GdkEventAny *event,
                                 gpointer data)
 {
-       account_edit_close();
+       account_edit_close(NULL, NULL);
        return TRUE;
 }
 
-static void account_selected(GtkCList *clist, gint row, gint column,
-                            GdkEvent *event, gpointer data)
-{
-       if (event && event->type == GDK_2BUTTON_PRESS) {
-               account_edit_prefs();
-               return;
-       }
-
-       if (column == COL_GETALL) {
-               PrefsAccount *ac;
-
-               ac = gtk_clist_get_row_data(clist, row);
-               if (ac->protocol == A_POP3 || ac->protocol == A_IMAP4 ||
-                   ac->protocol == A_NNTP || ac->protocol == A_LOCAL) {
-                       ac->recv_at_getall ^= TRUE;
-                       account_clist_set_row(ac, row);
-               }
-       }
-}
-
-static void account_row_moved(GtkCList *clist, gint source_row, gint dest_row)
-{
-       account_list_set();
-       if (gtk_clist_row_is_visible(clist, dest_row) != GTK_VISIBILITY_FULL)
-               gtk_clist_moveto(clist, dest_row, -1, 0.5, 0.0);
-}
-
 static gboolean account_key_pressed(GtkWidget *widget, GdkEventKey *event,
                                    gpointer data)
 {
        if (event && event->keyval == GDK_Escape)
-               account_edit_close();
+               account_edit_close(NULL, NULL);
        return FALSE;
 }
 
-/* set one CList row or add new row */
-static gint account_clist_set_row(PrefsAccount *ac_prefs, gint row)
+static void account_list_view_add(PrefsAccount *ac_prefs)
 {
-       GtkCList *clist = GTK_CLIST(edit_account.clist);
-       gchar *text[N_EDIT_ACCOUNT_COLS];
+       GtkTreeView *list_view = GTK_TREE_VIEW(edit_account.list_view);
+       GtkListStore *list_store = GTK_LIST_STORE(gtk_tree_view_get_model(list_view));
+       gchar *name, *protocol, *server;
        gboolean has_getallbox;
        gboolean getall;
 
-       text[COL_DEFAULT] = "";
-       text[COL_GETALL]  = "";
-       text[COL_NAME]    = ac_prefs->account_name;
+       name = ac_prefs->account_name;
 #if USE_OPENSSL
-       text[COL_PROTOCOL] = ac_prefs->protocol == A_POP3 ?
-                            (ac_prefs->ssl_pop == SSL_TUNNEL ?
-                             "POP3 (SSL)" :
-                             ac_prefs->ssl_pop == SSL_STARTTLS ?
-                             "POP3 (TLS)" : "POP3") :
-                            ac_prefs->protocol == A_IMAP4 ?
-                            (ac_prefs->ssl_imap == SSL_TUNNEL ?
-                             "IMAP4 (SSL)" :
-                             ac_prefs->ssl_imap == SSL_STARTTLS ?
-                             "IMAP4 (TLS)" : "IMAP4") :
-                            ac_prefs->protocol == A_NNTP ?
-                            (ac_prefs->ssl_nntp == SSL_TUNNEL ?
-                             "NNTP (SSL)" : "NNTP") :
-                            "";
+       protocol = ac_prefs->protocol == A_POP3 ?
+                 (ac_prefs->ssl_pop == SSL_TUNNEL ?
+                  "POP3 (SSL)" :
+                  ac_prefs->ssl_pop == SSL_STARTTLS ?
+                  "POP3 (TLS)" : "POP3") :
+                  ac_prefs->protocol == A_IMAP4 ?
+                 (ac_prefs->ssl_imap == SSL_TUNNEL ?
+                  "IMAP4 (SSL)" :
+                  ac_prefs->ssl_imap == SSL_STARTTLS ?
+                  "IMAP4 (TLS)" : "IMAP4") :
+                  ac_prefs->protocol == A_NNTP ?
+                 (ac_prefs->ssl_nntp == SSL_TUNNEL ?
+                  "NNTP (SSL)" : "NNTP") :
+                  "";
 #else
-       text[COL_PROTOCOL] = ac_prefs->protocol == A_POP3  ? "POP3" :
-                            ac_prefs->protocol == A_IMAP4 ? "IMAP4" :
-                            ac_prefs->protocol == A_LOCAL ? "Local" :
-                            ac_prefs->protocol == A_NNTP  ? "NNTP" : "";
+       protocol = ac_prefs->protocol == A_POP3  ? "POP3" :
+                  ac_prefs->protocol == A_IMAP4 ? "IMAP4" :
+                  ac_prefs->protocol == A_LOCAL ? "Local" :
+                  ac_prefs->protocol == A_NNTP  ? "NNTP" : "";
 #endif
-       text[COL_SERVER] = ac_prefs->protocol == A_NNTP
+       server= ac_prefs->protocol == A_NNTP
                ? ac_prefs->nntp_server : ac_prefs->recv_server;
 
-       if (row < 0)
-               row = gtk_clist_append(clist, text);
-       else {
-               gtk_clist_set_text(clist, row, COL_DEFAULT, text[COL_DEFAULT]);
-               gtk_clist_set_text(clist, row, COL_GETALL, text[COL_GETALL]);
-               gtk_clist_set_text(clist, row, COL_NAME, text[COL_NAME]);
-               gtk_clist_set_text(clist, row, COL_PROTOCOL, text[COL_PROTOCOL]);
-               gtk_clist_set_text(clist, row, COL_SERVER, text[COL_SERVER]);
-       }
-
        has_getallbox = (ac_prefs->protocol == A_POP3  ||
                         ac_prefs->protocol == A_IMAP4 ||
-                        ac_prefs->protocol == A_NNTP ||
+                        ac_prefs->protocol == A_NNTP  ||
                         ac_prefs->protocol == A_LOCAL);
        getall = has_getallbox && ac_prefs->recv_at_getall;
 
-       if (ac_prefs->is_default)
-               gtk_clist_set_pixmap(clist, row, COL_DEFAULT,
-                                    markxpm, markxpmmask);
-       if (getall)
-               gtk_clist_set_pixmap(clist, row, COL_GETALL,
-                                    checkboxonxpm, checkboxonxpmmask);
-       else if (has_getallbox)
-               gtk_clist_set_pixmap(clist, row, COL_GETALL,
-                                    checkboxoffxpm, checkboxoffxpmmask);
-
-       gtk_clist_set_row_data(clist, row, ac_prefs);
-
-       return row;
+       return account_list_view_insert_account_item(list_store,
+                                                    name, protocol, server,
+                                                    ac_prefs->is_default,
+                                                    getall, ac_prefs);
 }
 
-/* set CList from account list */
-static void account_clist_set(void)
+static void account_list_view_set(void)
 {
-       GtkCList *clist = GTK_CLIST(edit_account.clist);
        GList *cur;
-       gint row = -1, prev_row = -1;
-
-       if (clist->selection)
-               prev_row = GPOINTER_TO_INT(clist->selection->data);
+       gint prev_sel_account;
+       GtkListStore *store;
+       
+       store = GTK_LIST_STORE(gtk_tree_view_get_model
+               (GTK_TREE_VIEW(edit_account.list_view)));
 
-       gtk_clist_freeze(clist);
-       gtk_clist_clear(clist);
+       prev_sel_account = account_list_view_get_selected_account_id
+               (edit_account.list_view); 
 
+       gtk_list_store_clear(store);
+       
        for (cur = account_list; cur != NULL; cur = cur->next) {
-               row = account_clist_set_row((PrefsAccount *)cur->data, -1);
-               if ((PrefsAccount *)cur->data == cur_account) {
-                       gtk_clist_select_row(clist, row, -1);
-                       gtkut_clist_set_focus_row(clist, row);
-               }
+               account_list_view_add((PrefsAccount *)cur->data);
+               if ((PrefsAccount *)cur->data == cur_account)
+                       account_list_view_select_account
+                               (edit_account.list_view, 
+                                cur_account->account_id);
        }
-
-       if (prev_row >= 0) {
-               row = prev_row;
-               gtk_clist_select_row(clist, row, -1);
-               gtkut_clist_set_focus_row(clist, row);
-       }
-
-       if (row >= 0 &&
-           gtk_clist_row_is_visible(clist, row) != GTK_VISIBILITY_FULL)
-               gtk_clist_moveto(clist, row, -1, 0.5, 0);
-
-       gtk_clist_thaw(clist);
+       
+       if (prev_sel_account >= 0)
+               account_list_view_select_account(edit_account.list_view, 
+                                                prev_sel_account); 
 }
 
 /* set account list from CList */
 static void account_list_set(void)
 {
-       GtkCList *clist = GTK_CLIST(edit_account.clist);
-       gint row;
+       /* want to make sure we iterate *IN ORDER*, so therefore using
+        * gtk_tree_model_XXXX_nth_child() */
+       gint row, n_rows;
        PrefsAccount *ac_prefs;
-
+       GtkTreeModel *model = gtk_tree_view_get_model
+                               (GTK_TREE_VIEW(edit_account.list_view));
+       
        while (account_list)
                account_list = g_list_remove(account_list, account_list->data);
 
-       for (row = 0; (ac_prefs = gtk_clist_get_row_data(clist, row)) != NULL;
-            row++)
-               account_list = g_list_append(account_list, ac_prefs);
+       n_rows = gtk_tree_model_iter_n_children(model, NULL);
+
+       for (row = 0; row < n_rows; row++) {
+               GtkTreeIter iter;
+
+               if (!gtk_tree_model_iter_nth_child(model, &iter, NULL, row)) {
+                       g_warning("%s(%d) - no iter found???\n", __FILE__, __LINE__);                                         
+                       continue;
+               }
+       
+               ac_prefs = NULL;
+               gtk_tree_model_get(model, &iter,
+                                  ACCOUNT_DATA, &ac_prefs,
+                                  -1);
+               if (ac_prefs)
+                       account_list = g_list_append(account_list, ac_prefs);
+       }
 }
 
 /*!
@@ -1200,3 +1226,339 @@ PrefsAccount *account_get_reply_account(MsgInfo *msginfo, gboolean reply_autosel
        
        return account;
 }
+
+/*!
+ *\brief       Create data store
+ */
+static GtkListStore* account_create_data_store(void)
+{
+       return gtk_list_store_new(N_ACCOUNT_COLUMNS,
+                                GDK_TYPE_PIXBUF,       /* ACCOUNT_IS_DEFAULT */
+                                G_TYPE_BOOLEAN,        /* ACCOUNT_ENABLE_GET_ALL */
+                                G_TYPE_STRING,         /* ACCOUNT_NAME */
+                                G_TYPE_STRING,         /* ACCOUNT_PROTOCOL */
+                                G_TYPE_STRING,         /* ACCOUNT_SERVER */
+                                G_TYPE_POINTER,        /* ACCOUNT_DATA */
+                                -1);
+}
+
+/*!
+ *\brief       Insert an account item in the list. 
+ *
+ *\return      GtkTreeRowReference * A tree row reference, which is guaranteed to 
+ *             stable whatever operations are performed on the list.
+ */
+static void account_list_view_insert_account_item(GtkListStore *list_store, 
+                                                 const gchar *account_name,
+                                                 const gchar *protocol, 
+                                                 const gchar *server_name,
+                                                 gboolean is_default, 
+                                                 gboolean is_get_all,
+                                                 PrefsAccount *account_data)
+{
+       GtkTreeIter iter;
+       
+       gtk_list_store_append(list_store, &iter);
+       gtk_list_store_set(list_store, &iter, 
+                          ACCOUNT_IS_DEFAULT,     is_default ? mark_pixbuf : NULL,
+                          ACCOUNT_ENABLE_GET_ALL, is_get_all,
+                          ACCOUNT_NAME,           account_name,
+                          ACCOUNT_PROTOCOL,       protocol,
+                          ACCOUNT_SERVER,         server_name,
+                          ACCOUNT_DATA,           account_data,
+                          -1);
+}
+
+/*!
+ *\brief       Create and set up account list view, including tasks like
+ *             creating the data store (\ref account_create_data_store()),
+ *             creating images for the list view (\ref account_create_list_view_images()),
+ *             and setting up the account list's individual columns (\ref 
+ *             account_create_list_view_columns()).
+ *
+ *\return      GtkWidget * The created list view widget.
+ */
+static GtkWidget *account_list_view_create(void)
+{
+       GtkTreeView *list_view;
+       GtkTreeSelection *selector;
+
+       list_view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL
+               (account_create_data_store())));
+       
+       gtk_tree_view_set_rules_hint(list_view, TRUE);
+       
+       selector = gtk_tree_view_get_selection(list_view);
+       gtk_tree_selection_set_mode(selector, GTK_SELECTION_BROWSE);
+
+       /* create the pixbufs */
+       account_create_list_view_images(GTK_WIDGET(list_view));
+
+       /* create the columns */
+       account_create_list_view_columns(GTK_WIDGET(list_view));
+
+       /* set a double click listener */
+       g_signal_connect(G_OBJECT(list_view), "row_activated",
+                        G_CALLBACK(account_double_clicked),
+                        list_view);
+
+       return GTK_WIDGET(list_view);
+}
+
+static void account_create_list_view_images(GtkWidget *list_view)
+{
+       GdkPixmap *markxpm;
+       GdkBitmap *markxpmmask;
+       const guchar *pixdata;
+       GdkPixbuf *pbuf;
+       
+       stock_pixmap_gdk(list_view, STOCK_PIXMAP_MARK, &markxpm, &markxpmmask);
+
+       pbuf = gdk_pixbuf_get_from_drawable(NULL, markxpm, NULL,
+                                           0, 0, 0, 0, -1, -1);
+       pixdata = gdk_pixbuf_get_pixels(pbuf);
+       mark_pixbuf = gdk_pixbuf_add_alpha(pbuf, TRUE, 
+                                          pixdata[0],
+                                          pixdata[1],
+                                          pixdata[2]);
+       g_object_unref(pbuf);
+}
+
+static void account_create_list_view_columns(GtkWidget *list_view)
+{
+       GtkTreeViewColumn *column;
+       GtkCellRenderer *renderer;
+
+       renderer = gtk_cell_renderer_pixbuf_new();
+       column = gtk_tree_view_column_new_with_attributes
+               ("D", renderer,
+                "pixbuf", ACCOUNT_IS_DEFAULT,
+                NULL);
+       gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);           
+
+       renderer = gtk_cell_renderer_toggle_new();
+       g_object_set(renderer, 
+                    "radio", FALSE, 
+                    "activatable", TRUE,
+                     NULL);
+       column = gtk_tree_view_column_new_with_attributes
+               ("G", renderer,
+                "active", ACCOUNT_ENABLE_GET_ALL,
+                NULL);
+       gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);          
+       g_signal_connect(G_OBJECT(renderer), "toggled",                      
+                        G_CALLBACK(account_get_all_toggled),
+                        list_view);
+       
+       renderer = gtk_cell_renderer_text_new();
+       column = gtk_tree_view_column_new_with_attributes
+               (_("Name"), renderer,
+                "text", ACCOUNT_NAME,
+                NULL);
+       gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);          
+       
+       renderer = gtk_cell_renderer_text_new();
+       column = gtk_tree_view_column_new_with_attributes
+               (_("Protocol"), renderer,
+                "text", ACCOUNT_PROTOCOL,
+                NULL);
+       gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);           
+       
+       renderer = gtk_cell_renderer_text_new();
+       column = gtk_tree_view_column_new_with_attributes
+               (_("Server"), renderer,
+                "text", ACCOUNT_SERVER,
+                NULL);
+       gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);           
+}
+
+/*!
+ *\brief       Get currently selected account (by its unique ID)
+ */
+static gint account_list_view_get_selected_account_id(GtkWidget *list_view)
+{
+       GtkTreeSelection *selector;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       PrefsAccount *res = NULL;
+
+       selector = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view));
+       
+       if (!gtk_tree_selection_get_selected(selector, &model, &iter))
+               return -1;
+
+       gtk_tree_model_get(model, &iter, ACCOUNT_DATA, &res, -1);
+
+       return res->account_id;                    
+}
+
+/*!
+ *\brief       Get the tree path of the currently selected account
+ */
+GtkTreePath *account_list_view_get_selected_account_path(GtkWidget *list_view)
+{
+       GtkTreeSelection *selector;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       GtkTreePath *res;
+
+       selector = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view));
+       
+       if (!gtk_tree_selection_get_selected(selector, &model, &iter))
+               return NULL;
+
+       return gtk_tree_model_get_path(gtk_tree_view_get_model
+               (GTK_TREE_VIEW(list_view)), &iter);
+}
+
+/*!
+ *\brief       Get the account data of the currently selected account
+ */
+PrefsAccount *account_list_view_get_selected_account(GtkWidget *list_view)
+{
+       GtkTreeSelection *selector;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       PrefsAccount *res = NULL;
+
+       selector = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view));
+       
+       if (!gtk_tree_selection_get_selected(selector, &model, &iter))
+               return NULL;
+
+       gtk_tree_model_get(model, &iter, ACCOUNT_DATA, &res, -1);
+
+       return res;                        
+}
+
+/*!
+ *\brief       Select a row by the account it represents
+ *
+ *\return      gboolean TRUE if found and selected, FALSE if not.
+ */
+gboolean account_list_view_select_account(GtkWidget *list_view, gint account_id)
+{
+       FindAccountInStore fis;
+       GtkTreeModel *model;
+       
+       fis.account_id = account_id;
+       fis.path = NULL;
+
+       model = gtk_tree_view_get_model(GTK_TREE_VIEW(list_view));
+
+       gtk_tree_model_foreach(model, (GtkTreeModelForeachFunc) find_account_in_store,
+                              &fis);
+                              
+       if (fis.path) {
+               GtkTreeSelection *selection;
+               GtkTreePath* path;
+
+               selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view));
+               gtk_tree_selection_select_iter(selection, &fis.iter);
+               path = gtk_tree_model_get_path(model, &fis.iter);
+               /* XXX returned path may not be valid??? create new one to be sure */ 
+               gtk_tree_view_set_cursor(GTK_TREE_VIEW(list_view), path, NULL, FALSE);
+               gtk_tree_path_free(path);
+       }
+
+       return fis.path != NULL;
+}
+
+/*!
+ *\brief       Set a new default account by its ID. (There is only one
+ *             default account.)
+ */
+static void account_list_view_set_default_by_id(GtkWidget *list_view,
+                                               gint account_id)
+{
+       GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(list_view));
+       
+       gtk_tree_model_foreach
+               (model, (GtkTreeModelForeachFunc) set_new_default_account,
+                &account_id);
+}
+
+static gboolean set_new_default_account(GtkTreeModel *model,
+                                       GtkTreePath  *path,
+                                       GtkTreeIter  *iter,
+                                       gint         *account_id)
+{
+       PrefsAccount *account = NULL;
+       GdkPixbuf *pixbuf;
+       
+       gtk_tree_model_get(model, iter, 
+                          ACCOUNT_DATA, &account, 
+                          -1);
+
+       if (*account_id == account->account_id)
+               pixbuf = NULL;
+       else
+               pixbuf = mark_pixbuf;
+       
+       gtk_list_store_set(GTK_LIST_STORE(model), iter, 
+                          ACCOUNT_IS_DEFAULT, pixbuf,
+                          -1);
+
+       return FALSE;
+}
+                                       
+static gboolean find_account_in_store(GtkTreeModel *model,
+                                     GtkTreePath  *path,
+                                     GtkTreeIter  *iter,
+                                     FindAccountInStore *data)
+{
+       PrefsAccount *account = NULL;
+       gtk_tree_model_get(model, iter, ACCOUNT_DATA, &account, -1);
+
+       if (data->account_id == account->account_id) {
+               data->path = path; /* signal we found it */
+               data->iter = *iter;
+               return TRUE;
+       }
+
+       return FALSE; 
+}
+
+/*!
+ *\brief       Triggered when "get all" column is activated or de-activated
+ */
+static void account_get_all_toggled(GtkCellRendererToggle *widget, 
+                                   gchar *path, 
+                                   GtkWidget *list_view)
+{
+       GtkTreeIter iter;
+       GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(list_view));
+       PrefsAccount *ac = NULL;
+       gboolean get_all;
+       
+       if (!gtk_tree_model_get_iter_from_string(model, &iter, path))
+               return;
+
+       gtk_tree_model_get(model, &iter, 
+                          ACCOUNT_DATA, &ac,
+                          ACCOUNT_ENABLE_GET_ALL, &get_all,
+                          -1);
+
+       /* check if the account has a selectable get all checkbox anyway... */
+       if (!(ac->protocol == A_POP3  || 
+             ac->protocol == A_IMAP4 ||
+             ac->protocol == A_NNTP  ||
+             ac->protocol == A_LOCAL))
+               return;       
+
+       /* set value in store */
+       gtk_list_store_set(GTK_LIST_STORE(model), &iter,
+                          ACCOUNT_ENABLE_GET_ALL, !get_all,
+                          -1);
+
+       /* set value in account */
+       ac->recv_at_getall ^= TRUE;
+}
+
+static void account_double_clicked(GtkTreeView         *list_view,
+                                  GtkTreePath          *path,
+                                  GtkTreeViewColumn    *column,
+                                  gpointer              data)
+{
+       account_edit_prefs(NULL, NULL); 
+}
index 75b41c779d6c2217b5425ca5a072b421a0f0809b..c149064a78c390747a54528a034286ed4c164fbb 100644 (file)
 #include "prefswindow.h"
 #include "gtkutils.h"
 
+enum { 
+       PREFS_PAGE_TITLE,               /* page title */
+       PREFS_PAGE_DATA,                /* PrefsTreeNode data */        
+       PREFS_PAGE_DATA_AUTO_FREE,      /* auto free for PREFS_PAGE_DATA */
+       PREFS_PAGE_WEIGHT,              /* weight */
+       PREFS_PAGE_INDEX,               /* index in original page list */
+       N_PREFS_PAGE_COLUMNS
+};
+
 typedef struct _PrefsWindow PrefsWindow;
 typedef struct _PrefsTreeNode PrefsTreeNode;
 
@@ -39,7 +48,7 @@ struct _PrefsWindow
        GtkWidget *window;
        GtkWidget *table1;
        GtkWidget *scrolledwindow1;
-       GtkWidget *ctree;
+       GtkWidget *tree_view;
        GtkWidget *table2;
        GtkWidget *pagelabel;
        GtkWidget *labelframe;
@@ -60,49 +69,32 @@ struct _PrefsWindow
 struct _PrefsTreeNode
 {
        PrefsPage *page;
-       gfloat     treeweight;
+       gfloat     treeweight; /* GTK2: not used */
 };
 
-static gboolean ctree_select_row(GtkCTree *ctree, GList *node, gint column, gpointer user_data)
-{
-       PrefsTreeNode *prefsnode;
-       PrefsPage *page;
-       PrefsWindow *prefswindow = (PrefsWindow *) user_data;
-       gchar *labeltext;
-       gint pagenum, i;
+static GType G_TYPE_AUTO_POINTER;
 
-       prefsnode = gtk_ctree_node_get_row_data(GTK_CTREE(ctree), GTK_CTREE_NODE(node));
-       page = prefsnode->page;
+typedef struct AutoPointerRef {
+       gpointer        pointer;
+       glong           cnt;
+} AutoPointerRef;
 
-       debug_print("%f\n", prefsnode->treeweight);
+typedef struct AutoPointer {
+       AutoPointerRef *ref;
+} AutoPointer;
 
-       if (page == NULL) {
-               gtk_label_set_text(GTK_LABEL(prefswindow->pagelabel), "");
-               pagenum = gtk_notebook_page_num(GTK_NOTEBOOK(prefswindow->notebook),
-                                               prefswindow->empty_page);
-               gtk_notebook_set_page(GTK_NOTEBOOK(prefswindow->notebook), pagenum);
-               return FALSE;
-       }
+static gpointer g_auto_pointer_new                     (gpointer pointer);
+static gpointer g_auto_pointer_copy                    (gpointer p);
+static void g_auto_pointer_free                                (gpointer p);
 
-       if (!page->page_open) {
-               page->create_widget(page, GTK_WINDOW(prefswindow->window), prefswindow->data);
-               gtk_container_add(GTK_CONTAINER(prefswindow->notebook), page->widget);
-               page->page_open = TRUE;
-       }
-
-       i = 0;
-       while (page->path[i + 1] != 0)
-               i++;
-       labeltext = page->path[i];
-
-       gtk_label_set_text(GTK_LABEL(prefswindow->pagelabel), labeltext);
-
-       pagenum = gtk_notebook_page_num(GTK_NOTEBOOK(prefswindow->notebook),
-                                       page->widget);
-       gtk_notebook_set_page(GTK_NOTEBOOK(prefswindow->notebook), pagenum);
-
-       return FALSE;
-}
+static GtkTreeStore *prefswindow_create_data_store     (void);
+static GtkWidget *prefswindow_tree_view_create         (PrefsWindow* prefswindow);
+static void prefs_filtering_create_tree_view_columns   (GtkWidget *tree_view);
+static gboolean prefswindow_row_selected               (GtkTreeSelection *selector,
+                                                        GtkTreeModel *model, 
+                                                        GtkTreePath *path,
+                                                        gboolean currently_selected,
+                                                        gpointer data);
 
 static void save_all_pages(GSList *prefs_pages)
 {
@@ -143,6 +135,7 @@ static void close_prefs_window(PrefsWindow *prefswindow)
        debug_print("prefs window closed\n");
 
        close_all_pages(prefswindow->prefs_pages);
+
        gtk_widget_destroy(prefswindow->window);
        g_slist_free(prefswindow->prefs_pages);
        if(prefswindow->func != NULL)
@@ -173,39 +166,6 @@ static gboolean window_closed(GtkWidget *widget, GdkEvent *event, gpointer user_
        return FALSE;
 }
 
-struct name_search
-{
-       gchar *text;
-       GtkCTreeNode *node;
-};
-
-static gboolean find_child_by_name(GtkCTree *ctree, GtkCTreeNode *node, struct name_search *name_search)
-{
-       gchar *text = NULL;
-
-       text = GTK_CELL_TEXT(GTK_CTREE_ROW(node)->row.cell[0])->text;
-       if (text == NULL)
-               return FALSE;
-
-       if (strcmp(text, name_search->text) == 0)
-               name_search->node = node;
-
-       return FALSE;
-}
-
-gint compare_func(GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2)
-{
-       PrefsTreeNode *prefsnode1 = ((GtkCListRow *)ptr1)->data;
-       PrefsTreeNode *prefsnode2 = ((GtkCListRow *)ptr2)->data;
-
-       if (prefsnode1 == NULL || prefsnode2 == NULL)
-               return 0;
-
-       return prefsnode1->treeweight > prefsnode2->treeweight ? -1 : 
-              prefsnode1->treeweight < prefsnode2->treeweight ?  1 : 
-                                                                 0;
-}
-
 static gboolean prefswindow_key_pressed(GtkWidget *widget, GdkEventKey *event,
                                    PrefsWindow *data)
 {
@@ -233,14 +193,146 @@ static gboolean prefswindow_key_pressed(GtkWidget *widget, GdkEventKey *event,
        return FALSE;
 }
 
-void prefswindow_open_full(const gchar *title, GSList *prefs_pages, gpointer data, GtkDestroyNotify func)
+typedef struct FindNodeByName {
+       const gchar *name;
+       gboolean     found;
+       GtkTreeIter  node;
+} FindNodeByName;
+
+static gboolean find_node_by_name(GtkTreeModel *model, GtkTreePath *path,
+                                 GtkTreeIter *iter, FindNodeByName *data)
+{
+       gchar *name;
+       gboolean result = FALSE;
+
+       gtk_tree_model_get(model, iter, PREFS_PAGE_TITLE, &name, -1);
+       if (name) {
+               result = strcmp(name, data->name) == 0;
+               if (result) {
+                       data->found = TRUE;
+                       data->node  = *iter;
+               }                       
+               g_free(name);
+       }
+       
+       return result;
+}
+
+static gint prefswindow_tree_sort_by_weight(GtkTreeModel *model, 
+                                           GtkTreeIter  *a,
+                                           GtkTreeIter  *b,
+                                           gpointer      context)
+{
+       gfloat f1, f2;
+       gint i1, i2;
+
+       /* From observation sorting should keep in account the original
+        * order in the prefs_pages list. I.e. if equal weight, prefer 
+        * the index in the pages list */ 
+       gtk_tree_model_get(model, a, 
+                          PREFS_PAGE_INDEX,  &i1,
+                          PREFS_PAGE_WEIGHT, &f1, -1);
+       gtk_tree_model_get(model, b, 
+                          PREFS_PAGE_INDEX,  &i2,
+                          PREFS_PAGE_WEIGHT, &f2, -1);
+
+       return f1 < f2 ? -1 : (f1 > f2 ?  1 : 
+             (i1 < i2 ?  1 : (i1 > i2 ? -1 : 0)));
+}
+                                 
+static void prefswindow_build_tree(GtkWidget *tree_view, GSList *prefs_pages)
 {
-       static gchar *titles[1];
+       GtkTreeStore *store = GTK_TREE_STORE(gtk_tree_view_get_model
+                       (GTK_TREE_VIEW(tree_view)));
        GSList *cur;
+       gint index; /* index in pages list */
+       GtkTreeSelection *selection;
+       GtkTreeIter iter;
+       
+       for (cur = prefs_pages, index = 0; cur != NULL; cur = g_slist_next(cur), index++) {
+               PrefsPage *page = (PrefsPage *)cur->data;
+               FindNodeByName find_name;
+               GtkTreeIter node, child;
+               PrefsTreeNode *prefs_node;
+               int i;
+
+               /* each page tree component string */
+               for (i = 0; page->path[i] != NULL; i++) {
+                       find_name.found = FALSE;
+                       find_name.name  = page->path[i];
+                       
+                       /* find node to attach to 
+                        * FIXME: we search the entire tree, so this is suboptimal... */
+                       gtk_tree_model_foreach(GTK_TREE_MODEL(store), 
+                                              (GtkTreeModelForeachFunc) find_node_by_name,
+                                              &find_name);
+                       if (find_name.found) {
+                               node = find_name.node;
+                               gtk_tree_model_get(GTK_TREE_MODEL(store), &node,
+                                                  PREFS_PAGE_DATA, &prefs_node,
+                                                  -1);
+                       } else {
+                               gpointer autoptr; 
+                       
+                               /* create a new top level */
+                               gtk_tree_store_append(store, &child, i == 0 ? NULL : &node);
+                               prefs_node = g_new0(PrefsTreeNode, 1);
+                               autoptr = g_auto_pointer_new(prefs_node);
+                               gtk_tree_store_set(store, &child,
+                                                  PREFS_PAGE_TITLE, page->path[i],
+                                                  PREFS_PAGE_DATA,  prefs_node,
+                                                  PREFS_PAGE_DATA_AUTO_FREE, autoptr,
+                                                  PREFS_PAGE_INDEX, index,
+                                                  PREFS_PAGE_WEIGHT, 0.0f,
+                                                  -1);
+                               g_auto_pointer_free(autoptr);
+                               node = child;
+                       }
+               }
+
+               /* right now we have a node and its prefs_node */
+               prefs_node->page = page;
+
+               /* parents "inherit" the max weight of the children */
+               do {
+                       gfloat f;
+                       
+                       gtk_tree_model_get(GTK_TREE_MODEL(store), &node, 
+                                          PREFS_PAGE_WEIGHT, &f,
+                                          -1);
+                       if (page->weight > f) {
+                               f = page->weight;
+                               gtk_tree_store_set(store, &node,
+                                                  PREFS_PAGE_WEIGHT, f,
+                                                  -1);
+                       }       
+                       child = node;   
+               } while (gtk_tree_model_iter_parent(GTK_TREE_MODEL(store),      
+                                                   &node, &child));
+       }
+
+       gtk_tree_view_expand_all(GTK_TREE_VIEW(tree_view));
+
+       /* set sort func & sort */
+       gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(store),
+                                       PREFS_PAGE_WEIGHT,
+                                       prefswindow_tree_sort_by_weight,
+                                       NULL, NULL);
+       gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(store),
+                                            PREFS_PAGE_WEIGHT,
+                                            GTK_SORT_DESCENDING);
+
+       /* select first one */                                       
+       selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
+       if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
+               gtk_tree_selection_select_iter(selection, &iter);
+}
+
+void prefswindow_open_full(const gchar *title, GSList *prefs_pages, gpointer data, GtkDestroyNotify func)
+{
        gint optsize;
        PrefsWindow *prefswindow;
-
-       titles[0] = _("Page Index");
+       GtkTreeStore *store;
 
        prefswindow = g_new0(PrefsWindow, 1);
 
@@ -265,9 +357,10 @@ void prefswindow_open_full(const gchar *title, GSList *prefs_pages, gpointer dat
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(prefswindow->scrolledwindow1), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
        gtk_table_attach(GTK_TABLE(prefswindow->table1), prefswindow->scrolledwindow1, 0, 1, 0, 1, GTK_FILL, GTK_FILL | GTK_EXPAND, 2, 2);
 
-       prefswindow->ctree = gtk_ctree_new_with_titles(1, 0, titles);
-       gtk_widget_show(prefswindow->ctree);
-       gtk_container_add(GTK_CONTAINER(prefswindow->scrolledwindow1), prefswindow->ctree);
+       prefswindow->tree_view = prefswindow_tree_view_create(prefswindow);
+       gtk_widget_show(prefswindow->tree_view);
+       gtk_container_add(GTK_CONTAINER(prefswindow->scrolledwindow1), 
+                         prefswindow->tree_view);
 
        prefswindow->frame = gtk_frame_new(NULL);
        gtk_widget_show(prefswindow->frame);
@@ -300,57 +393,9 @@ void prefswindow_open_full(const gchar *title, GSList *prefs_pages, gpointer dat
        gtk_widget_show(prefswindow->empty_page);
        gtk_container_add(GTK_CONTAINER(prefswindow->notebook), prefswindow->empty_page);
 
-       /* actually we should create a tree here */
-       for (cur = prefs_pages; cur != NULL; cur = g_slist_next(cur)) {
-               PrefsPage *page = (PrefsPage *)cur->data;
-               GtkCTreeNode *node = NULL;
-               gchar *text[2], *part;
-               int i;
-               struct name_search name_search;
-               PrefsTreeNode *prefsnode;
-               for (i = 0; page->path[i] != NULL; i++) {
-                       part = page->path[i];
-                       name_search.text = part;
-                       name_search.node = NULL;
-
-                       gtk_ctree_post_recursive_to_depth(GTK_CTREE(prefswindow->ctree), node, node != NULL ? GTK_CTREE_ROW(node)->level + 1 : 1, GTK_CTREE_FUNC(find_child_by_name), &name_search);
-
-                       if (name_search.node) {
-                               node = name_search.node;
-                       } else {
-                               text[0] = part;
-                               node = gtk_ctree_insert_node(GTK_CTREE(prefswindow->ctree), node, NULL, text, 0, NULL, NULL, NULL, NULL, FALSE, TRUE);
-
-                               prefsnode = g_new0(PrefsTreeNode, 1);
-                               prefsnode->treeweight = 0.0;
-                               gtk_ctree_node_set_row_data_full(GTK_CTREE(prefswindow->ctree), node, prefsnode, g_free);
-                       }
-               }
-
-               prefsnode = (PrefsTreeNode *) GTK_CTREE_ROW(node)->row.data;
-               prefsnode->page = page;
+       prefswindow_build_tree(prefswindow->tree_view, prefs_pages);            
 
-               for (; node != NULL; node = GTK_CTREE_ROW(node)->parent) {
-                       PrefsTreeNode *curnode = (PrefsTreeNode *) GTK_CTREE_ROW(node)->row.data;
-
-                       if (page->weight > curnode->treeweight)
-                               curnode->treeweight = page->weight;
-               }
-       }
-       g_signal_connect(G_OBJECT(prefswindow->ctree), "tree-select-row", 
-                        G_CALLBACK(ctree_select_row), prefswindow);
-
-       gtk_clist_set_selection_mode(GTK_CLIST(prefswindow->ctree), GTK_SELECTION_BROWSE);
-       gtk_clist_column_titles_passive(GTK_CLIST(prefswindow->ctree));
-       optsize = gtk_clist_optimal_column_width(GTK_CLIST(prefswindow->ctree), 0);
-       gtk_clist_set_column_resizeable(GTK_CLIST(prefswindow->ctree), 0, TRUE);
-       gtk_clist_set_column_auto_resize(GTK_CLIST(prefswindow->ctree), 0, FALSE);
-       gtk_clist_set_column_width(GTK_CLIST(prefswindow->ctree), 0, optsize);
-       gtk_clist_set_column_min_width(GTK_CLIST(prefswindow->ctree), 0, optsize);
-       gtk_clist_set_column_max_width(GTK_CLIST(prefswindow->ctree), 0, optsize);
-       gtk_clist_set_compare_func(GTK_CLIST(prefswindow->ctree), compare_func);
-       gtk_ctree_sort_recursive(GTK_CTREE(prefswindow->ctree), NULL);
-       gtk_widget_grab_focus(GTK_WIDGET(prefswindow->ctree));
+       gtk_widget_grab_focus(prefswindow->tree_view);
 
        gtkut_button_set_create(&prefswindow->confirm_area,
                                &prefswindow->ok_btn,           _("OK"),
@@ -379,3 +424,154 @@ void prefswindow_open(const gchar *title, GSList *prefs_pages, gpointer data)
 {
        prefswindow_open_full(title, prefs_pages, data, NULL);
 }
+
+/* NOTE: auto pointer could be made more generic, but this works
+ * fine for now. */
+
+static gpointer g_auto_pointer_new(gpointer p)
+{      
+       AutoPointerRef *ref = g_new0(AutoPointerRef, 1);
+       AutoPointer    *ptr = g_new0(AutoPointer, 1);
+
+       ref->pointer = p;
+       ref->cnt = 1;
+
+       ptr->ref = ref;
+
+       return ptr;
+}
+
+static gpointer g_auto_pointer_copy(gpointer p)
+{
+       AutoPointer     *ptr = p;
+       AutoPointerRef  *ref = ptr->ref;
+       AutoPointer     *newp = g_new0(AutoPointer, 1);
+       newp->ref = ref;
+
+       ++(ref->cnt);
+       return newp;
+}
+
+static void g_auto_pointer_free(gpointer p)
+{
+       AutoPointer     *ptr = p;
+       AutoPointerRef  *ref = ptr->ref;
+
+       if (--(ref->cnt) == 0) {
+               g_free(ref->pointer);
+               g_free(ref);
+       }
+       g_free(ptr);            
+}
+
+static void prefswindow_static_init(void)
+{
+       if (!G_TYPE_AUTO_POINTER)
+               G_TYPE_AUTO_POINTER = 
+                       g_boxed_type_register_static("G_TYPE_AUTO_POINTER",
+                                                    g_auto_pointer_copy,
+                                                    g_auto_pointer_free);
+}
+
+static GtkTreeStore *prefswindow_create_data_store(void)
+{
+       /* should always be called before using auto pointer type */
+       prefswindow_static_init();
+       
+       return gtk_tree_store_new(N_PREFS_PAGE_COLUMNS,
+                                 G_TYPE_STRING,
+                                 G_TYPE_POINTER,
+                                 G_TYPE_AUTO_POINTER,
+                                 G_TYPE_FLOAT,
+                                 G_TYPE_INT,
+                                 -1);
+}
+
+static GtkWidget *prefswindow_tree_view_create(PrefsWindow *prefswindow)
+{
+       GtkTreeView *tree_view;
+       GtkTreeSelection *selector;
+       GtkTreeModel *model;
+
+       model = GTK_TREE_MODEL(prefswindow_create_data_store());
+       tree_view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(model));
+       g_object_unref(model);
+       gtk_tree_view_set_rules_hint(tree_view, TRUE);
+       
+       selector = gtk_tree_view_get_selection(tree_view);
+       gtk_tree_selection_set_mode(selector, GTK_SELECTION_BROWSE);
+       gtk_tree_selection_set_select_function(selector, prefswindow_row_selected,
+                                              prefswindow, NULL);
+
+       /* create the columns */
+       prefs_filtering_create_tree_view_columns(GTK_WIDGET(tree_view));
+
+       return GTK_WIDGET(tree_view);
+}
+
+static void prefs_filtering_create_tree_view_columns(GtkWidget *tree_view)
+{
+       GtkTreeViewColumn *column;
+       GtkCellRenderer *renderer;
+
+       renderer = gtk_cell_renderer_text_new();
+       column = gtk_tree_view_column_new_with_attributes
+               (_("Page Index"),
+                renderer,
+                "text", PREFS_PAGE_TITLE,
+                NULL);
+       gtk_tree_view_append_column(GTK_TREE_VIEW(tree_view), column);          
+}
+
+static gboolean prefswindow_row_selected(GtkTreeSelection *selector,
+                                        GtkTreeModel *model, 
+                                        GtkTreePath *path,
+                                        gboolean currently_selected,
+                                        gpointer data)
+{
+       PrefsTreeNode *prefsnode;
+       PrefsPage *page;
+       PrefsWindow *prefswindow = (PrefsWindow *) data;
+       gchar *labeltext;
+       gint pagenum, i;
+       GtkTreeIter iter;
+
+       if (currently_selected) 
+               return TRUE;
+
+       if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(model), &iter, path))
+               return TRUE;
+
+       gtk_tree_model_get(model, &iter, PREFS_PAGE_DATA, &prefsnode, -1);
+       page = prefsnode->page;
+
+       debug_print("%f\n", prefsnode->treeweight);
+
+       if (page == NULL) {
+               gtk_label_set_text(GTK_LABEL(prefswindow->pagelabel), "");
+               pagenum = gtk_notebook_page_num(GTK_NOTEBOOK(prefswindow->notebook),
+                                               prefswindow->empty_page);
+               gtk_notebook_set_page(GTK_NOTEBOOK(prefswindow->notebook), pagenum);
+               return TRUE;
+       }
+
+       if (!page->page_open) {
+               page->create_widget(page, GTK_WINDOW(prefswindow->window), prefswindow->data);
+               gtk_container_add(GTK_CONTAINER(prefswindow->notebook), page->widget);
+               page->page_open = TRUE;
+       }
+
+       i = 0;
+       while (page->path[i + 1] != 0)
+               i++;
+       labeltext = page->path[i];
+
+       gtk_label_set_text(GTK_LABEL(prefswindow->pagelabel), labeltext);
+
+       pagenum = gtk_notebook_page_num(GTK_NOTEBOOK(prefswindow->notebook),
+                                       page->widget);
+       gtk_notebook_set_page(GTK_NOTEBOOK(prefswindow->notebook), pagenum);
+
+       return TRUE;
+}
+
index 8e4a501be2b14690a6e881ade6c4a5633580ff70..bbfad0f4d3cc688731ca384d38060ea671f9e21b 100644 (file)
 #include "action.h"
 #include "description_window.h"
 
+enum {
+       PREFS_ACTIONS_STRING,   /*!< string pointer managed by list store, 
+                                *   and never touched or retrieved by 
+                                *   us */ 
+       PREFS_ACTIONS_DATA,     /*!< pointer to string that is not managed by 
+                                *   the list store, and which is retrieved
+                                *   and touched by us */
+       PREFS_ACTIONS_VALID,    /*!< contains a valid action, otherwise "(New)" */
+       N_PREFS_ACTIONS_COLUMNS
+};
+
 static struct Actions
 {
        GtkWidget *window;
@@ -53,13 +64,13 @@ static struct Actions
        GtkWidget *name_entry;
        GtkWidget *cmd_entry;
 
-       GtkWidget *actions_clist;
+       GtkWidget *actions_list_view;
 } actions;
 
 /* widget creating functions */
 static void prefs_actions_create       (MainWindow *mainwin);
 static void prefs_actions_set_dialog   (void);
-static gint prefs_actions_clist_set_row        (gint row);
+static gint prefs_actions_clist_set_row        (GtkTreeIter *row);
 
 /* callback functions */
 static void prefs_actions_help_cb      (GtkWidget      *w,
@@ -74,13 +85,6 @@ static void prefs_actions_up         (GtkWidget      *w,
                                         gpointer        data);
 static void prefs_actions_down         (GtkWidget      *w,
                                         gpointer        data);
-static void prefs_actions_select       (GtkCList       *clist,
-                                        gint            row,
-                                        gint            column,
-                                        GdkEvent       *event);
-static void prefs_actions_row_move     (GtkCList       *clist,
-                                        gint            source_row,
-                                        gint            dest_row);
 static gint prefs_actions_deleted      (GtkWidget      *widget,
                                         GdkEventAny    *event,
                                         gpointer       *data);
@@ -93,6 +97,20 @@ static void prefs_actions_ok         (GtkWidget      *w,
                                         gpointer        data);
 
 
+static GtkListStore* prefs_actions_create_data_store   (void);
+
+static void prefs_actions_list_view_insert_action      (GtkWidget *list_view,
+                                                        GtkTreeIter *row_iter,
+                                                        gchar *action,
+                                                        gboolean is_valid);
+static GtkWidget *prefs_actions_list_view_create       (void);
+static void prefs_actions_create_list_view_columns     (GtkWidget *list_view);
+static gboolean prefs_actions_selected                 (GtkTreeSelection *selector,
+                                                        GtkTreeModel *model, 
+                                                        GtkTreePath *path,
+                                                        gboolean currently_selected,
+                                                        gpointer data);
+
 void prefs_actions_open(MainWindow *mainwin)
 {
        inc_lock();
@@ -134,7 +152,7 @@ static void prefs_actions_create(MainWindow *mainwin)
 
        GtkWidget *cond_hbox;
        GtkWidget *cond_scrolledwin;
-       GtkWidget *cond_clist;
+       GtkWidget *cond_list_view;
 
        GtkWidget *help_button;
 
@@ -142,8 +160,6 @@ static void prefs_actions_create(MainWindow *mainwin)
        GtkWidget *up_btn;
        GtkWidget *down_btn;
 
-       gchar *title[1];
-
        debug_print("Creating actions configuration window...\n");
 
        window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
@@ -256,20 +272,9 @@ static void prefs_actions_create(MainWindow *mainwin)
                                       GTK_POLICY_AUTOMATIC,
                                       GTK_POLICY_AUTOMATIC);
 
-       title[0] = _("Current actions");
-       cond_clist = gtk_clist_new_with_titles(1, title);
-       gtk_widget_show(cond_clist);
-       gtk_container_add(GTK_CONTAINER (cond_scrolledwin), cond_clist);
-       gtk_clist_set_column_width(GTK_CLIST (cond_clist), 0, 80);
-       gtk_clist_set_selection_mode(GTK_CLIST (cond_clist),
-                                    GTK_SELECTION_BROWSE);
-       GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(cond_clist)->column[0].button,
-                              GTK_CAN_FOCUS);
-       g_signal_connect(G_OBJECT(cond_clist), "select_row",
-                        G_CALLBACK(prefs_actions_select), NULL);
-       g_signal_connect_after(G_OBJECT(cond_clist), "row_move",
-                              G_CALLBACK(prefs_actions_row_move),
-                              NULL);
+       cond_list_view = prefs_actions_list_view_create();                                     
+       gtk_widget_show(cond_list_view);
+       gtk_container_add(GTK_CONTAINER (cond_scrolledwin), cond_list_view);
 
        btn_vbox = gtk_vbox_new(FALSE, 8);
        gtk_widget_show(btn_vbox);
@@ -295,7 +300,7 @@ static void prefs_actions_create(MainWindow *mainwin)
        actions.name_entry = name_entry;
        actions.cmd_entry  = cmd_entry;
 
-       actions.actions_clist = cond_clist;
+       actions.actions_list_view = cond_list_view;
 }
 
 
@@ -394,57 +399,79 @@ void prefs_actions_write_config(void)
 
 static void prefs_actions_set_dialog(void)
 {
-       GtkCList *clist = GTK_CLIST(actions.actions_clist);
+       GtkListStore *store;
        GSList *cur;
-       gchar *action_str[1];
-       gint row;
+       GtkTreeSelection *selection;
+       GtkTreeIter iter;
 
-       gtk_clist_freeze(clist);
-       gtk_clist_clear(clist);
+       store = GTK_LIST_STORE(gtk_tree_view_get_model
+                               (GTK_TREE_VIEW(actions.actions_list_view)));
+       gtk_list_store_clear(store);
 
-       action_str[0] = _("(New)");
-       row = gtk_clist_append(clist, action_str);
-       gtk_clist_set_row_data(clist, row, NULL);
+       prefs_actions_list_view_insert_action(actions.actions_list_view,
+                                             NULL, _("New"), FALSE);
 
        for (cur = prefs_common.actions_list; cur != NULL; cur = cur->next) {
-               gchar *action[1];
-
-               action[0] = (gchar *)cur->data;
-               row = gtk_clist_append(clist, action);
-               gtk_clist_set_row_data(clist, row, action[0]);
+               gchar *action = (gchar *) cur->data;
+               
+               prefs_actions_list_view_insert_action(actions.actions_list_view,
+                                                     NULL, action, TRUE);
        }
 
-       gtk_clist_thaw(clist);
+       /* select first entry */
+       selection = gtk_tree_view_get_selection
+               (GTK_TREE_VIEW(actions.actions_list_view));
+       if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store),
+                                         &iter))
+               gtk_tree_selection_select_iter(selection, &iter);
 }
 
 static void prefs_actions_set_list(void)
 {
-       gint row = 1;
        gchar *action;
-
+       GtkTreeIter iter;
+       GtkListStore *store;
+       
        g_slist_free(prefs_common.actions_list);
        prefs_common.actions_list = NULL;
 
-       while ((action = (gchar *)gtk_clist_get_row_data
-               (GTK_CLIST(actions.actions_clist), row)) != NULL) {
-               prefs_common.actions_list =
-                       g_slist_append(prefs_common.actions_list, action);
-               row++;
+       store = GTK_LIST_STORE(gtk_tree_view_get_model
+                               (GTK_TREE_VIEW(actions.actions_list_view)));
+
+       if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) {
+               do {
+                       gchar *action;
+                       gboolean is_valid;
+
+                       gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
+                                          PREFS_ACTIONS_DATA, &action,
+                                          PREFS_ACTIONS_VALID, &is_valid,
+                                          -1);
+                       
+                       if (is_valid) 
+                               prefs_common.actions_list = 
+                                       g_slist_append(prefs_common.actions_list,
+                                                      action);
+
+               } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store),
+                                                 &iter));
        }
 }
 
 #define GET_ENTRY(entry) \
        entry_text = gtk_entry_get_text(GTK_ENTRY(entry))
 
-static gint prefs_actions_clist_set_row(gint row)
+static gint prefs_actions_clist_set_row(GtkTreeIter *row)
 {
-       GtkCList *clist = GTK_CLIST(actions.actions_clist);
        const gchar *entry_text;
        gint len;
        gchar action[PREFSBUFSIZE];
-       gchar *buf[1];
+       gchar *new_action;
+       GtkListStore *store;
 
-       g_return_val_if_fail(row != 0, -1);
+       store = GTK_LIST_STORE(gtk_tree_view_get_model
+                               (GTK_TREE_VIEW(actions.actions_list_view)));
+       
 
        GET_ENTRY(actions.name_entry);
        if (entry_text[0] == '\0') {
@@ -489,21 +516,10 @@ static gint prefs_actions_clist_set_row(gint row)
 
        strcat(action, entry_text);
 
-       buf[0] = action;
-       if (row < 0)
-               row = gtk_clist_append(clist, buf);
-       else {
-               gchar *old_action;
-               gtk_clist_set_text(clist, row, 0, action);
-               old_action = (gchar *) gtk_clist_get_row_data(clist, row);
-               if (old_action)
-                       g_free(old_action);
-       }
-
-       buf[0] = g_strdup(action);
-
-       gtk_clist_set_row_data(clist, row, buf[0]);
-
+       new_action = g_strdup(action);  
+       prefs_actions_list_view_insert_action(actions.actions_list_view,
+                                             row, new_action, TRUE);
+                                               
        prefs_actions_set_list();
 
        return 0;
@@ -513,110 +529,121 @@ static gint prefs_actions_clist_set_row(gint row)
 
 static void prefs_actions_register_cb(GtkWidget *w, gpointer data)
 {
-       prefs_actions_clist_set_row(-1);
+       prefs_actions_clist_set_row(NULL);
 }
 
 static void prefs_actions_substitute_cb(GtkWidget *w, gpointer data)
 {
-       GtkCList *clist = GTK_CLIST(actions.actions_clist);
-       gchar *action;
-       gint row;
-
-       if (!clist->selection) return;
-
-       row = GPOINTER_TO_INT(clist->selection->data);
-       if (row == 0) return;
+       GtkTreeIter sel;
 
-       action = gtk_clist_get_row_data(clist, row);
-       if (!action) return;
+       if (!gtk_tree_selection_get_selected(gtk_tree_view_get_selection
+                               (GTK_TREE_VIEW(actions.actions_list_view)),
+                               NULL, &sel))
+               return;
 
-       prefs_actions_clist_set_row(row);
+       prefs_actions_clist_set_row(&sel);
 }
 
 static void prefs_actions_delete_cb(GtkWidget *w, gpointer data)
 {
-       GtkCList *clist = GTK_CLIST(actions.actions_clist);
+       GtkTreeIter sel;
+       GtkTreeModel *model;
        gchar *action;
-       gint row;
 
-       if (!clist->selection) return;
-       row = GPOINTER_TO_INT(clist->selection->data);
-       if (row == 0) return;
+       if (!gtk_tree_selection_get_selected(gtk_tree_view_get_selection
+                               (GTK_TREE_VIEW(actions.actions_list_view)),
+                               &model, &sel))
+               return;                         
 
        if (alertpanel(_("Delete action"),
                       _("Do you really want to delete this action?"),
                       _("Yes"), _("No"), NULL) != G_ALERTDEFAULT)
                return;
 
-       action = gtk_clist_get_row_data(clist, row);
-       g_free(action);
-       gtk_clist_remove(clist, row);
+       /* 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,
+                          PREFS_ACTIONS_DATA, &action,
+                          -1);
+       gtk_list_store_remove(GTK_LIST_STORE(model), &sel);
+
        prefs_common.actions_list = g_slist_remove(prefs_common.actions_list,
                                                   action);
 }
 
 static void prefs_actions_up(GtkWidget *w, gpointer data)
 {
-       GtkCList *clist = GTK_CLIST(actions.actions_clist);
-       gint row;
-
-       if (!clist->selection) return;
+       GtkTreePath *prev, *sel, *try;
+       GtkTreeIter isel;
+       GtkListStore *store;
+       GtkTreeIter iprev;
+       
+       if (!gtk_tree_selection_get_selected
+               (gtk_tree_view_get_selection
+                       (GTK_TREE_VIEW(actions.actions_list_view)),
+                (GtkTreeModel **) &store,      
+                &isel))
+               return;
 
-       row = GPOINTER_TO_INT(clist->selection->data);
-       if (row > 1)
-               gtk_clist_row_move(clist, row, row - 1);
-}
+       sel = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &isel);
+       if (!sel)
+               return;
+       
+       /* no move if we're at row 0 or 1, looks phony, but other
+        * solutions are more convoluted... */
+       try = gtk_tree_path_copy(sel);
+       if (!gtk_tree_path_prev(try) || !gtk_tree_path_prev(try)) {
+               gtk_tree_path_free(try);
+               gtk_tree_path_free(sel);
+               return;
+       }
 
-static void prefs_actions_down(GtkWidget *w, gpointer data)
-{
-       GtkCList *clist = GTK_CLIST(actions.actions_clist);
-       gint row;
+       prev = gtk_tree_path_copy(sel);         
+       if (!gtk_tree_path_prev(prev)) {
+               gtk_tree_path_free(prev);
+               gtk_tree_path_free(sel);
+               return;
+       }
 
-       if (!clist->selection) return;
+       gtk_tree_model_get_iter(GTK_TREE_MODEL(store),
+                               &iprev, prev);
+       gtk_tree_path_free(sel);
+       gtk_tree_path_free(prev);
 
-       row = GPOINTER_TO_INT(clist->selection->data);
-       if (row > 0 && row < clist->rows - 1)
-               gtk_clist_row_move(clist, row, row + 1);
+       gtk_list_store_swap(store, &iprev, &isel);
+       prefs_actions_set_list();
 }
 
-#define ENTRY_SET_TEXT(entry, str) \
-       gtk_entry_set_text(GTK_ENTRY(entry), str ? str : "")
-
-static void prefs_actions_select(GtkCList *clist, gint row, gint column,
-                                GdkEvent *event)
+static void prefs_actions_down(GtkWidget *w, gpointer data)
 {
-       gchar *action;
-       gchar *cmd;
-       gchar buf[PREFSBUFSIZE];
-       action = gtk_clist_get_row_data(clist, row);
-
-       if (!action) {
-               ENTRY_SET_TEXT(actions.name_entry, "");
-               ENTRY_SET_TEXT(actions.cmd_entry, "");
+       GtkListStore *store;
+       GtkTreeIter next, sel;
+       GtkTreePath *try;
+       
+       if (!gtk_tree_selection_get_selected
+               (gtk_tree_view_get_selection
+                       (GTK_TREE_VIEW(actions.actions_list_view)),
+                (GtkTreeModel **) &store,
+                &sel))
                return;
-       }
 
-       strncpy(buf, action, PREFSBUFSIZE - 1);
-       buf[PREFSBUFSIZE - 1] = 0x00;
-       cmd = strstr(buf, ": ");
+       try = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &sel);
+       if (!try) 
+               return;
 
-       if (cmd && cmd[2])
-               ENTRY_SET_TEXT(actions.cmd_entry, &cmd[2]);
-       else
+       /* no move when we're at row 0 */
+       if (!gtk_tree_path_prev(try)) {
+               gtk_tree_path_free(try);
                return;
+       }
+       gtk_tree_path_free(try);
 
-       *cmd = 0x00;
-       ENTRY_SET_TEXT(actions.name_entry, buf);
-}
+       next = sel;
+       if (!gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &next)) 
+               return;
 
-static void prefs_actions_row_move(GtkCList *clist,
-                                  gint source_row, gint dest_row)
-{
+       gtk_list_store_swap(store, &next, &sel);
        prefs_actions_set_list();
-       if (gtk_clist_row_is_visible(clist, dest_row) != GTK_VISIBILITY_FULL) {
-               gtk_clist_moveto(clist, dest_row, -1,
-                                source_row < dest_row ? 1.0 : 0.0, 0.0);
-       }
 }
 
 static gint prefs_actions_deleted(GtkWidget *widget, GdkEventAny *event,
@@ -714,3 +741,133 @@ static void prefs_actions_help_cb(GtkWidget *w, gpointer data)
 {
        description_window_create(&actions_desc_win);
 }
+
+static GtkListStore* prefs_actions_create_data_store(void)
+{
+       return gtk_list_store_new(N_PREFS_ACTIONS_COLUMNS,
+                                 G_TYPE_STRING,        
+                                 G_TYPE_POINTER,
+                                 G_TYPE_BOOLEAN,
+                                 -1);
+}
+
+static void prefs_actions_list_view_insert_action(GtkWidget *list_view,
+                                                 GtkTreeIter *row_iter,
+                                                 gchar *action,
+                                                 gboolean is_valid) 
+{
+       GtkTreeIter iter;
+       GtkListStore *list_store = GTK_LIST_STORE(gtk_tree_view_get_model
+                                       (GTK_TREE_VIEW(list_view)));
+
+       if (row_iter == NULL) {
+               /* append new */
+               gtk_list_store_append(list_store, &iter);
+               gtk_list_store_set(list_store, &iter,
+                                  PREFS_ACTIONS_STRING, action,
+                                  PREFS_ACTIONS_DATA, action,
+                                  PREFS_ACTIONS_VALID,  is_valid,
+                                  -1);
+       } else {
+               /* change existing */
+               gchar *old_action;
+
+               gtk_tree_model_get(GTK_TREE_MODEL(list_store), row_iter,
+                                  PREFS_ACTIONS_DATA, &old_action,
+                                  -1);
+               
+               /* NOTE: we assume we never change the first entry,
+                * which is "(New)" */
+               g_assert(strcmp(_("New"), old_action) != 0);
+               
+               g_free(old_action);                             
+               gtk_list_store_set(list_store, row_iter,
+                                  PREFS_ACTIONS_STRING, action,
+                                  PREFS_ACTIONS_DATA, action,
+                                  -1);
+       }
+}
+
+static GtkWidget *prefs_actions_list_view_create(void)
+{
+       GtkTreeView *list_view;
+       GtkTreeSelection *selector;
+       GtkTreeModel *model;
+
+       model = GTK_TREE_MODEL(prefs_actions_create_data_store());
+       list_view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(model));
+       g_object_unref(model);  
+       
+       gtk_tree_view_set_rules_hint(list_view, TRUE);
+       
+       selector = gtk_tree_view_get_selection(list_view);
+       gtk_tree_selection_set_mode(selector, GTK_SELECTION_BROWSE);
+       gtk_tree_selection_set_select_function(selector, prefs_actions_selected,
+                                              NULL, NULL);
+
+       /* create the columns */
+       prefs_actions_create_list_view_columns(GTK_WIDGET(list_view));
+
+       return GTK_WIDGET(list_view);
+}
+
+static void prefs_actions_create_list_view_columns(GtkWidget *list_view)
+{
+       GtkTreeViewColumn *column;
+       GtkCellRenderer *renderer;
+
+       renderer = gtk_cell_renderer_text_new();
+       column = gtk_tree_view_column_new_with_attributes
+               (_("Current actions"),
+                renderer,
+                "text", PREFS_ACTIONS_STRING,
+                NULL);
+       gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);          
+}
+
+#define ENTRY_SET_TEXT(entry, str) \
+       gtk_entry_set_text(GTK_ENTRY(entry), str ? str : "")
+
+static gboolean prefs_actions_selected(GtkTreeSelection *selector,
+                                      GtkTreeModel *model, 
+                                      GtkTreePath *path,
+                                      gboolean currently_selected,
+                                      gpointer data)
+{
+       gchar *action;
+       gchar *cmd;
+       gchar buf[PREFSBUFSIZE];
+       GtkTreeIter iter;
+       gboolean is_valid;
+
+       if (currently_selected)
+               return TRUE;
+
+       if (!gtk_tree_model_get_iter(model, &iter, path))
+               return TRUE;
+
+       gtk_tree_model_get(model, &iter, 
+                          PREFS_ACTIONS_VALID,  &is_valid,
+                          PREFS_ACTIONS_DATA, &action,
+                          -1);
+       if (!is_valid) {
+               ENTRY_SET_TEXT(actions.name_entry, "");
+               ENTRY_SET_TEXT(actions.cmd_entry, "");
+               return TRUE;
+       }
+       
+       strncpy(buf, action, PREFSBUFSIZE - 1);
+       buf[PREFSBUFSIZE - 1] = 0x00;
+       cmd = strstr(buf, ": ");
+
+       if (cmd && cmd[2])
+               ENTRY_SET_TEXT(actions.cmd_entry, &cmd[2]);
+       else
+               return;
+
+       *cmd = 0x00;
+       ENTRY_SET_TEXT(actions.name_entry, buf);
+
+       return TRUE;
+}
+
index 4644f76f57d37823a79842fb5637f0b5f32355b7..91fff8cb356c2fd71ad739c1195aa2d85925d9c7 100644 (file)
 #include "gtkutils.h"
 #include "alertpanel.h"
 
+enum {
+       CUSTHDR_STRING,         /*!< display string managed by list store */
+       CUSTHDR_DATA,           /*!< string managed by us */
+       N_CUSTHDR_COLUMNS
+};
+
 static struct CustomHdr {
        GtkWidget *window;
 
@@ -55,31 +61,21 @@ static struct CustomHdr {
        GtkWidget *hdr_combo;
        GtkWidget *hdr_entry;
        GtkWidget *val_entry;
-       GtkWidget *customhdr_clist;
+       GtkWidget *list_view;
 } customhdr;
 
 /* widget creating functions */
 static void prefs_custom_header_create (void);
 
-static void prefs_custom_header_set_dialog     (PrefsAccount *ac);
-static void prefs_custom_header_set_list       (PrefsAccount *ac);
-static gint prefs_custom_header_clist_set_row  (PrefsAccount *ac,
-                                                gint          row);
+static void prefs_custom_header_set_dialog             (PrefsAccount *ac);
+static void prefs_custom_header_set_list               (PrefsAccount *ac);
+static void prefs_custom_header_list_view_set_row      (PrefsAccount *ac);
 
 /* callback functions */
 static void prefs_custom_header_add_cb         (void);
 static void prefs_custom_header_delete_cb      (void);
 static void prefs_custom_header_up             (void);
 static void prefs_custom_header_down           (void);
-static void prefs_custom_header_select         (GtkCList       *clist,
-                                                gint            row,
-                                                gint            column,
-                                                GdkEvent       *event);
-
-static void prefs_custom_header_row_moved      (GtkCList       *clist,
-                                                gint            source_row,
-                                                gint            dest_row,
-                                                gpointer        data);
 
 static gboolean prefs_custom_header_key_pressed        (GtkWidget      *widget,
                                                 GdkEventKey    *event,
@@ -90,6 +86,24 @@ static gint prefs_custom_header_deleted              (GtkWidget      *widget,
                                                 GdkEventAny    *event,
                                                 gpointer        data);
 
+static GtkListStore* prefs_custom_header_create_data_store     (void);
+
+static void prefs_custom_header_list_view_insert_header        (GtkWidget *list_view,
+                                                        GtkTreeIter *row_iter,
+                                                        gchar *header,
+                                                        gpointer data);
+
+static GtkWidget *prefs_custom_header_list_view_create (void);
+
+static void prefs_custom_header_create_list_view_columns       (GtkWidget *list_view);
+
+static gboolean prefs_custom_header_selected   (GtkTreeSelection *selector,
+                                                GtkTreeModel *model, 
+                                                GtkTreePath *path,
+                                                gboolean currently_selected,
+                                                gpointer data);
+
+
 static PrefsAccount *cur_ac = NULL;
 
 void prefs_custom_header_open(PrefsAccount *ac)
@@ -134,7 +148,7 @@ static void prefs_custom_header_create(void)
 
        GtkWidget *ch_hbox;
        GtkWidget *ch_scrolledwin;
-       GtkWidget *customhdr_clist;
+       GtkWidget *list_view;
 
        GtkWidget *btn_vbox;
        GtkWidget *up_btn;
@@ -258,23 +272,9 @@ static void prefs_custom_header_create(void)
                                        GTK_POLICY_AUTOMATIC,
                                        GTK_POLICY_AUTOMATIC);
 
-       title[0] = _("Current custom headers");
-       customhdr_clist = gtk_clist_new_with_titles(1, title);
-       gtk_widget_show (customhdr_clist);
-       gtk_container_add (GTK_CONTAINER (ch_scrolledwin), customhdr_clist);
-       gtk_clist_set_column_width (GTK_CLIST (customhdr_clist), 0, 80);
-       gtk_clist_set_selection_mode (GTK_CLIST (customhdr_clist),
-                                     GTK_SELECTION_BROWSE);
-       gtk_clist_set_reorderable (GTK_CLIST (customhdr_clist), TRUE);
-       gtk_clist_set_use_drag_icons (GTK_CLIST (customhdr_clist), FALSE);
-       GTK_WIDGET_UNSET_FLAGS (GTK_CLIST (customhdr_clist)->column[0].button,
-                               GTK_CAN_FOCUS);
-       g_signal_connect (G_OBJECT (customhdr_clist), "select_row",
-                         G_CALLBACK (prefs_custom_header_select),
-                         NULL);
-       g_signal_connect_after
-               (G_OBJECT (customhdr_clist), "row_move",
-                G_CALLBACK (prefs_custom_header_row_moved), NULL);
+       list_view = prefs_custom_header_list_view_create();
+       gtk_widget_show (list_view);
+       gtk_container_add (GTK_CONTAINER (ch_scrolledwin), list_view);
 
        btn_vbox = gtk_vbox_new (FALSE, 8);
        gtk_widget_show (btn_vbox);
@@ -302,7 +302,7 @@ static void prefs_custom_header_create(void)
        customhdr.hdr_entry  = GTK_COMBO (hdr_combo)->entry;
        customhdr.val_entry  = val_entry;
 
-       customhdr.customhdr_clist   = customhdr_clist;
+       customhdr.list_view   = list_view;
 }
 
 void prefs_custom_header_read_config(PrefsAccount *ac)
@@ -434,58 +434,68 @@ void prefs_custom_header_write_config(PrefsAccount *ac)
 
 static void prefs_custom_header_set_dialog(PrefsAccount *ac)
 {
-       GtkCList *clist = GTK_CLIST(customhdr.customhdr_clist);
+       GtkListStore *store;
        GSList *cur;
-       gchar *ch_str[1];
-       gint row;
-
-       gtk_clist_freeze(clist);
-       gtk_clist_clear(clist);
+       
+       store = GTK_LIST_STORE(gtk_tree_view_get_model
+                               (GTK_TREE_VIEW(customhdr.list_view)));
+       gtk_list_store_clear(store);
 
        for (cur = ac->customhdr_list; cur != NULL; cur = cur->next) {
                CustomHeader *ch = (CustomHeader *)cur->data;
+               gchar *ch_str;
 
-               ch_str[0] = g_strdup_printf("%s: %s", ch->name,
-                                           ch->value ? ch->value : "");
-               row = gtk_clist_append(clist, ch_str);
-               gtk_clist_set_row_data(clist, row, ch);
+               ch_str = g_strdup_printf("%s: %s", ch->name,
+                                        ch->value ? ch->value : "");
 
-               g_free(ch_str[0]);
-       }
+               prefs_custom_header_list_view_insert_header
+                       (customhdr.list_view, NULL, ch_str, ch);                                                 
 
-       gtk_clist_thaw(clist);
+               g_free(ch_str);
+       }
 }
 
 static void prefs_custom_header_set_list(PrefsAccount *ac)
 {
-       gint row = 0;
        CustomHeader *ch;
+       GtkTreeIter iter;
+       GtkListStore *store;
 
        g_slist_free(ac->customhdr_list);
        ac->customhdr_list = NULL;
 
-       while ((ch = gtk_clist_get_row_data
-               (GTK_CLIST(customhdr.customhdr_clist), row)) != NULL) {
-               ac->customhdr_list = g_slist_append(ac->customhdr_list, ch);
-               row++;
+       store = GTK_LIST_STORE(gtk_tree_view_get_model
+                               (GTK_TREE_VIEW(customhdr.list_view)));
+
+       if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) {
+               do {
+                       gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
+                                          CUSTHDR_DATA, &ch,
+                                          -1);
+                       ac->customhdr_list = g_slist_append(ac->customhdr_list, ch);
+               } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store),
+                                                 &iter));
        }
 }
 
-static gint prefs_custom_header_clist_set_row(PrefsAccount *ac, gint row)
+static void prefs_custom_header_list_view_set_row(PrefsAccount *ac)
 {
-       GtkCList *clist = GTK_CLIST(customhdr.customhdr_clist);
        CustomHeader *ch;
        const gchar *entry_text;
-       gchar *ch_str[1];
+       gchar *ch_str;
+       GtkListStore *store;
+
+       store = GTK_LIST_STORE(gtk_tree_view_get_model
+                               (GTK_TREE_VIEW(customhdr.list_view)));
 
        entry_text = gtk_entry_get_text(GTK_ENTRY(customhdr.hdr_entry));
        if (entry_text[0] == '\0') {
                alertpanel_error(_("Header name is not set."));
-               return -1;
+               return;
        }
        if (!custom_header_is_allowed(entry_text)) {
                alertpanel_error(_("This Header name is not allowed as a custom header."));
-               return -1;
+               return;
        }
 
        ch = g_new0(CustomHeader, 1);
@@ -505,99 +515,101 @@ static gint prefs_custom_header_clist_set_row(PrefsAccount *ac, gint row)
                gtk_entry_set_text(GTK_ENTRY(customhdr.val_entry), ch->value);
        }
 
-       ch_str[0] = g_strdup_printf("%s: %s", ch->name,
-                                   ch->value ? ch->value : "");
-
-       if (row < 0)
-               row = gtk_clist_append(clist, ch_str);
-       else {
-               CustomHeader *tmp_ch;
-
-               gtk_clist_set_text(clist, row, 0, ch_str[0]);
-               tmp_ch = gtk_clist_get_row_data(clist, row);
-               if (tmp_ch)
-                       custom_header_free(tmp_ch);
-       }
-
-       gtk_clist_set_row_data(clist, row, ch);
-
-       g_free(ch_str[0]);
+       ch_str = g_strdup_printf("%s: %s", ch->name,
+                                ch->value ? ch->value : "");
+       
+       prefs_custom_header_list_view_insert_header
+               (customhdr.list_view, NULL, ch_str, ch);
+       
+       g_free(ch_str);
 
        prefs_custom_header_set_list(cur_ac);
 
-       return row;
 }
 
 static void prefs_custom_header_add_cb(void)
 {
-       prefs_custom_header_clist_set_row(cur_ac, -1);
+       prefs_custom_header_list_view_set_row(cur_ac);
 }
 
 static void prefs_custom_header_delete_cb(void)
 {
-       GtkCList *clist = GTK_CLIST(customhdr.customhdr_clist);
+       GtkTreeIter sel;
+       GtkTreeModel *model;
        CustomHeader *ch;
-       gint row;
 
-       if (!clist->selection) return;
-       row = GPOINTER_TO_INT(clist->selection->data);
+       if (!gtk_tree_selection_get_selected(gtk_tree_view_get_selection
+                               (GTK_TREE_VIEW(customhdr.list_view)),
+                               &model, &sel))
+               return; 
 
        if (alertpanel(_("Delete header"),
                       _("Do you really want to delete this header?"),
                       _("Yes"), _("No"), NULL) != G_ALERTDEFAULT)
                return;
 
-       ch = gtk_clist_get_row_data(clist, row);
-       custom_header_free(ch);
-       gtk_clist_remove(clist, row);
+       gtk_tree_model_get(model, &sel,
+                          CUSTHDR_DATA, &ch,
+                          -1);
+       gtk_list_store_remove(GTK_LIST_STORE(model), &sel);
+
        cur_ac->customhdr_list = g_slist_remove(cur_ac->customhdr_list, ch);
+       
+       custom_header_free(ch);
 }
 
 static void prefs_custom_header_up(void)
 {
-       GtkCList *clist = GTK_CLIST(customhdr.customhdr_clist);
-       gint row;
-
-       if (!clist->selection) return;
-
-       row = GPOINTER_TO_INT(clist->selection->data);
-       if (row > 0)
-               gtk_clist_row_move(clist, row, row - 1);
-}
+       GtkTreePath *prev, *sel;
+       GtkTreeIter isel;
+       GtkListStore *store;
+       GtkTreeIter iprev;
+       
+       if (!gtk_tree_selection_get_selected
+               (gtk_tree_view_get_selection
+                       (GTK_TREE_VIEW(customhdr.list_view)),
+                (GtkTreeModel **) &store,      
+                &isel))
+               return;
 
-static void prefs_custom_header_down(void)
-{
-       GtkCList *clist = GTK_CLIST(customhdr.customhdr_clist);
-       gint row;
+       sel = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &isel);
+       if (!sel)
+               return;
+       
+       /* no move if we're at row 0... */
+       prev = gtk_tree_path_copy(sel);
+       if (!gtk_tree_path_prev(prev)) {
+               gtk_tree_path_free(prev);
+               gtk_tree_path_free(sel);
+               return;
+       }
 
-       if (!clist->selection) return;
+       gtk_tree_model_get_iter(GTK_TREE_MODEL(store),
+                               &iprev, prev);
+       gtk_tree_path_free(sel);
+       gtk_tree_path_free(prev);
 
-       row = GPOINTER_TO_INT(clist->selection->data);
-       if (row >= 0 && row < clist->rows - 1)
-               gtk_clist_row_move(clist, row, row + 1);
+       gtk_list_store_swap(store, &iprev, &isel);
+       prefs_custom_header_set_list(cur_ac);
 }
 
-#define ENTRY_SET_TEXT(entry, str) \
-       gtk_entry_set_text(GTK_ENTRY(entry), str ? str : "")
-
-static void prefs_custom_header_select(GtkCList *clist, gint row, gint column,
-                                      GdkEvent *event)
+static void prefs_custom_header_down(void)
 {
-       CustomHeader *ch;
-       CustomHeader default_ch = { 0, "", NULL };
-
-       ch = gtk_clist_get_row_data(clist, row);
-       if (!ch) ch = &default_ch;
-
-       ENTRY_SET_TEXT(customhdr.hdr_entry, ch->name);
-       ENTRY_SET_TEXT(customhdr.val_entry, ch->value);
-}
+       GtkListStore *store;
+       GtkTreeIter next, sel;
+       
+       if (!gtk_tree_selection_get_selected
+               (gtk_tree_view_get_selection
+                       (GTK_TREE_VIEW(customhdr.list_view)),
+                (GtkTreeModel **) &store,
+                &sel))
+               return;
 
-#undef ENTRY_SET_TEXT
+       next = sel;
+       if (!gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &next)) 
+               return;
 
-static void prefs_custom_header_row_moved(GtkCList *clist, gint source_row,
-                                         gint dest_row, gpointer data)
-{
+       gtk_list_store_swap(store, &next, &sel);
        prefs_custom_header_set_list(cur_ac);
 }
 
@@ -628,3 +640,114 @@ static gint prefs_custom_header_deleted(GtkWidget *widget, GdkEventAny *event,
        prefs_custom_header_cancel();
        return TRUE;
 }
+
+static GtkListStore* prefs_custom_header_create_data_store(void)
+{
+       return gtk_list_store_new(N_CUSTHDR_COLUMNS,
+                                 G_TYPE_STRING,        
+                                 G_TYPE_POINTER,
+                                 -1);
+}
+
+static void prefs_custom_header_list_view_insert_header(GtkWidget *list_view,
+                                                       GtkTreeIter *row_iter,
+                                                       gchar *header,
+                                                       gpointer data)
+{
+       GtkTreeIter iter;
+       GtkListStore *list_store = GTK_LIST_STORE(gtk_tree_view_get_model
+                                       (GTK_TREE_VIEW(list_view)));
+
+       if (row_iter == NULL) {
+               /* append new */
+               gtk_list_store_append(list_store, &iter);
+               gtk_list_store_set(list_store, &iter,
+                                  CUSTHDR_STRING, header,
+                                  CUSTHDR_DATA,   data,
+                                  -1);
+       } else {
+               /* change existing */
+               CustomHeader *old_data;
+
+               gtk_tree_model_get(GTK_TREE_MODEL(list_store), row_iter,
+                                  CUSTHDR_DATA, &old_data,
+                                  -1);
+
+               custom_header_free(old_data);
+               
+               gtk_list_store_set(list_store, row_iter,
+                                  CUSTHDR_STRING, header,
+                                  CUSTHDR_DATA, data,
+                                  -1);
+       }
+}
+
+static GtkWidget *prefs_custom_header_list_view_create(void)
+{
+       GtkTreeView *list_view;
+       GtkTreeSelection *selector;
+       GtkTreeModel *model;
+
+       model = GTK_TREE_MODEL(prefs_custom_header_create_data_store());
+       list_view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(model));
+       g_object_unref(model);  
+       
+       gtk_tree_view_set_rules_hint(list_view, TRUE);
+       
+       selector = gtk_tree_view_get_selection(list_view);
+       gtk_tree_selection_set_mode(selector, GTK_SELECTION_BROWSE);
+       gtk_tree_selection_set_select_function(selector, prefs_custom_header_selected,
+                                              NULL, NULL);
+
+       /* create the columns */
+       prefs_custom_header_create_list_view_columns(GTK_WIDGET(list_view));
+
+       return GTK_WIDGET(list_view);
+}
+
+static void prefs_custom_header_create_list_view_columns(GtkWidget *list_view)
+{
+       GtkTreeViewColumn *column;
+       GtkCellRenderer *renderer;
+
+       renderer = gtk_cell_renderer_text_new();
+       column = gtk_tree_view_column_new_with_attributes
+               (_("Current custom headers"),
+                renderer,
+                "text", CUSTHDR_STRING,
+                NULL);
+       gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);          
+}
+
+#define ENTRY_SET_TEXT(entry, str) \
+       gtk_entry_set_text(GTK_ENTRY(entry), str ? str : "")
+
+static gboolean prefs_custom_header_selected(GtkTreeSelection *selector,
+                                            GtkTreeModel *model, 
+                                            GtkTreePath *path,
+                                            gboolean currently_selected,
+                                            gpointer data)
+{
+       GtkTreeIter iter;
+       CustomHeader *ch;
+       CustomHeader default_ch = { 0, "", NULL };
+
+       if (currently_selected)
+               return TRUE;
+
+       if (!gtk_tree_model_get_iter(model, &iter, path))
+               return TRUE;
+
+       gtk_tree_model_get(model, &iter, 
+                          CUSTHDR_DATA, &ch,
+                          -1);
+       
+       if (!ch) ch = &default_ch;
+
+       ENTRY_SET_TEXT(customhdr.hdr_entry, ch->name);
+       ENTRY_SET_TEXT(customhdr.val_entry, ch->value);
+                          
+       return TRUE;
+}
+
+#undef ENTRY_SET_TEXT
index 993346fdaeb2e38e1d5ad0072e4bdff653c8bb0f..d8602954cbb4d078e74060663c5172d4e49806c0 100644 (file)
 #include "matcher.h"
 #include "prefs_filtering_action.h"
 
+enum {
+       PREFS_FILTERING_RULE,
+       PREFS_FILTERING_PROP,
+       N_PREFS_FILTERING_COLUMNS
+};
+
 static struct Filtering {
        GtkWidget *window;
 
@@ -61,7 +67,7 @@ static struct Filtering {
        GtkWidget *cond_entry;
        GtkWidget *action_entry;
 
-       GtkWidget *cond_clist;
+       GtkWidget *cond_list_view;
 } filtering;
 
 static GSList ** p_processing_list = NULL;
@@ -81,11 +87,6 @@ static void prefs_filtering_top              (void);
 static void prefs_filtering_up         (void);
 static void prefs_filtering_down       (void);
 static void prefs_filtering_bottom     (void);
-static void prefs_filtering_select     (GtkCList       *clist,
-                                        gint            row,
-                                        gint            column,
-                                        GdkEvent       *event);
-
 static gint prefs_filtering_deleted    (GtkWidget      *widget,
                                         GdkEventAny    *event,
                                         gpointer        data);
@@ -97,7 +98,7 @@ static void prefs_filtering_ok                (void);
 
 static void prefs_filtering_condition_define   (void);
 static void prefs_filtering_action_define(void);
-static gint prefs_filtering_clist_set_row      (gint row, FilteringProp * prop);
+static gint prefs_filtering_list_view_set_row  (gint row, FilteringProp * prop);
                                          
 static void prefs_filtering_reset_dialog       (void);
 static gboolean prefs_filtering_rename_path_func(GNode *node, gpointer data);
@@ -105,6 +106,26 @@ static gboolean prefs_filtering_delete_path_func(GNode *node, gpointer data);
 
 static void delete_path(GSList ** p_filters, const gchar * path);
 
+
+static GtkListStore* prefs_filtering_create_data_store (void);
+static gint prefs_filtering_list_view_insert_rule      (GtkListStore *list_store,
+                                                        gint row,
+                                                        const gchar *rule, 
+                                                        gboolean prop);
+static gchar *prefs_filtering_list_view_get_rule       (GtkWidget *list, 
+                                                        gint row);
+
+static GtkWidget *prefs_filtering_list_view_create     (void);
+static void prefs_filtering_create_list_view_columns   (GtkWidget *list_view);
+static gint prefs_filtering_get_selected_row           (GtkWidget *list_view);
+static gboolean prefs_filtering_list_view_select_row   (GtkWidget *list, gint row);
+
+static gboolean prefs_filtering_selected               (GtkTreeSelection *selector,
+                                                        GtkTreeModel *model, 
+                                                        GtkTreePath *path,
+                                                        gboolean currently_selected,
+                                                        gpointer data);
+
 void prefs_filtering_open(GSList ** p_processing,
                          const gchar * title,
                          const gchar *header,
@@ -173,7 +194,7 @@ static void prefs_filtering_create(void)
 
        GtkWidget *cond_hbox;
        GtkWidget *cond_scrolledwin;
-       GtkWidget *cond_clist;
+       GtkWidget *cond_list_view;
 
        GtkWidget *btn_vbox;
        GtkWidget *spc_vbox;
@@ -309,17 +330,9 @@ static void prefs_filtering_create(void)
                                        GTK_POLICY_AUTOMATIC,
                                        GTK_POLICY_AUTOMATIC);
 
-       title[0] = _("Current filtering/processing rules");
-       cond_clist = gtk_clist_new_with_titles(1, title);
-       gtk_widget_show (cond_clist);
-       gtk_container_add (GTK_CONTAINER (cond_scrolledwin), cond_clist);
-       gtk_clist_set_column_width (GTK_CLIST (cond_clist), 0, 80);
-       gtk_clist_set_selection_mode (GTK_CLIST (cond_clist),
-                                     GTK_SELECTION_BROWSE);
-       GTK_WIDGET_UNSET_FLAGS (GTK_CLIST (cond_clist)->column[0].button,
-                               GTK_CAN_FOCUS);
-       g_signal_connect(G_OBJECT (cond_clist), "select_row",
-                        G_CALLBACK(prefs_filtering_select), NULL);
+       cond_list_view = prefs_filtering_list_view_create();    
+       gtk_widget_show (cond_list_view);
+       gtk_container_add (GTK_CONTAINER (cond_scrolledwin), cond_list_view);
 
        btn_vbox = gtk_vbox_new (FALSE, 8);
        gtk_widget_show (btn_vbox);
@@ -360,15 +373,9 @@ static void prefs_filtering_create(void)
        filtering.window    = window;
        filtering.ok_btn = ok_btn;
 
-       filtering.cond_entry = cond_entry;
-       filtering.action_entry = action_entry;
-       filtering.cond_clist   = cond_clist;
-}
-
-static void prefs_filtering_update_hscrollbar(void)
-{
-       gint optwidth = gtk_clist_optimal_column_width(GTK_CLIST(filtering.cond_clist), 0);
-       gtk_clist_set_column_width(GTK_CLIST(filtering.cond_clist), 0, optwidth);
+       filtering.cond_entry     = cond_entry;
+       filtering.action_entry   = action_entry;
+       filtering.cond_list_view = cond_list_view;
 }
 
 static void rename_path(GSList * filters,
@@ -581,35 +588,35 @@ static gboolean prefs_filtering_delete_path_func(GNode *node, gpointer data)
 
 static void prefs_filtering_set_dialog(const gchar *header, const gchar *key)
 {
-       GtkCList *clist = GTK_CLIST(filtering.cond_clist);
+       GtkTreeView *list_view = GTK_TREE_VIEW(filtering.cond_list_view);
        GSList *cur;
        GSList * prefs_filtering;
-       gchar *cond_str[1];
+       gchar *cond_str;
        gint row;
+       GtkListStore *list_store;
        
-       gtk_clist_freeze(clist);
-       gtk_clist_clear(clist);
+       list_store = GTK_LIST_STORE(gtk_tree_view_get_model(list_view));
+       gtk_list_store_clear(list_store);
 
-       cond_str[0] = _("(New)");
-       row = gtk_clist_append(clist, cond_str);
-       gtk_clist_set_row_data(clist, row, NULL);
+       /* add the place holder (New) at row 0 */
+       prefs_filtering_list_view_insert_rule(list_store, -1, 
+                                             _("(New)"),
+                                             FALSE);
 
-        prefs_filtering = * p_processing_list;
+        prefs_filtering = *p_processing_list;
 
        for(cur = prefs_filtering ; cur != NULL ; cur = g_slist_next(cur)) {
                FilteringProp * prop = (FilteringProp *) cur->data;
 
-               cond_str[0] = filteringprop_to_string(prop);
-               subst_char(cond_str[0], '\t', ':');
-               row = gtk_clist_append(clist, cond_str);
-               gtk_clist_set_row_data(clist, row, prop);
+               cond_str = filteringprop_to_string(prop);
+               subst_char(cond_str, '\t', ':');
 
-               g_free(cond_str[0]);
+               prefs_filtering_list_view_insert_rule(list_store, -1, 
+                                                     cond_str, TRUE);
+               
+               g_free(cond_str);
        }
 
-       prefs_filtering_update_hscrollbar();
-       gtk_clist_thaw(clist);
-
        prefs_filtering_reset_dialog();
 
        if (header && key) {
@@ -641,48 +648,45 @@ static void prefs_filtering_set_list(void)
        gchar * filtering_str;
        GSList * prefs_filtering;
 
-        prefs_filtering = * p_processing_list;
-
-       for(cur = prefs_filtering ; cur != NULL ; cur = g_slist_next(cur))
+        prefs_filtering = *p_processing_list;
+       for (cur = prefs_filtering ; cur != NULL ; cur = g_slist_next(cur))
                filteringprop_free((FilteringProp *) cur->data);
        g_slist_free(prefs_filtering);
        prefs_filtering = NULL;
+       
 
-       while (gtk_clist_get_text(GTK_CLIST(filtering.cond_clist),
-                                 row, 0, &filtering_str)) {
+       while (NULL != (filtering_str = prefs_filtering_list_view_get_rule
+                                               (filtering.cond_list_view, row))) {
+               /* FIXME: this strcmp() is bogus: "(New)" should never
+                * be inserted in the storage */
                if (strcmp(filtering_str, _("(New)")) != 0) {
                        prop = matcher_parser_get_filtering(filtering_str);
-                       if (prop != NULL)
-                               prefs_filtering =
+                       g_free(filtering_str);
+                       if (prop) 
+                               prefs_filtering = 
                                        g_slist_append(prefs_filtering, prop);
                }
+               
                row++;
-       }
-
-        * p_processing_list = prefs_filtering;
+       }                               
+       
+        *p_processing_list = prefs_filtering;
 }
 
-static gint prefs_filtering_clist_set_row(gint row, FilteringProp * prop)
+static gint prefs_filtering_list_view_set_row(gint row, FilteringProp * prop)
 {
-       GtkCList *clist = GTK_CLIST(filtering.cond_clist);
-       gchar * str;
-       gchar *cond_str[1];
-
-       if (prop == NULL) {
-               cond_str[0] = _("(New)");
-               return gtk_clist_append(clist, cond_str);
-       }
+       GtkTreeView *list_view = GTK_TREE_VIEW(filtering.cond_list_view);
+       gchar *str;
+       GtkListStore *list_store;
 
        str = filteringprop_to_string(prop);
-       if (str == NULL) {
+       if (str == NULL)
                return -1;
-       }
-       cond_str[0] = str;
 
-       if (row < 0)
-               row = gtk_clist_append(clist, cond_str);
-       else
-               gtk_clist_set_text(clist, row, 0, cond_str[0]);
+       list_store = GTK_LIST_STORE(gtk_tree_view_get_model(list_view));
+
+       row = prefs_filtering_list_view_insert_rule(list_store, row, str, prop != NULL);
+
        g_free(str);
 
        return row;
@@ -819,107 +823,131 @@ static void prefs_filtering_register_cb(void)
        prop = prefs_filtering_dialog_to_filtering(TRUE);
        if (prop == NULL)
                return;
-       prefs_filtering_clist_set_row(-1, prop);
-
-       filteringprop_free(prop);
+       prefs_filtering_list_view_set_row(-1, prop);
        
-       prefs_filtering_update_hscrollbar();
+       filteringprop_free(prop);
 }
 
 static void prefs_filtering_substitute_cb(void)
 {
-       GtkCList *clist = GTK_CLIST(filtering.cond_clist);
-       gint row;
-       FilteringProp * prop;
+       gint selected_row = prefs_filtering_get_selected_row
+               (filtering.cond_list_view);
+       FilteringProp *prop;
        
-       if (!clist->selection) return;
-
-       row = GPOINTER_TO_INT(clist->selection->data);
-       if (row == 0) return;
+       if (selected_row <= 0)
+               return;
 
        prop = prefs_filtering_dialog_to_filtering(TRUE);
-       if (prop == NULL)
+       if (prop == NULL) 
                return;
-       prefs_filtering_clist_set_row(row, prop);
+       prefs_filtering_list_view_set_row(selected_row, prop);
 
        filteringprop_free(prop);
-       
-       prefs_filtering_update_hscrollbar();
 }
 
 static void prefs_filtering_delete_cb(void)
 {
-       GtkCList *clist = GTK_CLIST(filtering.cond_clist);
+       GtkTreeView *list_view = GTK_TREE_VIEW(filtering.cond_list_view);
+       GtkTreeModel *model;
+       GtkTreeIter iter;
        gint row;
-
-       if (!clist->selection) return;
-       row = GPOINTER_TO_INT(clist->selection->data);
-       if (row == 0) return;
+       
+       row = prefs_filtering_get_selected_row(filtering.cond_list_view);
+       if (row <= 0) 
+               return; 
 
        if (alertpanel(_("Delete rule"),
                       _("Do you really want to delete this rule?"),
                       _("Yes"), _("No"), NULL) == G_ALERTALTERNATE)
                return;
 
-       gtk_clist_remove(clist, row);
+       model = gtk_tree_view_get_model(list_view);     
+       if (!gtk_tree_model_iter_nth_child(model, &iter, NULL, row))
+               return;
 
-       prefs_filtering_reset_dialog();
+       gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
 
-       prefs_filtering_update_hscrollbar();
+       prefs_filtering_reset_dialog();
 }
 
 static void prefs_filtering_top(void)
 {
-       GtkCList *clist = GTK_CLIST(filtering.cond_clist);
        gint row;
+       GtkTreeIter top, sel;
+       GtkTreeModel *model;
 
-       if (!clist->selection) return;
+       row = prefs_filtering_get_selected_row(filtering.cond_list_view);
+       if (row <= 1) 
+               return;
 
-       row = GPOINTER_TO_INT(clist->selection->data);
-       if (row > 1)
-               gtk_clist_row_move(clist, row, 1);
+       model = gtk_tree_view_get_model(GTK_TREE_VIEW(filtering.cond_list_view));               
+       
+       if (!gtk_tree_model_iter_nth_child(model, &top, NULL, 0)
+       ||  !gtk_tree_model_iter_nth_child(model, &sel, NULL, row))
+               return;
+
+       gtk_list_store_move_after(GTK_LIST_STORE(model), &sel, &top);
+       prefs_filtering_list_view_select_row(filtering.cond_list_view, 1);
 }
 
 static void prefs_filtering_up(void)
 {
-       GtkCList *clist = GTK_CLIST(filtering.cond_clist);
        gint row;
+       GtkTreeIter top, sel;
+       GtkTreeModel *model;
+
+       row = prefs_filtering_get_selected_row(filtering.cond_list_view);
+       if (row <= 1) 
+               return;
+               
+       model = gtk_tree_view_get_model(GTK_TREE_VIEW(filtering.cond_list_view));       
 
-       if (!clist->selection) return;
+       if (!gtk_tree_model_iter_nth_child(model, &top, NULL, row - 1)
+       ||  !gtk_tree_model_iter_nth_child(model, &sel, NULL, row))
+               return;
 
-       row = GPOINTER_TO_INT(clist->selection->data);
-       if (row > 1) {
-               gtk_clist_row_move(clist, row, row - 1);
-               if (gtk_clist_row_is_visible(clist, row - 1) != GTK_VISIBILITY_FULL) 
-                       gtk_clist_moveto(clist, row - 1, 0, 0, 0); 
-       }
+       gtk_list_store_swap(GTK_LIST_STORE(model), &top, &sel);
+       prefs_filtering_list_view_select_row(filtering.cond_list_view, row - 1);
 }
 
 static void prefs_filtering_down(void)
 {
-       GtkCList *clist = GTK_CLIST(filtering.cond_clist);
-       gint row;
-
-       if (!clist->selection) return;
+       gint row, n_rows;
+       GtkTreeIter top, sel;
+       GtkTreeModel *model;
+
+       model = gtk_tree_view_get_model(GTK_TREE_VIEW(filtering.cond_list_view));       
+       n_rows = gtk_tree_model_iter_n_children(model, NULL);
+       row = prefs_filtering_get_selected_row(filtering.cond_list_view);
+       if (row < 1 || row >= n_rows - 1)
+               return;
 
-       row = GPOINTER_TO_INT(clist->selection->data);
-       if (row > 0 && row < clist->rows - 1) {
-               gtk_clist_row_move(clist, row, row + 1);
-               if (gtk_clist_row_is_visible(clist, row + 1) != GTK_VISIBILITY_FULL)
-                       gtk_clist_moveto(clist, row + 1, 0, 1, 0); 
-       }
+       if (!gtk_tree_model_iter_nth_child(model, &top, NULL, row)
+       ||  !gtk_tree_model_iter_nth_child(model, &sel, NULL, row + 1))
+               return;
+                       
+       gtk_list_store_swap(GTK_LIST_STORE(model), &top, &sel);
+       prefs_filtering_list_view_select_row(filtering.cond_list_view, row + 1);
 }
 
 static void prefs_filtering_bottom(void)
 {
-       GtkCList *clist = GTK_CLIST(filtering.cond_clist);
-       gint row;
+       gint row, n_rows;
+       GtkTreeIter top, sel;
+       GtkTreeModel *model;
+
+       model = gtk_tree_view_get_model(GTK_TREE_VIEW(filtering.cond_list_view));       
+       n_rows = gtk_tree_model_iter_n_children(model, NULL);
+       row = prefs_filtering_get_selected_row(filtering.cond_list_view);
+       if (row < 1 || row >= n_rows - 1)
+               return;
 
-       if (!clist->selection) return;
+       if (!gtk_tree_model_iter_nth_child(model, &top, NULL, row)
+       ||  !gtk_tree_model_iter_nth_child(model, &sel, NULL, n_rows - 1))
+               return;
 
-       row = GPOINTER_TO_INT(clist->selection->data);
-       if (row > 0 && row < clist->rows - 1)
-               gtk_clist_row_move(clist, row, clist->rows - 1);
+       gtk_list_store_move_after(GTK_LIST_STORE(model), &top, &sel);           
+       prefs_filtering_list_view_select_row(filtering.cond_list_view, n_rows - 1);
 }
 
 static void prefs_filtering_select_set(FilteringProp *prop)
@@ -946,31 +974,6 @@ static void prefs_filtering_select_set(FilteringProp *prop)
        g_free(matcher_str);
 }
 
-static void prefs_filtering_select(GtkCList *clist, gint row, gint column,
-                               GdkEvent *event)
-{
-       FilteringProp * prop;
-       gchar * filtering_str;
-
-       if (row == 0) {
-               prefs_filtering_reset_dialog();
-               return;
-       }
-
-        if (!gtk_clist_get_text(GTK_CLIST(filtering.cond_clist),
-                               row, 0, &filtering_str))
-               return;
-       
-       prop = matcher_parser_get_filtering(filtering_str);
-       if (prop == NULL)
-               return;
-
-       prefs_filtering_select_set(prop);
-
-       filteringprop_free(prop);
-}
-
-
 static gint prefs_filtering_deleted(GtkWidget *widget, GdkEventAny *event,
                                 gpointer data)
 {
@@ -1000,21 +1003,30 @@ static void prefs_filtering_ok(void)
        if (prop != NULL) {
                str = filteringprop_to_string(prop);
 
-               while (gtk_clist_get_text(GTK_CLIST(filtering.cond_clist),
-                                         row, 0, &filtering_str)) {
-                       if (strcmp(filtering_str, str) == 0) break;
+               while (NULL != (filtering_str = (prefs_filtering_list_view_get_rule
+                                                       (filtering.cond_list_view,
+                                                        row)))) {
+                       if (strcmp(filtering_str, str) == 0)
+                               break;
                        row++;
-               }
-               if (strcmp(filtering_str, str) != 0) {
+                       g_free(filtering_str);
+               }       
+
+               if (!filtering_str) {
                        val = alertpanel(_("Entry not saved"),
                                 _("The entry was not saved. Close anyway?"),
                                 _("Yes"), _("No"), NULL);
                        if (G_ALERTDEFAULT != val) {
-                               g_free(str);
+                               g_free(filtering_str);
+                               g_free(str); /* fixed two leaks: huzzah! */
+                               filteringprop_free(prop);
                                return;
                        }
-               }
+               }               
+
+               g_free(filtering_str);
                g_free(str);
+               filteringprop_free(prop); /* fixed a leak: huzzah! */
        }
        prefs_filtering_set_list();
        prefs_matcher_write_config();
@@ -1026,3 +1038,225 @@ static void prefs_filtering_cancel(void)
        prefs_matcher_read_config();
        prefs_filtering_close();
 }
+
+static GtkListStore* prefs_filtering_create_data_store(void)
+{
+       return gtk_list_store_new(N_PREFS_FILTERING_COLUMNS,
+                                 G_TYPE_STRING,
+                                 G_TYPE_BOOLEAN,
+                                -1);
+}
+
+/*!
+ *\brief       Insert filtering rule into store. Note that we access the
+ *             tree view / store by index, which is a bit suboptimal, but
+ *             at least it made GTK 2 porting easier.
+ *
+ *\param       list_store Store to operate on
+ *\param       row -1 to add a new rule to store, else change an existing
+ *             row
+ *\param       rule String representation of rule
+ *\param       prop TRUE if valid filtering rule; if FALSE it's the first
+ *             entry in the store ("(New)").
+ *
+ *\return      int Row of inserted / changed rule.
+ */
+static gint prefs_filtering_list_view_insert_rule(GtkListStore *list_store,
+                                                 gint row,
+                                                 const gchar *rule,
+                                                 gboolean prop) 
+{
+       GtkTreeIter iter;
+
+       /* check if valid row at all */
+       if (row >= 0) {
+               if (!gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(list_store),
+                                                  &iter, NULL, row))
+                       row = -1;                                                  
+       }
+
+       if (row < 0) {
+               /* append new */
+               gtk_list_store_append(list_store, &iter);
+               gtk_list_store_set(list_store, &iter, 
+                                  PREFS_FILTERING_RULE, rule,
+                                  PREFS_FILTERING_PROP, prop,
+                                  -1);
+               return gtk_tree_model_iter_n_children(GTK_TREE_MODEL(list_store),
+                                                     NULL) - 1;
+       } else {
+               /* change existing */
+               gtk_list_store_set(list_store, &iter, 
+                                  PREFS_FILTERING_RULE, rule,
+                                  -1);
+               return row;                                
+       }
+}
+
+/*!
+ *\return      gchar * Rule at specified row - should be freed.
+ */
+static gchar *prefs_filtering_list_view_get_rule(GtkWidget *list, gint row)
+{      
+       GtkTreeView *list_view = GTK_TREE_VIEW(list);
+       GtkTreeModel *model = gtk_tree_view_get_model(list_view);
+       GtkTreeIter iter;
+       gchar *result;
+
+       if (!gtk_tree_model_iter_nth_child(model, &iter, NULL, row))
+               return NULL;
+       
+       gtk_tree_model_get(model, &iter, 
+                          PREFS_FILTERING_RULE, &result,
+                          -1);
+       
+       return result;
+}
+
+/*!
+ *\brief       Create list view for filtering
+ */
+static GtkWidget *prefs_filtering_list_view_create(void)
+{
+       GtkTreeView *list_view;
+       GtkTreeSelection *selector;
+
+       list_view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL
+               (prefs_filtering_create_data_store())));
+       
+       gtk_tree_view_set_rules_hint(list_view, TRUE);
+       
+       selector = gtk_tree_view_get_selection(list_view);
+       gtk_tree_selection_set_mode(selector, GTK_SELECTION_BROWSE);
+       gtk_tree_selection_set_select_function(selector, prefs_filtering_selected,
+                                              NULL, NULL);
+
+       /* create the columns */
+       prefs_filtering_create_list_view_columns(GTK_WIDGET(list_view));
+
+       return GTK_WIDGET(list_view);
+}
+
+static void prefs_filtering_create_list_view_columns(GtkWidget *list_view)
+{
+       GtkTreeViewColumn *column;
+       GtkCellRenderer *renderer;
+
+       renderer = gtk_cell_renderer_text_new();
+       column = gtk_tree_view_column_new_with_attributes
+               (_("Current filtering/processing rules"),
+                renderer,
+                "text", PREFS_FILTERING_RULE,
+                NULL);
+       gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);          
+}
+
+static gboolean gtkut_tree_iter_comp(GtkTreeModel *model, 
+                                    GtkTreeIter *iter1, 
+                                    GtkTreeIter *iter2)
+{
+       GtkTreePath *path1 = gtk_tree_model_get_path(model, iter1);
+       GtkTreePath *path2 = gtk_tree_model_get_path(model, iter2);
+       gboolean result;
+
+       result = gtk_tree_path_compare(path1, path2) == 0;
+
+       gtk_tree_path_free(path1);
+       gtk_tree_path_free(path2);
+       
+       return result;
+}
+
+/*!
+ *\brief       Get selected row number.
+ */
+static gint prefs_filtering_get_selected_row(GtkWidget *list_view)
+{
+       GtkTreeView *view = GTK_TREE_VIEW(list_view);
+       GtkTreeModel *model = gtk_tree_view_get_model(view);
+       int n_rows = gtk_tree_model_iter_n_children(model, NULL);
+       GtkTreeSelection *selection;
+       GtkTreeIter iter;
+       int row;
+
+       if (n_rows == 0) 
+               return -1;
+       
+       selection = gtk_tree_view_get_selection(view);
+       if (!gtk_tree_selection_get_selected(selection, &model, &iter))
+               return -1;
+       
+       /* get all iterators and compare them... */
+       for (row = 0; row < n_rows; row++) {
+               GtkTreeIter itern;
+
+               gtk_tree_model_iter_nth_child(model, &itern, NULL, row);
+               if (gtkut_tree_iter_comp(model, &iter, &itern))
+                       return row;
+       }
+       
+       return -1;
+}
+
+static gboolean prefs_filtering_list_view_select_row(GtkWidget *list, gint row)
+{
+       GtkTreeView *list_view = GTK_TREE_VIEW(list);
+       GtkTreeSelection *selection = gtk_tree_view_get_selection(list_view);
+       GtkTreeModel *model = gtk_tree_view_get_model(list_view);
+       GtkTreeIter iter;
+       GtkTreePath *path;
+
+       if (!gtk_tree_model_iter_nth_child(model, &iter, NULL, row))
+               return FALSE;
+       
+       gtk_tree_selection_select_iter(selection, &iter);
+
+       path = gtk_tree_model_get_path(model, &iter);
+       gtk_tree_view_set_cursor(list_view, path, NULL, FALSE);
+       gtk_tree_path_free(path);
+       
+       return TRUE;
+}
+
+/*!
+ *\brief       Triggered when a row is selected
+ */
+static gboolean prefs_filtering_selected(GtkTreeSelection *selector,
+                                        GtkTreeModel *model, 
+                                        GtkTreePath *path,
+                                        gboolean currently_selected,
+                                        gpointer data)
+{
+       if (currently_selected)
+               return TRUE;
+       else {          
+               gboolean has_prop  = FALSE;
+               GtkTreeIter iter;
+
+               gtk_tree_model_get_iter(model, &iter, path);
+               gtk_tree_model_get(model, &iter,
+                                  PREFS_FILTERING_PROP, &has_prop,
+                                  -1);
+
+               if (has_prop) {
+                       FilteringProp *prop;
+                       gchar *filtering_str = NULL;
+                       
+                       gtk_tree_model_get(model, &iter,
+                                          PREFS_FILTERING_RULE, &filtering_str,
+                                          -1);
+
+                       prop = matcher_parser_get_filtering(filtering_str);
+                       if (prop) { 
+                               prefs_filtering_select_set(prop);
+                               filteringprop_free(prop);
+                       }                               
+                       
+                       g_free(filtering_str);
+               } else
+                       prefs_filtering_reset_dialog();
+       }               
+
+       return TRUE;
+}
+
index 6facc387bb17ca56c122ffd472c1c1906e9f3665..2409d62e211a0615fb3b13da47c9b94667653513 100644 (file)
@@ -331,7 +331,28 @@ static gboolean quote_colors_set_dialog_key_pressed(GtkWidget *widget,
                                                GdkEventKey *event,
                                                gpointer data)
 {
-       gtk_widget_destroy(color_dialog);
+       if (event) {
+               switch (event->keyval) {
+                       case GDK_Escape:
+                               gtk_button_clicked(GTK_BUTTON(GTK_COLOR_SELECTION_DIALOG
+                                                       (widget)->cancel_button));
+                               return TRUE;
+                       case GDK_Return: 
+                       case GDK_KP_Enter:
+                               /* NOTE: changing focus makes widget accept all currently 
+                                * changed settings! */
+                               gtk_widget_grab_focus
+                                       (GTK_COLOR_SELECTION_DIALOG
+                                               (widget)->ok_button);
+                               /* call ok handler */                                           
+                               gtk_button_clicked(GTK_BUTTON
+                                       (GTK_COLOR_SELECTION_DIALOG
+                                               (widget)->ok_button));
+                               return TRUE;
+                       default:
+                               break;
+               }
+       }
        return FALSE;
 }
 
index f89185e997d967e88bb461eba6eafd9ef0c99143..5a4c6bb9dc5bd4ab4920a3a01e709f2b56e26a1f 100644 (file)
@@ -28,7 +28,6 @@
 #include <gtk/gtkwindow.h>
 #include <gtk/gtkvbox.h>
 #include <gtk/gtkhbox.h>
-#include <gtk/gtkclist.h>
 #include <gtk/gtkbutton.h>
 #include <gdk/gdkkeysyms.h>
 
 #include "gtkutils.h"
 #include "utils.h"
 
+enum {
+       SUMCOL_NAME,
+       SUMCOL_TYPE,
+       N_SUMCOL_COLUMNS
+};
+
+#define TARGET_INFO_SUMCOL  (0xFEEDBABE)
+
+static const GtkTargetEntry row_targets[] = {
+       { "PREFS_SUM_COL_MODEL_ROW", GTK_TARGET_SAME_APP, TARGET_INFO_SUMCOL }
+};
+
+
 static struct _SummaryColumnDialog
 {
        GtkWidget *window;
 
-       GtkWidget *stock_clist;
-       GtkWidget *shown_clist;
+       GtkWidget *stock_list_view;
+       GtkWidget *shown_list_view;
 
        GtkWidget *add_btn;
        GtkWidget *remove_btn;
@@ -113,6 +125,36 @@ static gboolean prefs_summary_column_key_pressed(GtkWidget *widget,
                                                 GdkEventKey    *event,
                                                 gpointer        data);
 
+static GtkListStore *prefs_summary_column_create_store (void);
+
+static gint prefs_summary_column_insert_column (GtkListStore *store,
+                                                gint row,
+                                                const gchar *name,
+                                                SummaryColumnType type);
+                                              
+static SummaryColumnType prefs_summary_column_get_column       (GtkWidget *list, 
+                                                                gint row);
+
+static GtkWidget *prefs_summary_column_list_view_create        (const gchar *name);
+
+static void prefs_filtering_create_list_view_columns   (GtkWidget *list_view, 
+                                                        const gchar *name);
+
+static void drag_data_get      (GtkTreeView *tree_view, 
+                                GdkDragContext *context, 
+                                GtkSelectionData *data, 
+                                guint info, 
+                                guint time, 
+                                GtkTreeModel *model);
+                         
+static void drag_data_received (GtkTreeView *tree_view, 
+                                GdkDragContext *context,
+                                gint x, gint y, 
+                                GtkSelectionData *data,
+                                guint info, 
+                                guint time, 
+                                GtkTreeModel *model);
+
 void prefs_summary_column_open(void)
 {
        inc_lock();
@@ -149,8 +191,8 @@ static void prefs_summary_column_create(void)
        GtkWidget *hbox1;
        GtkWidget *clist_hbox;
        GtkWidget *scrolledwin;
-       GtkWidget *stock_clist;
-       GtkWidget *shown_clist;
+       GtkWidget *stock_list_view;
+       GtkWidget *shown_list_view;
 
        GtkWidget *btn_vbox;
        GtkWidget *btn_vbox1;
@@ -165,8 +207,6 @@ static void prefs_summary_column_create(void)
        GtkWidget *ok_btn;
        GtkWidget *cancel_btn;
 
-       gchar *title[1];
-
        debug_print("Creating summary column setting window...\n");
 
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
@@ -219,14 +259,11 @@ static void prefs_summary_column_create(void)
                                       GTK_POLICY_AUTOMATIC,
                                       GTK_POLICY_AUTOMATIC);
 
-       title[0] = _("Available items");
-       stock_clist = gtk_clist_new_with_titles(1, title);
-       gtk_widget_show(stock_clist);
-       gtk_container_add(GTK_CONTAINER(scrolledwin), stock_clist);
-       gtk_clist_set_selection_mode(GTK_CLIST(stock_clist),
-                                    GTK_SELECTION_BROWSE);
-       GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(stock_clist)->column[0].button,
-                              GTK_CAN_FOCUS);
+                                      
+       stock_list_view = prefs_summary_column_list_view_create
+                               (_("Available items"));
+       gtk_widget_show(stock_list_view);
+       gtk_container_add(GTK_CONTAINER(scrolledwin), stock_list_view);
 
        /* add/remove button */
        btn_vbox = gtk_vbox_new(FALSE, 0);
@@ -262,16 +299,10 @@ static void prefs_summary_column_create(void)
                                       GTK_POLICY_AUTOMATIC,
                                       GTK_POLICY_AUTOMATIC);
 
-       title[0] = _("Displayed items");
-       shown_clist = gtk_clist_new_with_titles(1, title);
-       gtk_widget_show(shown_clist);
-       gtk_container_add(GTK_CONTAINER(scrolledwin), shown_clist);
-       gtk_clist_set_selection_mode(GTK_CLIST(shown_clist),
-                                    GTK_SELECTION_BROWSE);
-       gtk_clist_set_reorderable(GTK_CLIST(shown_clist), TRUE);
-       gtk_clist_set_use_drag_icons(GTK_CLIST(shown_clist), FALSE);
-       GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(shown_clist)->column[0].button,
-                              GTK_CAN_FOCUS);
+       shown_list_view = prefs_summary_column_list_view_create
+                               (_("Displayed items"));
+       gtk_widget_show(shown_list_view);
+       gtk_container_add(GTK_CONTAINER(scrolledwin), shown_list_view);
 
        /* up/down button */
        btn_vbox = gtk_vbox_new(FALSE, 0);
@@ -321,15 +352,16 @@ static void prefs_summary_column_create(void)
        g_signal_connect(G_OBJECT(cancel_btn), "clicked",
                         G_CALLBACK(prefs_summary_column_cancel), NULL);
 
+
        summary_col.window      = window;
-       summary_col.stock_clist = stock_clist;
-       summary_col.shown_clist = shown_clist;
        summary_col.add_btn     = add_btn;
        summary_col.remove_btn  = remove_btn;
        summary_col.up_btn      = up_btn;
        summary_col.down_btn    = down_btn;
        summary_col.ok_btn      = ok_btn;
        summary_col.cancel_btn  = cancel_btn;
+       summary_col.stock_list_view = stock_list_view;
+       summary_col.shown_list_view = shown_list_view;
 }
 
 SummaryColumnState *prefs_summary_column_get_config(void)
@@ -371,14 +403,18 @@ void prefs_summary_column_set_config(SummaryColumnState *state)
 
 static void prefs_summary_column_set_dialog(SummaryColumnState *state)
 {
-       GtkCList *stock_clist = GTK_CLIST(summary_col.stock_clist);
-       GtkCList *shown_clist = GTK_CLIST(summary_col.shown_clist);
+       GtkListStore *stock_store, *shown_store;
        gint pos;
        SummaryColumnType type;
        gchar *name;
 
-       gtk_clist_clear(stock_clist);
-       gtk_clist_clear(shown_clist);
+       stock_store = GTK_LIST_STORE(gtk_tree_view_get_model
+                       (GTK_TREE_VIEW(summary_col.stock_list_view)));
+       shown_store = GTK_LIST_STORE(gtk_tree_view_get_model
+                       (GTK_TREE_VIEW(summary_col.shown_list_view)));
+
+       gtk_list_store_clear(stock_store);
+       gtk_list_store_clear(shown_store);
 
        if (!state)
                state = prefs_summary_column_get_config();
@@ -388,40 +424,45 @@ static void prefs_summary_column_set_dialog(SummaryColumnState *state)
                type = state[pos].type;
                name = gettext(col_name[type]);
 
-               if (state[pos].visible) {
-                       row = gtk_clist_append(shown_clist, (gchar **)&name);
-                       gtk_clist_set_row_data(shown_clist, row,
-                                              GINT_TO_POINTER(type));
-               } else {
-                       row = gtk_clist_append(stock_clist, (gchar **)&name);
-                       gtk_clist_set_row_data(stock_clist, row,
-                                              GINT_TO_POINTER(type));
-               }
+               if (state[pos].visible)
+                       prefs_summary_column_insert_column(shown_store,
+                                                          -1, name,
+                                                          type);
+               else
+                       prefs_summary_column_insert_column(stock_store,
+                                                           -1, name,
+                                                           type);
        }
 }
 
 static void prefs_summary_column_set_view(void)
 {
-       GtkCList *stock_clist = GTK_CLIST(summary_col.stock_clist);
-       GtkCList *shown_clist = GTK_CLIST(summary_col.shown_clist);
+       gint stock_n_rows, shown_n_rows;
        SummaryColumnState state[N_SUMMARY_COLS];
        SummaryColumnType type;
        gint row, pos = 0;
 
+       stock_n_rows = gtk_tree_model_iter_n_children
+               (gtk_tree_view_get_model(GTK_TREE_VIEW
+                       (summary_col.stock_list_view)), NULL);
+       shown_n_rows = gtk_tree_model_iter_n_children
+               (gtk_tree_view_get_model(GTK_TREE_VIEW
+                       (summary_col.shown_list_view)), NULL);
+
        g_return_if_fail
-               (stock_clist->rows + shown_clist->rows == N_SUMMARY_COLS);
+               (stock_n_rows + shown_n_rows == N_SUMMARY_COLS);
 
-       for (row = 0; row < stock_clist->rows; row++) {
-               type = GPOINTER_TO_INT
-                       (gtk_clist_get_row_data(stock_clist, row));
+       for (row = 0; row < stock_n_rows; row++) {
+               type = prefs_summary_column_get_column
+                       (summary_col.stock_list_view, row);
                state[row].type = type;
                state[row].visible = FALSE;
        }
 
        pos = row;
-       for (row = 0; row < shown_clist->rows; row++) {
-               type = GPOINTER_TO_INT
-                       (gtk_clist_get_row_data(shown_clist, row));
+       for (row = 0; row < shown_n_rows; row++) {
+               type = prefs_summary_column_get_column
+                       (summary_col.shown_list_view, row);
                state[pos + row].type = type;
                state[pos + row].visible = TRUE;
        }
@@ -432,80 +473,155 @@ static void prefs_summary_column_set_view(void)
 
 static void prefs_summary_column_add(void)
 {
-       GtkCList *stock_clist = GTK_CLIST(summary_col.stock_clist);
-       GtkCList *shown_clist = GTK_CLIST(summary_col.shown_clist);
-       gint row;
-       SummaryColumnType type;
+       GtkListStore *stock_store, *shown_store;
+       GtkTreeIter stock_sel, shown_sel, shown_add;
+       gboolean shown_sel_valid;
        gchar *name;
-
-       if (!stock_clist->selection) return;
-
-       row = GPOINTER_TO_INT(stock_clist->selection->data);
-       type = GPOINTER_TO_INT(gtk_clist_get_row_data(stock_clist, row));
-       gtk_clist_remove(stock_clist, row);
-       if (stock_clist->rows == row)
-               gtk_clist_select_row(stock_clist, row - 1, -1);
-
-       if (!shown_clist->selection)
-               row = 0;
-       else
-               row = GPOINTER_TO_INT(shown_clist->selection->data) + 1;
-
-       name = gettext(col_name[type]);
-       row = gtk_clist_insert(shown_clist, row, (gchar **)&name);
-       gtk_clist_set_row_data(shown_clist, row, GINT_TO_POINTER(type));
-       gtk_clist_select_row(shown_clist, row, -1);
+       SummaryColumnType type;
+       
+       stock_store = GTK_LIST_STORE(gtk_tree_view_get_model
+               (GTK_TREE_VIEW(summary_col.stock_list_view)));
+       shown_store = GTK_LIST_STORE(gtk_tree_view_get_model
+               (GTK_TREE_VIEW(summary_col.shown_list_view)));
+       
+       if (!gtk_tree_selection_get_selected
+               (gtk_tree_view_get_selection
+                       (GTK_TREE_VIEW(summary_col.stock_list_view)),
+                NULL,
+                &stock_sel))
+               return;
+
+       shown_sel_valid = gtk_tree_selection_get_selected
+               (gtk_tree_view_get_selection
+                       (GTK_TREE_VIEW(summary_col.shown_list_view)),
+                NULL,
+                &shown_sel);
+                        
+       gtk_tree_model_get(GTK_TREE_MODEL(stock_store), &stock_sel,
+                          SUMCOL_TYPE, &type,
+                          -1);
+                       
+       gtk_list_store_remove(stock_store, &stock_sel);
+
+       gtk_list_store_insert_after(shown_store, &shown_add, 
+                                   shown_sel_valid ? &shown_sel : NULL);
+
+       name = gettext(col_name[type]);                             
+                                   
+       gtk_list_store_set(shown_store, &shown_add,
+                          SUMCOL_NAME, name,
+                          SUMCOL_TYPE, type,
+                          -1);
+       
+       gtk_tree_selection_select_iter(gtk_tree_view_get_selection
+               (GTK_TREE_VIEW(summary_col.shown_list_view)),
+                &shown_add);
 }
 
 static void prefs_summary_column_remove(void)
 {
-       GtkCList *stock_clist = GTK_CLIST(summary_col.stock_clist);
-       GtkCList *shown_clist = GTK_CLIST(summary_col.shown_clist);
-       gint row;
-       SummaryColumnType type;
+       GtkListStore *stock_store, *shown_store;
+       GtkTreeIter shown_sel, stock_sel, stock_add;
+       gboolean stock_sel_valid;
        gchar *name;
-
-       if (!shown_clist->selection) return;
-
-       row = GPOINTER_TO_INT(shown_clist->selection->data);
-       type = GPOINTER_TO_INT(gtk_clist_get_row_data(shown_clist, row));
-       gtk_clist_remove(shown_clist, row);
-       if (shown_clist->rows == row)
-               gtk_clist_select_row(shown_clist, row - 1, -1);
-
-       if (!stock_clist->selection)
-               row = 0;
-       else
-               row = GPOINTER_TO_INT(stock_clist->selection->data) + 1;
-
-       name = gettext(col_name[type]);
-       row = gtk_clist_insert(stock_clist, row, (gchar **)&name);
-       gtk_clist_set_row_data(stock_clist, row, GINT_TO_POINTER(type));
-       gtk_clist_select_row(stock_clist, row, -1);
+       SummaryColumnType type;
+       
+       stock_store = GTK_LIST_STORE(gtk_tree_view_get_model
+               (GTK_TREE_VIEW(summary_col.stock_list_view)));
+       shown_store = GTK_LIST_STORE(gtk_tree_view_get_model
+               (GTK_TREE_VIEW(summary_col.shown_list_view)));
+               
+       if (!gtk_tree_selection_get_selected
+               (gtk_tree_view_get_selection
+                       (GTK_TREE_VIEW(summary_col.shown_list_view)),
+                NULL,
+                &shown_sel))
+               return;
+
+       stock_sel_valid = gtk_tree_selection_get_selected
+               (gtk_tree_view_get_selection
+                       (GTK_TREE_VIEW(summary_col.stock_list_view)),
+                NULL,
+                &stock_sel);
+       
+       gtk_tree_model_get(GTK_TREE_MODEL(shown_store), &shown_sel,
+                          SUMCOL_TYPE, &type,
+                          -1);
+                       
+       gtk_list_store_remove(shown_store, &shown_sel);
+
+       gtk_list_store_insert_after(stock_store, &stock_add, 
+                                   stock_sel_valid ? &stock_sel : NULL);
+
+       name = gettext(col_name[type]);                             
+                                   
+       gtk_list_store_set(stock_store, &stock_add,
+                          SUMCOL_NAME, name,
+                          SUMCOL_TYPE, type,
+                          -1);
+       
+       gtk_tree_selection_select_iter(gtk_tree_view_get_selection
+               (GTK_TREE_VIEW(summary_col.stock_list_view)),
+               &stock_add);
 }
 
 static void prefs_summary_column_up(void)
 {
-       GtkCList *clist = GTK_CLIST(summary_col.shown_clist);
-       gint row;
+       GtkTreePath *prev, *sel;
+       GtkTreeIter isel;
+       GtkListStore *shown_store;
+       GtkTreeIter iprev;
+       
+       if (!gtk_tree_selection_get_selected
+               (gtk_tree_view_get_selection
+                       (GTK_TREE_VIEW(summary_col.shown_list_view)),
+                NULL,
+                &isel))
+               return;
+
+       shown_store = GTK_LIST_STORE(gtk_tree_view_get_model
+               (GTK_TREE_VIEW(summary_col.shown_list_view)));
+
+       sel = gtk_tree_model_get_path(GTK_TREE_MODEL(shown_store), 
+                                     &isel);
+       if (!sel)
+               return;
+
+       prev = gtk_tree_path_copy(sel);         
+       if (!gtk_tree_path_prev(prev)) {
+               gtk_tree_path_free(prev);
+               gtk_tree_path_free(sel);
+               return;
+       }
 
-       if (!clist->selection) return;
+       gtk_tree_model_get_iter(GTK_TREE_MODEL(shown_store),
+                               &iprev, prev);
+       gtk_tree_path_free(sel);
+       gtk_tree_path_free(prev);
 
-       row = GPOINTER_TO_INT(clist->selection->data);
-       if (row > 0)
-               gtk_clist_row_move(clist, row, row - 1);
+       gtk_list_store_swap(shown_store, &iprev, &isel);
 }
 
 static void prefs_summary_column_down(void)
 {
-       GtkCList *clist = GTK_CLIST(summary_col.shown_clist);
-       gint row;
-
-       if (!clist->selection) return;
-
-       row = GPOINTER_TO_INT(clist->selection->data);
-       if (row >= 0 && row < clist->rows - 1)
-               gtk_clist_row_move(clist, row, row + 1);
+       GtkListStore *shown_store;
+       GtkTreeIter next, sel;
+       
+       if (!gtk_tree_selection_get_selected
+               (gtk_tree_view_get_selection
+                       (GTK_TREE_VIEW(summary_col.shown_list_view)),
+                NULL,
+                &sel))
+               return;
+
+       shown_store = GTK_LIST_STORE(gtk_tree_view_get_model
+               (GTK_TREE_VIEW(summary_col.shown_list_view)));
+
+       next = sel;
+       if (!gtk_tree_model_iter_next(GTK_TREE_MODEL(shown_store), &next)) 
+               return;
+
+       gtk_list_store_swap(shown_store, &next, &sel);
 }
 
 static void prefs_summary_column_set_to_default(void)
@@ -542,3 +658,242 @@ static gboolean prefs_summary_column_key_pressed(GtkWidget *widget,
                summary_col.finished = TRUE;
        return FALSE;
 }
+
+static GtkListStore *prefs_summary_column_create_store(void)
+{
+       return gtk_list_store_new(N_SUMCOL_COLUMNS,
+                                 G_TYPE_STRING,
+                                 G_TYPE_INT,
+                                 -1);
+}
+
+static gint prefs_summary_column_insert_column(GtkListStore *store,
+                                              gint row,
+                                              const gchar *name,
+                                              SummaryColumnType type)
+{
+       GtkTreeIter iter;
+
+       if (row >= 0) {
+               if (!gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store),
+                                                  &iter, NULL, row))
+                       row = -1;                                                  
+       }
+       if (row < 0) {
+               /* add new */
+               gtk_list_store_append(store, &iter);
+               gtk_list_store_set(store, &iter,
+                                  SUMCOL_NAME, name,
+                                  SUMCOL_TYPE, type,
+                                  -1);
+               return -1 + gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store),
+                                                          NULL);
+       } else {
+               /* change existing */
+               gtk_list_store_set(store, &iter, 
+                                  SUMCOL_NAME, name,
+                                  SUMCOL_TYPE, type,
+                                  -1);
+       }
+}
+
+/*!
+ *\brief       Return the columnn type for a row
+ */
+static SummaryColumnType prefs_summary_column_get_column(GtkWidget *list, gint row)
+{      
+       GtkTreeView *list_view = GTK_TREE_VIEW(list);
+       GtkTreeModel *model = gtk_tree_view_get_model(list_view);
+       GtkTreeIter iter;
+       SummaryColumnType result;
+
+       if (!gtk_tree_model_iter_nth_child(model, &iter, NULL, row))
+               return -1;
+       
+       gtk_tree_model_get(model, &iter, 
+                          SUMCOL_TYPE, &result,
+                          -1);
+       
+       return result;
+}
+
+static GtkWidget *prefs_summary_column_list_view_create(const gchar *name)
+{
+       GtkWidget *list_view;
+       GtkTreeSelection *selector;
+       GtkTreeModel *model;
+
+       model = GTK_TREE_MODEL(prefs_summary_column_create_store());
+       list_view = gtk_tree_view_new_with_model(model);
+       g_object_unref(G_OBJECT(model));
+       
+       gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(list_view), TRUE);
+       
+       selector = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view));
+       gtk_tree_selection_set_mode(selector, GTK_SELECTION_BROWSE);
+
+       prefs_filtering_create_list_view_columns(GTK_WIDGET(list_view), name);
+
+       gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(list_view),
+                                              GDK_BUTTON1_MASK,
+                                              row_targets,
+                                              G_N_ELEMENTS(row_targets), 
+                                              GDK_ACTION_MOVE);
+                                           
+       gtk_tree_view_enable_model_drag_dest(GTK_TREE_VIEW(list_view), 
+                                            row_targets, 
+                                            G_N_ELEMENTS(row_targets), 
+                                            GDK_ACTION_MOVE);
+               
+       g_signal_connect(G_OBJECT(list_view), "drag_data_get",
+                        G_CALLBACK(drag_data_get),
+                        model);
+
+       g_signal_connect(G_OBJECT(list_view), "drag_data_received",
+                        G_CALLBACK(drag_data_received),
+                        model);
+
+       return list_view;
+}
+
+static void prefs_filtering_create_list_view_columns(GtkWidget *list_view, 
+                                                    const gchar *name)
+{
+       GtkTreeViewColumn *column;
+       GtkCellRenderer *renderer;
+
+       renderer = gtk_cell_renderer_text_new();
+       column = gtk_tree_view_column_new_with_attributes
+               (name, renderer, "text", SUMCOL_NAME, NULL);
+       gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);          
+}
+
+static void drag_data_get(GtkTreeView *tree_view, GdkDragContext *context, 
+                         GtkSelectionData *data, guint info, 
+                         guint time, GtkTreeModel *model)
+{
+       GtkWidget *source;
+       GtkTreeIter iter;
+       SummaryColumnType type;
+       GtkTreeModel *source_model;
+
+       if (info != TARGET_INFO_SUMCOL) 
+               return;
+
+       if (!gtk_tree_selection_get_selected
+                       (gtk_tree_view_get_selection(tree_view),
+                        &source_model, &iter)) 
+               return;                  
+       
+       gtk_tree_model_get(source_model, &iter, 
+                          SUMCOL_TYPE, &type,
+                          -1);
+
+       /* send the type */
+       gtk_selection_data_set(data, data->target, 8, (gchar *) &type, sizeof type);
+}
+
+static void drag_data_received(GtkTreeView *tree_view, GdkDragContext *context,
+                              gint x, gint y, GtkSelectionData *data,
+                              guint info, guint time, GtkTreeModel *model)
+{
+       GtkWidget *source;
+       GtkTreePath *dst = NULL, *sel = NULL;
+       GtkTreeIter isel, idst;
+       GtkTreeViewDropPosition pos;
+       gboolean before;
+       SummaryColumnType type;
+       GtkTreeModel *sel_model;
+       gchar *name;
+       
+       source = gtk_drag_get_source_widget(context);
+       
+       if (source == GTK_WIDGET(tree_view)) {
+       
+               /*
+                * Same widget: re-order
+                */
+                
+               gtk_tree_selection_get_selected(gtk_tree_view_get_selection(tree_view),
+                                          NULL, &isel);
+               sel = gtk_tree_model_get_path(model, &isel);
+               gtk_tree_view_get_dest_row_at_pos(tree_view, x, y,
+                                                 &dst, &pos);
+
+               /* NOTE: dst is invalid if selection beyond last row, in that
+                * case move beyond last one (XXX_move_before(..., NULL)) */                                              
+
+               if (dst)                                                  
+                       gtk_tree_model_get_iter(model, &idst, dst);
+               else 
+                       gtk_list_store_move_before(GTK_LIST_STORE(model),
+                                                  &isel,
+                                                  NULL);
+
+               /* we do not drag if no valid dst and sel, and when
+                * dst and sel are the same (moving after or before
+                * itself doesn't change order...) */
+               if ((dst && sel) && gtk_tree_path_compare(sel, dst) != 0) {
+                       if (pos == GTK_TREE_VIEW_DROP_BEFORE
+                       ||  pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)
+                               gtk_list_store_move_before(GTK_LIST_STORE(model),
+                                                          &isel,
+                                                          &idst);
+                       else
+                               gtk_list_store_move_after(GTK_LIST_STORE(model),
+                                                         &isel,
+                                                         &idst);
+                       
+               } 
+               gtk_tree_path_free(dst);                                          
+               gtk_tree_path_free(sel);
+               gtk_drag_finish(context, TRUE, FALSE, time);
+               
+       } else if (source == summary_col.stock_list_view 
+       ||         source == summary_col.shown_list_view) {
+       
+               /*
+                * Other widget: change and update
+                */
+
+               
+               /* get source information and remove */
+               gtk_tree_selection_get_selected(gtk_tree_view_get_selection(
+                                               GTK_TREE_VIEW(source)),
+                                               &sel_model, &isel);
+               type = *((gint *) data->data);
+               name = gettext(col_name[type]);
+               gtk_list_store_remove(GTK_LIST_STORE(sel_model), &isel);
+
+               /* get insertion position */
+               gtk_tree_view_get_dest_row_at_pos(tree_view, x, y, &dst, &pos);
+
+               /* NOTE: dst is invalid if insertion point beyond last row, 
+                * just append to list in that case (XXX_store_append()) */
+
+               if (dst) {
+                       gtk_tree_model_get_iter(model, &idst, dst);
+
+                       if (pos == GTK_TREE_VIEW_DROP_BEFORE
+                       ||  pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)
+                               gtk_list_store_insert_before(GTK_LIST_STORE(model),
+                                                            &isel,
+                                                            &idst);
+                       else
+                               gtk_list_store_insert_after(GTK_LIST_STORE(model),
+                                                           &isel,
+                                                           &idst);
+               } else
+                       gtk_list_store_append(GTK_LIST_STORE(model),
+                                             &isel);
+               
+               gtk_list_store_set(GTK_LIST_STORE(model), &isel,
+                                  SUMCOL_NAME, name,
+                                  SUMCOL_TYPE, type, -1);
+               gtk_tree_path_free(dst);
+               gtk_drag_finish(context, TRUE, FALSE, time);
+       }
+
+       /* XXXX: should we call gtk_drag_finish() for other code paths? */
+}
+