talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

prefs_folder_column.c (27064B)


      1 /*
      2  * Claws Mail -- a GTK based, lightweight, and fast e-mail client
      3  * Copyright (C) 1999-2024 the Claws Mail team and Hiroyuki Yamamoto
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License as published by
      7  * the Free Software Foundation; either version 3 of the License, or
      8  * (at your option) any later version.
      9  *
     10  * This program is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  * GNU General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU General Public License
     16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
     17  */
     18 
     19 #include "defs.h"
     20 
     21 #include <glib.h>
     22 #include <glib/gi18n.h>
     23 #include <gtk/gtk.h>
     24 #include <gdk/gdkkeysyms.h>
     25 
     26 #include "prefs_gtk.h"
     27 #include "prefs_common.h"
     28 #include "prefs_folder_column.h"
     29 #include "manage_window.h"
     30 #include "folderview.h"
     31 #include "mainwindow.h"
     32 #include "inc.h"
     33 #include "gtkutils.h"
     34 #include "utils.h"
     35 
     36 static void prefs_folder_column_set_config(FolderColumnState *state);
     37 
     38 enum {
     39 	SUMCOL_NAME,
     40 	SUMCOL_TYPE,
     41 	N_SUMCOL_COLUMNS
     42 };
     43 
     44 #define TARGET_INFO_SUMCOL  (0xFEEDBABE)
     45 
     46 static const GtkTargetEntry row_targets[] = {
     47 	{ "PREFS_SUM_COL_MODEL_ROW", GTK_TARGET_SAME_APP, TARGET_INFO_SUMCOL }
     48 };
     49 
     50 
     51 static struct _FolderColumnDialog
     52 {
     53 	GtkWidget *window;
     54 
     55 	GtkWidget *stock_list_view;
     56 	GtkWidget *shown_list_view;
     57 
     58 	GtkWidget *add_btn;
     59 	GtkWidget *remove_btn;
     60 	GtkWidget *up_btn;
     61 	GtkWidget *down_btn;
     62 
     63 	GtkWidget *default_btn;
     64 
     65 	GtkWidget *ok_btn;
     66 	GtkWidget *cancel_btn;
     67 
     68 	gboolean finished;
     69 } folder_col;
     70 
     71 static const gchar *const col_name[N_FOLDER_COLS] = {
     72 	N_("Folder"),		/* F_COL_FOLDER  */
     73 	N_("New"),		/* F_COL_NEW     */
     74 	N_("Unread"),		/* F_COL_UNREAD  */
     75 	N_("Total"),		/* F_COL_TOTAL   */
     76 };
     77 
     78 static FolderColumnState default_state[N_FOLDER_COLS] = {
     79 	{ F_COL_FOLDER   , TRUE  },
     80 	{ F_COL_NEW      , TRUE  },
     81 	{ F_COL_UNREAD   , TRUE  },
     82 	{ F_COL_TOTAL    , TRUE  },
     83 };
     84 
     85 static void prefs_folder_column_create	(void);
     86 
     87 static void prefs_folder_column_set_dialog	(FolderColumnState *state);
     88 static void prefs_folder_column_set_view	(void);
     89 
     90 /* callback functions */
     91 static void prefs_folder_column_add	(void);
     92 static void prefs_folder_column_remove	(void);
     93 
     94 static void prefs_folder_column_up	(void);
     95 static void prefs_folder_column_down	(void);
     96 
     97 static void prefs_folder_column_set_to_default	(void);
     98 
     99 static void prefs_folder_column_ok	(void);
    100 static void prefs_folder_column_cancel	(void);
    101 
    102 static gint prefs_folder_column_delete_event	(GtkWidget	*widget,
    103 						 GdkEventAny	*event,
    104 						 gpointer	 data);
    105 
    106 static GtkListStore *prefs_folder_column_create_store	(void);
    107 
    108 static void prefs_folder_column_insert_column	(GtkListStore *store,
    109 						 gint row,
    110 						 const gchar *name,
    111 						 FolderColumnType type);
    112 
    113 static FolderColumnType prefs_folder_column_get_column	(GtkWidget *list,
    114 								 gint row);
    115 
    116 static GtkWidget *prefs_folder_column_list_view_create	(const gchar *name);
    117 
    118 static void prefs_filtering_create_list_view_columns	(GtkWidget *list_view,
    119 							 const gchar *name);
    120 
    121 static void drag_data_get	(GtkTreeView *tree_view,
    122 				 GdkDragContext *context,
    123 				 GtkSelectionData *data,
    124 				 guint info,
    125 				 guint time,
    126 				 GtkTreeModel *model);
    127 
    128 static void drag_data_received	(GtkTreeView *tree_view,
    129 				 GdkDragContext *context,
    130 				 gint x, gint y,
    131 				 GtkSelectionData *data,
    132 				 guint info,
    133 				 guint time,
    134 				 GtkTreeModel *model);
    135 
    136 static void prefs_folder_column_shown_set_btn_sensitivity(void);
    137 static void prefs_folder_column_shown_set_active(const gboolean active);
    138 static void prefs_folder_column_stock_set_active(const gboolean active);
    139 static void prefs_folder_column_shown_sel_changed(void);
    140 static void prefs_folder_column_stock_sel_changed(void);
    141 
    142 
    143 void prefs_folder_column_open(void)
    144 {
    145 	inc_lock();
    146 
    147 	if (!folder_col.window)
    148 		prefs_folder_column_create();
    149 
    150 	manage_window_set_transient(GTK_WINDOW(folder_col.window));
    151 	gtk_widget_grab_focus(folder_col.ok_btn);
    152 
    153 	prefs_folder_column_set_dialog(NULL);
    154 
    155 	gtk_widget_show(folder_col.window);
    156 	gtk_window_set_modal(GTK_WINDOW(folder_col.window), TRUE);
    157 
    158 	folder_col.finished = FALSE;
    159 	while (folder_col.finished == FALSE)
    160 		gtk_main_iteration();
    161 
    162 	gtk_widget_hide(folder_col.window);
    163 	gtk_window_set_modal(GTK_WINDOW(folder_col.window), FALSE);
    164 
    165 	inc_unlock();
    166 }
    167 
    168 static void prefs_folder_column_create(void)
    169 {
    170 	GtkWidget *window;
    171 	GtkWidget *vbox;
    172 
    173 	GtkWidget *label_hbox;
    174 	GtkWidget *label;
    175 
    176 	GtkWidget *vbox1;
    177 
    178 	GtkWidget *hbox1;
    179 	GtkWidget *clist_hbox;
    180 	GtkWidget *scrolledwin;
    181 	GtkWidget *stock_list_view;
    182 	GtkWidget *shown_list_view;
    183 
    184 	GtkWidget *btn_vbox;
    185 	GtkWidget *add_btn;
    186 	GtkWidget *remove_btn;
    187 	GtkWidget *up_btn;
    188 	GtkWidget *down_btn;
    189 
    190 	GtkWidget *btn_hbox;
    191 	GtkWidget *default_btn;
    192 	GtkWidget *confirm_area;
    193 	GtkWidget *ok_btn;
    194 	GtkWidget *cancel_btn;
    195 
    196 	debug_print("Creating folder column setting window...\n");
    197 
    198 	window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "prefs_folder_column");
    199 	gtk_container_set_border_width(GTK_CONTAINER(window), 8);
    200 	gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    201 	gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
    202 	gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
    203 	gtk_window_set_title(GTK_WINDOW(window),
    204 			     _("Folder list columns configuration"));
    205 	g_signal_connect(G_OBJECT(window), "delete_event",
    206 			 G_CALLBACK(prefs_folder_column_delete_event),
    207 			 NULL);
    208 
    209 	vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
    210 	gtk_widget_show(vbox);
    211 	gtk_container_add(GTK_CONTAINER(window), vbox);
    212 
    213 	label_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
    214 	gtk_widget_show(label_hbox);
    215 	gtk_box_pack_start(GTK_BOX(vbox), label_hbox, FALSE, FALSE, 4);
    216 
    217 	label = gtk_label_new
    218 		(_("Select columns to be displayed in the folder list. You can modify\n"
    219 		   "the order by using the Up / Down buttons or by dragging the items."));
    220 	gtk_widget_show(label);
    221 	gtk_box_pack_start(GTK_BOX(label_hbox), label, FALSE, FALSE, 4);
    222 	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
    223 
    224 	vbox1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, VSPACING);
    225 	gtk_widget_show(vbox1);
    226 	gtk_box_pack_start(GTK_BOX(vbox), vbox1, TRUE, TRUE, 0);
    227 	gtk_container_set_border_width(GTK_CONTAINER(vbox1), 2);
    228 
    229 	hbox1 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
    230 	gtk_widget_show(hbox1);
    231 	gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, TRUE, 0);
    232 
    233 	clist_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
    234 	gtk_widget_show(clist_hbox);
    235 	gtk_box_pack_start(GTK_BOX(hbox1), clist_hbox, TRUE, TRUE, 0);
    236 
    237 	scrolledwin = gtk_scrolled_window_new(NULL, NULL);
    238 	gtk_widget_set_size_request(scrolledwin, 180, 210);
    239 	gtk_widget_show(scrolledwin);
    240 	gtk_box_pack_start(GTK_BOX(clist_hbox), scrolledwin, TRUE, TRUE, 0);
    241 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
    242 				       GTK_POLICY_AUTOMATIC,
    243 				       GTK_POLICY_AUTOMATIC);
    244 	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin),
    245 					   GTK_SHADOW_IN);
    246 
    247 	stock_list_view = prefs_folder_column_list_view_create
    248 				(_("Hidden columns"));
    249 	g_signal_connect(G_OBJECT(stock_list_view), "cursor-changed",
    250 			   G_CALLBACK(prefs_folder_column_stock_sel_changed),
    251 			   NULL);
    252 	gtk_widget_show(stock_list_view);
    253 	gtk_container_add(GTK_CONTAINER(scrolledwin), stock_list_view);
    254 
    255 	/* add/remove button */
    256 	btn_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8);
    257 	gtk_widget_show(btn_vbox);
    258 	gtk_box_pack_start(GTK_BOX(hbox1), btn_vbox, FALSE, FALSE, 0);
    259 
    260 	add_btn = gtkut_stock_button("list-add", _("_Add"));
    261 	gtk_widget_show(add_btn);
    262 	gtk_box_pack_start(GTK_BOX(btn_vbox), add_btn, FALSE, TRUE, 0);
    263 
    264 	g_signal_connect(G_OBJECT(add_btn), "clicked",
    265 			 G_CALLBACK(prefs_folder_column_add), NULL);
    266 
    267 	remove_btn = gtkut_stock_button("list-remove", _("_Remove"));
    268 	gtk_widget_show(remove_btn);
    269 	gtk_box_pack_start(GTK_BOX(btn_vbox), remove_btn, FALSE, TRUE, 0);
    270 
    271 	g_signal_connect(G_OBJECT(remove_btn), "clicked",
    272 			 G_CALLBACK(prefs_folder_column_remove), NULL);
    273 
    274 	clist_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
    275 	gtk_widget_show(clist_hbox);
    276 	gtk_box_pack_start(GTK_BOX(hbox1), clist_hbox, TRUE, TRUE, 0);
    277 
    278 	scrolledwin = gtk_scrolled_window_new(NULL, NULL);
    279 	gtk_widget_set_size_request(scrolledwin, 180, 210);
    280 	gtk_widget_show(scrolledwin);
    281 	gtk_box_pack_start(GTK_BOX(clist_hbox), scrolledwin, TRUE, TRUE, 0);
    282 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
    283 				       GTK_POLICY_AUTOMATIC,
    284 				       GTK_POLICY_AUTOMATIC);
    285 	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin),
    286 					   GTK_SHADOW_IN);
    287 
    288 	shown_list_view = prefs_folder_column_list_view_create
    289 				(_("Displayed columns"));
    290 	g_signal_connect(G_OBJECT(shown_list_view), "cursor-changed",
    291 			   G_CALLBACK(prefs_folder_column_shown_sel_changed),
    292 			   NULL);
    293 	gtk_widget_show(shown_list_view);
    294 	gtk_container_add(GTK_CONTAINER(scrolledwin), shown_list_view);
    295 
    296 	/* up/down button */
    297 	btn_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8);
    298 	gtk_widget_show(btn_vbox);
    299 	gtk_box_pack_start(GTK_BOX(hbox1), btn_vbox, FALSE, FALSE, 0);
    300 
    301 	up_btn = gtkut_stock_button("go-up", _("_Up"));
    302 	gtk_widget_show(up_btn);
    303 	gtk_box_pack_start(GTK_BOX(btn_vbox), up_btn, FALSE, TRUE, 0);
    304 
    305 	down_btn = gtkut_stock_button("go-down", _("_Down"));
    306 	gtk_widget_show(down_btn);
    307 	gtk_box_pack_start(GTK_BOX(btn_vbox), down_btn, FALSE, TRUE, 0);
    308 
    309 	g_signal_connect(G_OBJECT(up_btn), "clicked",
    310 			 G_CALLBACK(prefs_folder_column_up), NULL);
    311 	g_signal_connect(G_OBJECT(down_btn), "clicked",
    312 			 G_CALLBACK(prefs_folder_column_down), NULL);
    313 
    314 	btn_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
    315 	gtk_widget_show(btn_hbox);
    316 	gtk_box_pack_end(GTK_BOX(vbox), btn_hbox, FALSE, FALSE, 0);
    317 
    318 	btn_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
    319 	gtk_widget_show(btn_vbox);
    320 	gtk_box_pack_start(GTK_BOX(btn_hbox), btn_vbox, FALSE, FALSE, 0);
    321 
    322 	default_btn = gtk_button_new_with_label(_(" Use default "));
    323 	gtk_widget_show(default_btn);
    324 	gtk_box_pack_start(GTK_BOX(btn_vbox), default_btn, TRUE, FALSE, 0);
    325 	g_signal_connect(G_OBJECT(default_btn), "clicked",
    326 			 G_CALLBACK(prefs_folder_column_set_to_default),
    327 			 NULL);
    328 
    329 	gtkut_stock_button_set_create(&confirm_area,
    330 				      &cancel_btn, NULL, _("_Cancel"),
    331 				      &ok_btn, NULL, _("_OK"),
    332 				      NULL, NULL, NULL);
    333 	gtk_widget_show(confirm_area);
    334 	gtk_box_pack_end(GTK_BOX(btn_hbox), confirm_area, FALSE, FALSE, 0);
    335 	gtk_widget_grab_default(ok_btn);
    336 
    337 	g_signal_connect(G_OBJECT(ok_btn), "clicked",
    338 			 G_CALLBACK(prefs_folder_column_ok), NULL);
    339 	g_signal_connect(G_OBJECT(cancel_btn), "clicked",
    340 			 G_CALLBACK(prefs_folder_column_cancel), NULL);
    341 
    342 	folder_col.window      = window;
    343 	folder_col.add_btn     = add_btn;
    344 	folder_col.remove_btn  = remove_btn;
    345 	folder_col.up_btn      = up_btn;
    346 	folder_col.down_btn    = down_btn;
    347 	folder_col.ok_btn      = ok_btn;
    348 	folder_col.cancel_btn  = cancel_btn;
    349 	folder_col.stock_list_view = stock_list_view;
    350 	folder_col.shown_list_view = shown_list_view;
    351 
    352 	prefs_folder_column_shown_set_active(FALSE);
    353 	prefs_folder_column_stock_set_active(FALSE);
    354 }
    355 
    356 FolderColumnState *prefs_folder_column_get_config(void)
    357 {
    358 	static FolderColumnState state[N_FOLDER_COLS];
    359 	FolderColumnType type;
    360 	gint pos;
    361 
    362 	for (pos = 0; pos < N_FOLDER_COLS; pos++)
    363 		state[pos].type = -1;
    364 
    365 	for (type = 0; type < N_FOLDER_COLS; type++) {
    366 		pos = prefs_common.folder_col_pos[type];
    367 		if (pos < 0 || pos >= N_FOLDER_COLS ||
    368 		    state[pos].type != -1) {
    369 			g_warning("wrong column position");
    370 			prefs_folder_column_set_config(default_state);
    371 			return default_state;
    372 		}
    373 
    374 		state[pos].type = type;
    375 		state[pos].visible = prefs_common.folder_col_visible[type];
    376 	}
    377 
    378 	return state;
    379 }
    380 
    381 static void prefs_folder_column_set_config(FolderColumnState *state)
    382 {
    383 	FolderColumnType type;
    384 	gint pos;
    385 
    386 	for (pos = 0; pos < N_FOLDER_COLS; pos++) {
    387 		type = state[pos].type;
    388 		prefs_common.folder_col_visible[type] = state[pos].visible;
    389 		prefs_common.folder_col_pos[type] = pos;
    390 	}
    391 }
    392 
    393 static void prefs_folder_column_set_dialog(FolderColumnState *state)
    394 {
    395 	GtkListStore *stock_store, *shown_store;
    396 	gint pos;
    397 	FolderColumnType type;
    398 	gchar *name;
    399 
    400 	stock_store = GTK_LIST_STORE(gtk_tree_view_get_model
    401 			(GTK_TREE_VIEW(folder_col.stock_list_view)));
    402 	shown_store = GTK_LIST_STORE(gtk_tree_view_get_model
    403 			(GTK_TREE_VIEW(folder_col.shown_list_view)));
    404 
    405 	gtk_list_store_clear(stock_store);
    406 	gtk_list_store_clear(shown_store);
    407 
    408 	if (!state)
    409 		state = prefs_folder_column_get_config();
    410 
    411 	for (pos = 0; pos < N_FOLDER_COLS; pos++) {
    412 		type = state[pos].type;
    413 		name = col_name[type];
    414 
    415 		if (state[pos].visible)
    416 			prefs_folder_column_insert_column(shown_store,
    417 							   -1, name,
    418 							   type);
    419 		else
    420 			prefs_folder_column_insert_column(stock_store,
    421 							    -1, name,
    422 							    type);
    423 	}
    424 }
    425 
    426 static void prefs_folder_column_set_view(void)
    427 {
    428 	gint stock_n_rows, shown_n_rows;
    429 	FolderColumnState state[N_FOLDER_COLS];
    430 	FolderColumnType type;
    431 	gint row, pos = 0;
    432 
    433 	stock_n_rows = gtk_tree_model_iter_n_children
    434 		(gtk_tree_view_get_model(GTK_TREE_VIEW
    435 			(folder_col.stock_list_view)), NULL);
    436 	shown_n_rows = gtk_tree_model_iter_n_children
    437 		(gtk_tree_view_get_model(GTK_TREE_VIEW
    438 			(folder_col.shown_list_view)), NULL);
    439 
    440 	cm_return_if_fail
    441 		(stock_n_rows + shown_n_rows == N_FOLDER_COLS);
    442 
    443 	for (row = 0; row < stock_n_rows; row++) {
    444 		type = prefs_folder_column_get_column
    445 			(folder_col.stock_list_view, row);
    446 		state[row].type = type;
    447 		state[row].visible = FALSE;
    448 	}
    449 
    450 	pos = row;
    451 	for (row = 0; row < shown_n_rows; row++) {
    452 		type = prefs_folder_column_get_column
    453 			(folder_col.shown_list_view, row);
    454 		state[pos + row].type = type;
    455 		state[pos + row].visible = TRUE;
    456 	}
    457 
    458 	prefs_folder_column_set_config(state);
    459 	main_window_set_folder_column();
    460 }
    461 
    462 static void prefs_folder_column_add(void)
    463 {
    464 	GtkListStore *stock_store, *shown_store;
    465 	GtkTreeIter stock_sel, shown_sel, shown_add;
    466 	gboolean shown_sel_valid;
    467 	gchar *name;
    468 	FolderColumnType type;
    469 
    470 	stock_store = GTK_LIST_STORE(gtk_tree_view_get_model
    471 		(GTK_TREE_VIEW(folder_col.stock_list_view)));
    472 	shown_store = GTK_LIST_STORE(gtk_tree_view_get_model
    473 		(GTK_TREE_VIEW(folder_col.shown_list_view)));
    474 
    475 	if (!gtk_tree_selection_get_selected
    476 		(gtk_tree_view_get_selection
    477 			(GTK_TREE_VIEW(folder_col.stock_list_view)),
    478 		 NULL,
    479 		 &stock_sel))
    480 		return;
    481 
    482 	shown_sel_valid = gtk_tree_selection_get_selected
    483 		(gtk_tree_view_get_selection
    484 			(GTK_TREE_VIEW(folder_col.shown_list_view)),
    485 		 NULL,
    486 		 &shown_sel);
    487 
    488 	gtk_tree_model_get(GTK_TREE_MODEL(stock_store), &stock_sel,
    489 			   SUMCOL_TYPE, &type,
    490 			   -1);
    491 
    492 	gtk_list_store_remove(stock_store, &stock_sel);
    493 
    494 	gtk_list_store_insert_after(shown_store, &shown_add,
    495 				    shown_sel_valid ? &shown_sel : NULL);
    496 
    497 	gtk_list_store_set(shown_store, &shown_add,
    498 			   SUMCOL_NAME, col_name[type],
    499 			   SUMCOL_TYPE, type,
    500 			   -1);
    501 
    502 	gtk_tree_selection_select_iter(gtk_tree_view_get_selection
    503 		(GTK_TREE_VIEW(folder_col.shown_list_view)),
    504 		 &shown_add);
    505 	prefs_folder_column_shown_set_active(TRUE);
    506 	prefs_folder_column_stock_set_active(FALSE);
    507 }
    508 
    509 static void prefs_folder_column_remove(void)
    510 {
    511 	GtkListStore *stock_store, *shown_store;
    512 	GtkTreeIter shown_sel, stock_sel, stock_add;
    513 	gboolean stock_sel_valid;
    514 	FolderColumnType type;
    515 
    516 	stock_store = GTK_LIST_STORE(gtk_tree_view_get_model
    517 		(GTK_TREE_VIEW(folder_col.stock_list_view)));
    518 	shown_store = GTK_LIST_STORE(gtk_tree_view_get_model
    519 		(GTK_TREE_VIEW(folder_col.shown_list_view)));
    520 
    521 	if (!gtk_tree_selection_get_selected
    522 		(gtk_tree_view_get_selection
    523 			(GTK_TREE_VIEW(folder_col.shown_list_view)),
    524 		 NULL,
    525 		 &shown_sel))
    526 		return;
    527 
    528 	stock_sel_valid = gtk_tree_selection_get_selected
    529 		(gtk_tree_view_get_selection
    530 			(GTK_TREE_VIEW(folder_col.stock_list_view)),
    531 		 NULL,
    532 		 &stock_sel);
    533 
    534 	gtk_tree_model_get(GTK_TREE_MODEL(shown_store), &shown_sel,
    535 			   SUMCOL_TYPE, &type,
    536 			   -1);
    537 
    538 	gtk_list_store_remove(shown_store, &shown_sel);
    539 
    540 	gtk_list_store_insert_after(stock_store, &stock_add,
    541 				    stock_sel_valid ? &stock_sel : NULL);
    542 
    543 	gtk_list_store_set(stock_store, &stock_add,
    544 			   SUMCOL_NAME, col_name[type],
    545 			   SUMCOL_TYPE, type,
    546 			   -1);
    547 
    548 	gtk_tree_selection_select_iter(gtk_tree_view_get_selection
    549 		(GTK_TREE_VIEW(folder_col.stock_list_view)),
    550 		&stock_add);
    551 	prefs_folder_column_shown_set_active(FALSE);
    552 	prefs_folder_column_stock_set_active(TRUE);
    553 }
    554 
    555 static void prefs_folder_column_up(void)
    556 {
    557 	GtkTreePath *prev, *sel;
    558 	GtkTreeIter isel;
    559 	GtkListStore *shown_store;
    560 	GtkTreeIter iprev;
    561 
    562 	if (!gtk_tree_selection_get_selected
    563 		(gtk_tree_view_get_selection
    564 			(GTK_TREE_VIEW(folder_col.shown_list_view)),
    565 		 NULL,
    566 		 &isel))
    567 		return;
    568 
    569 	shown_store = GTK_LIST_STORE(gtk_tree_view_get_model
    570 		(GTK_TREE_VIEW(folder_col.shown_list_view)));
    571 
    572 	sel = gtk_tree_model_get_path(GTK_TREE_MODEL(shown_store),
    573 				      &isel);
    574 	if (!sel)
    575 		return;
    576 
    577 	prev = gtk_tree_path_copy(sel);
    578 	if (!gtk_tree_path_prev(prev)) {
    579 		gtk_tree_path_free(prev);
    580 		gtk_tree_path_free(sel);
    581 		return;
    582 	}
    583 
    584 	gtk_tree_model_get_iter(GTK_TREE_MODEL(shown_store),
    585 				&iprev, prev);
    586 	gtk_tree_path_free(sel);
    587 	gtk_tree_path_free(prev);
    588 
    589 	gtk_list_store_swap(shown_store, &iprev, &isel);
    590 	prefs_folder_column_shown_set_btn_sensitivity();
    591 }
    592 
    593 static void prefs_folder_column_down(void)
    594 {
    595 	GtkListStore *shown_store;
    596 	GtkTreeIter next, sel;
    597 
    598 	if (!gtk_tree_selection_get_selected
    599 		(gtk_tree_view_get_selection
    600 			(GTK_TREE_VIEW(folder_col.shown_list_view)),
    601 		 NULL,
    602 		 &sel))
    603 		return;
    604 
    605 	shown_store = GTK_LIST_STORE(gtk_tree_view_get_model
    606 		(GTK_TREE_VIEW(folder_col.shown_list_view)));
    607 
    608 	next = sel;
    609 	if (!gtk_tree_model_iter_next(GTK_TREE_MODEL(shown_store), &next))
    610 		return;
    611 
    612 	gtk_list_store_swap(shown_store, &next, &sel);
    613 	prefs_folder_column_shown_set_btn_sensitivity();
    614 }
    615 
    616 static void prefs_folder_column_set_to_default(void)
    617 {
    618 	prefs_folder_column_set_dialog(default_state);
    619 	prefs_folder_column_shown_set_active(FALSE);
    620 	prefs_folder_column_stock_set_active(FALSE);
    621 }
    622 
    623 static void prefs_folder_column_ok(void)
    624 {
    625 	if (!folder_col.finished) {
    626 		folder_col.finished = TRUE;
    627 		prefs_folder_column_set_view();
    628 	}
    629 }
    630 
    631 static void prefs_folder_column_cancel(void)
    632 {
    633 	folder_col.finished = TRUE;
    634 }
    635 
    636 static gint prefs_folder_column_delete_event(GtkWidget *widget,
    637 					      GdkEventAny *event,
    638 					      gpointer data)
    639 {
    640 	folder_col.finished = TRUE;
    641 	return TRUE;
    642 }
    643 
    644 static GtkListStore *prefs_folder_column_create_store(void)
    645 {
    646 	return gtk_list_store_new(N_SUMCOL_COLUMNS,
    647 				  G_TYPE_STRING,
    648 				  G_TYPE_INT,
    649 				  -1);
    650 }
    651 
    652 static void prefs_folder_column_insert_column(GtkListStore *store,
    653 					       gint row,
    654 					       const gchar *name,
    655 					       FolderColumnType type)
    656 {
    657 	GtkTreeIter iter;
    658 
    659 	if (row >= 0) {
    660 		if (!gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store),
    661 						   &iter, NULL, row))
    662 			row = -1;
    663 	}
    664 	if (row < 0) {
    665 		/* add new */
    666 		gtk_list_store_append(store, &iter);
    667 		gtk_list_store_set(store, &iter,
    668 				   SUMCOL_NAME, name,
    669 				   SUMCOL_TYPE, type,
    670 				   -1);
    671 		return;
    672 	} else {
    673 		/* change existing */
    674 		gtk_list_store_set(store, &iter,
    675 				   SUMCOL_NAME, name,
    676 				   SUMCOL_TYPE, type,
    677 				   -1);
    678 	}
    679 }
    680 
    681 /*!
    682  *\brief	Return the columnn type for a row
    683  */
    684 static FolderColumnType prefs_folder_column_get_column(GtkWidget *list, gint row)
    685 {
    686 	GtkTreeView *list_view = GTK_TREE_VIEW(list);
    687 	GtkTreeModel *model = gtk_tree_view_get_model(list_view);
    688 	GtkTreeIter iter;
    689 	FolderColumnType result;
    690 
    691 	if (!gtk_tree_model_iter_nth_child(model, &iter, NULL, row))
    692 		return -1;
    693 
    694 	gtk_tree_model_get(model, &iter,
    695 			   SUMCOL_TYPE, &result,
    696 			   -1);
    697 
    698 	return result;
    699 }
    700 
    701 static GtkWidget *prefs_folder_column_list_view_create(const gchar *name)
    702 {
    703 	GtkWidget *list_view;
    704 	GtkTreeSelection *selector;
    705 	GtkTreeModel *model;
    706 
    707 	model = GTK_TREE_MODEL(prefs_folder_column_create_store());
    708 	list_view = gtk_tree_view_new_with_model(model);
    709 	g_object_unref(G_OBJECT(model));
    710 
    711 	selector = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view));
    712 	gtk_tree_selection_set_mode(selector, GTK_SELECTION_BROWSE);
    713 
    714 	prefs_filtering_create_list_view_columns(GTK_WIDGET(list_view), name);
    715 
    716 	gtk_tree_view_enable_model_drag_source(GTK_TREE_VIEW(list_view),
    717 					       GDK_BUTTON1_MASK,
    718 					       row_targets,
    719 					       G_N_ELEMENTS(row_targets),
    720 					       GDK_ACTION_MOVE);
    721 
    722 	gtk_tree_view_enable_model_drag_dest(GTK_TREE_VIEW(list_view),
    723 					     row_targets,
    724 					     G_N_ELEMENTS(row_targets),
    725 					     GDK_ACTION_MOVE);
    726 
    727 	g_signal_connect(G_OBJECT(list_view), "drag_data_get",
    728 			 G_CALLBACK(drag_data_get),
    729 			 model);
    730 
    731 	g_signal_connect(G_OBJECT(list_view), "drag_data_received",
    732 			 G_CALLBACK(drag_data_received),
    733 			 model);
    734 
    735 	return list_view;
    736 }
    737 
    738 static void prefs_filtering_create_list_view_columns(GtkWidget *list_view,
    739 						     const gchar *name)
    740 {
    741 	GtkTreeViewColumn *column;
    742 	GtkCellRenderer *renderer;
    743 
    744 	renderer = gtk_cell_renderer_text_new();
    745 	column = gtk_tree_view_column_new_with_attributes
    746 		(name, renderer, "text", SUMCOL_NAME, NULL);
    747 	gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);
    748 }
    749 
    750 static void drag_data_get(GtkTreeView *tree_view, GdkDragContext *context,
    751 			  GtkSelectionData *data, guint info,
    752 			  guint time, GtkTreeModel *model)
    753 {
    754 	GtkTreeIter iter;
    755 	FolderColumnType type;
    756 	GtkTreeModel *source_model;
    757 
    758 	if (info != TARGET_INFO_SUMCOL)
    759 		return;
    760 
    761 	if (!gtk_tree_selection_get_selected
    762 			(gtk_tree_view_get_selection(tree_view),
    763 			 &source_model, &iter))
    764 		return;
    765 
    766 	gtk_tree_model_get(source_model, &iter,
    767 			   SUMCOL_TYPE, &type,
    768 			   -1);
    769 
    770 	/* send the type */
    771 	gtk_selection_data_set(data, gtk_selection_data_get_target(data), 8,
    772 		(gchar *) &type, sizeof type);
    773 }
    774 
    775 static void drag_data_received(GtkTreeView *tree_view, GdkDragContext *context,
    776 			       gint x, gint y, GtkSelectionData *data,
    777 			       guint info, guint time, GtkTreeModel *model)
    778 {
    779 	GtkWidget *source;
    780 	GtkTreePath *dst = NULL, *sel = NULL;
    781 	GtkTreeIter isel, idst;
    782 	GtkTreeViewDropPosition pos;
    783 	FolderColumnType type;
    784 	GtkTreeModel *sel_model;
    785 	gchar *name;
    786 
    787 	source = gtk_drag_get_source_widget(context);
    788 
    789 	if (source == GTK_WIDGET(tree_view)) {
    790 
    791 		/*
    792 		 * Same widget: re-order
    793 		 */
    794 
    795 		if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(tree_view),
    796 					   NULL, &isel)) {
    797 			sel = gtk_tree_model_get_path(model, &isel);
    798 			gtk_tree_view_get_dest_row_at_pos(tree_view, x, y,
    799 							  &dst, &pos);
    800 
    801 			/* NOTE: dst is invalid if selection beyond last row, in that
    802 			 * case move beyond last one (XXX_move_before(..., NULL)) */
    803 
    804 			if (dst)
    805 				gtk_tree_model_get_iter(model, &idst, dst);
    806 			else
    807 				gtk_list_store_move_before(GTK_LIST_STORE(model),
    808 							   &isel,
    809 							   NULL);
    810 
    811 			/* we do not drag if no valid dst and sel, and when
    812 			 * dst and sel are the same (moving after or before
    813 			 * itself doesn't change order...) */
    814 			if ((dst && sel) && gtk_tree_path_compare(sel, dst) != 0) {
    815 				if (pos == GTK_TREE_VIEW_DROP_BEFORE
    816 				||  pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)
    817 					gtk_list_store_move_before(GTK_LIST_STORE(model),
    818 								   &isel,
    819 								   &idst);
    820 				else
    821 					gtk_list_store_move_after(GTK_LIST_STORE(model),
    822 								  &isel,
    823 								  &idst);
    824 			}
    825 			gtk_tree_path_free(dst);
    826 			gtk_tree_path_free(sel);
    827 		}
    828 		gtk_drag_finish(context, TRUE, FALSE, time);
    829 
    830 	} else if (source == folder_col.stock_list_view
    831 	||	   source == folder_col.shown_list_view) {
    832 
    833 		/*
    834 		 * Other widget: change and update
    835 		 */
    836 
    837 		/* get source information and remove */
    838 		if (gtk_tree_selection_get_selected(gtk_tree_view_get_selection(
    839 						GTK_TREE_VIEW(source)),
    840 						&sel_model, &isel)) {
    841 			type = *((gint *) gtk_selection_data_get_data(data));
    842 			name = col_name[type];
    843 			gtk_list_store_remove(GTK_LIST_STORE(sel_model), &isel);
    844 
    845 			/* get insertion position */
    846 			gtk_tree_view_get_dest_row_at_pos(tree_view, x, y, &dst, &pos);
    847 
    848 			/* NOTE: dst is invalid if insertion point beyond last row,
    849 			 * just append to list in that case (XXX_store_append()) */
    850 
    851 			if (dst) {
    852 				gtk_tree_model_get_iter(model, &idst, dst);
    853 
    854 				if (pos == GTK_TREE_VIEW_DROP_BEFORE
    855 				||  pos == GTK_TREE_VIEW_DROP_INTO_OR_BEFORE)
    856 					gtk_list_store_insert_before(GTK_LIST_STORE(model),
    857 								     &isel,
    858 								     &idst);
    859 				else
    860 					gtk_list_store_insert_after(GTK_LIST_STORE(model),
    861 								    &isel,
    862 								    &idst);
    863 			} else
    864 				gtk_list_store_append(GTK_LIST_STORE(model),
    865 						      &isel);
    866 
    867 			gtk_list_store_set(GTK_LIST_STORE(model), &isel,
    868 					   SUMCOL_NAME, name,
    869 					   SUMCOL_TYPE, type, -1);
    870 			gtk_tree_path_free(dst);
    871 		}
    872 		gtk_drag_finish(context, TRUE, FALSE, time);
    873 	}
    874 
    875 	prefs_folder_column_shown_set_active(FALSE);
    876 	prefs_folder_column_stock_set_active(FALSE);
    877 
    878 	/* XXXX: should we call gtk_drag_finish() for other code paths? */
    879 }
    880 
    881 static void prefs_folder_column_shown_set_btn_sensitivity(void)
    882 {
    883 	GtkTreeModel *model = GTK_TREE_MODEL(gtk_tree_view_get_model(
    884 		GTK_TREE_VIEW(folder_col.shown_list_view)));
    885 	GtkTreeSelection *selection = gtk_tree_view_get_selection(
    886 		GTK_TREE_VIEW(folder_col.shown_list_view));
    887 	GtkTreeIter iter;
    888 	GtkTreePath *path;
    889 
    890 	if(!gtk_tree_selection_get_selected(selection, NULL, &iter)) {
    891 		gtk_widget_set_sensitive(folder_col.remove_btn, FALSE);
    892 		gtk_widget_set_sensitive(folder_col.up_btn, FALSE);
    893 		gtk_widget_set_sensitive(folder_col.down_btn, FALSE);
    894 		return;
    895 	}
    896 
    897 	path = gtk_tree_model_get_path(model, &iter);
    898 
    899 	gtk_widget_set_sensitive(folder_col.up_btn, gtk_tree_path_prev(path));
    900 	gtk_widget_set_sensitive(folder_col.down_btn,
    901 				 gtk_tree_model_iter_next(model, &iter));
    902 	gtk_tree_path_free(path);
    903 }
    904 
    905 static void prefs_folder_column_shown_set_active(const gboolean active)
    906 {
    907 	GtkTreeSelection *selection = NULL;
    908 
    909 	gtk_widget_set_sensitive(folder_col.remove_btn, active);
    910 
    911 	if(active == FALSE) {
    912 		selection = gtk_tree_view_get_selection(
    913 			GTK_TREE_VIEW(folder_col.shown_list_view));
    914 		gtk_tree_selection_unselect_all(selection);
    915 
    916 		gtk_widget_set_sensitive(folder_col.up_btn, FALSE);
    917 		gtk_widget_set_sensitive(folder_col.down_btn, FALSE);
    918 	} else {
    919 		prefs_folder_column_shown_set_btn_sensitivity();
    920 	}
    921 }
    922 
    923 static void prefs_folder_column_stock_set_active(const gboolean active)
    924 {
    925 	GtkTreeSelection *selection = NULL;
    926 
    927 	gtk_widget_set_sensitive(folder_col.add_btn, active);
    928 
    929 	if(active == FALSE) {
    930 		selection = gtk_tree_view_get_selection(
    931 			GTK_TREE_VIEW(folder_col.stock_list_view));
    932 		gtk_tree_selection_unselect_all(selection);
    933 	}
    934 }
    935 
    936 static void prefs_folder_column_stock_sel_changed(void)
    937 {
    938 	GtkTreeSelection *selection = gtk_tree_view_get_selection(
    939 		GTK_TREE_VIEW(folder_col.stock_list_view));
    940 	prefs_folder_column_stock_set_active(
    941 		(selection != NULL) ? TRUE : FALSE);
    942 	prefs_folder_column_shown_set_active(
    943 		(selection != NULL) ? FALSE : TRUE);
    944 }
    945 
    946 static void prefs_folder_column_shown_sel_changed(void)
    947 {
    948 	GtkTreeSelection *selection = gtk_tree_view_get_selection(
    949 		GTK_TREE_VIEW(folder_col.shown_list_view));
    950 	prefs_folder_column_shown_set_active(
    951 		(selection != NULL) ? TRUE : FALSE);
    952 	prefs_folder_column_stock_set_active(
    953 		(selection != NULL) ? FALSE : TRUE);
    954 }