talons

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

foldersort.c (11455B)


      1 /*
      2  * Claws Mail -- a GTK based, lightweight, and fast e-mail client
      3  * Copyright (C) 2004-2024 the Claws Mail Team
      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 
     20 #include <glib.h>
     21 #include <glib/gi18n.h>
     22 #include <gdk/gdkkeysyms.h>
     23 
     24 #include "foldersort.h"
     25 #include "inc.h"
     26 #include "utils.h"
     27 #include "prefs_common.h"
     28 
     29 enum {
     30 	FOLDERSORT_COL_NAME,
     31 	FOLDERSORT_COL_PTR,
     32 	N_FOLDERSORT_COLS
     33 };
     34 
     35 typedef struct _FolderSortDialog FolderSortDialog;
     36 
     37 struct _FolderSortDialog
     38 {
     39 	GtkWidget *window;
     40 	GtkWidget *moveup_btn;
     41 	GtkWidget *movedown_btn;
     42 	GtkWidget *folderlist;
     43 	gint rows;
     44 };
     45 
     46 static void destroy_dialog(FolderSortDialog *dialog)
     47 {
     48 	inc_unlock();
     49 	gtk_widget_destroy(dialog->window);
     50 
     51 	g_free(dialog);
     52 }
     53 
     54 static void ok_clicked(GtkWidget *widget, FolderSortDialog *dialog)
     55 {
     56 	Folder *folder;
     57 	GtkTreeModel *model;
     58 	GtkTreeIter iter;
     59 	int i;
     60 
     61 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(dialog->folderlist));
     62 
     63 	for (i = 0; i < dialog->rows; i++) {
     64 		if (!gtk_tree_model_iter_nth_child(model, &iter, NULL, i))
     65 			continue;
     66 
     67 		gtk_tree_model_get(model, &iter, FOLDERSORT_COL_PTR, &folder, -1);
     68 
     69 		folder_set_sort(folder, dialog->rows - i);
     70 	}
     71 
     72 	destroy_dialog(dialog);
     73 }
     74 
     75 static void cancel_clicked(GtkWidget *widget, FolderSortDialog *dialog)
     76 {
     77 	destroy_dialog(dialog);
     78 }
     79 
     80 static void set_selected(FolderSortDialog *dialog)
     81 {
     82 	GtkTreeSelection *sel;
     83 	GtkTreeModel *model;
     84 	GtkTreeIter iter;
     85 	GtkTreePath *path;
     86 	gint *indices;
     87 	gint selected;
     88 
     89 	/* Get row number of the selected row */
     90 	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->folderlist));
     91 	if (!gtk_tree_selection_get_selected(sel, &model, &iter))
     92 		return;
     93 	path = gtk_tree_model_get_path(model, &iter);
     94 	indices = gtk_tree_path_get_indices(path);
     95 	selected = indices[0];
     96 	gtk_tree_path_free(path);
     97 
     98 	if (selected >= 0) {
     99 		gtk_widget_set_sensitive(dialog->moveup_btn, selected > 0);
    100 		gtk_widget_set_sensitive(dialog->movedown_btn, selected < (dialog->rows - 1));
    101 	} else {
    102 		gtk_widget_set_sensitive(dialog->moveup_btn, FALSE);
    103 		gtk_widget_set_sensitive(dialog->movedown_btn, FALSE);
    104 	}
    105 }
    106 
    107 static void moveup_clicked(GtkWidget *widget, FolderSortDialog *dialog)
    108 {
    109 	GtkTreeSelection *sel;
    110 	GtkTreeModel *model;
    111 	GtkTreeIter iter, previter;
    112 
    113 	/* Get currently selected iter */
    114 	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->folderlist));
    115 	if (!gtk_tree_selection_get_selected(sel, &model, &iter))
    116 		return;
    117 
    118 	/* Now get the iter above it, if any */
    119 	previter = iter;
    120 	if (!gtk_tree_model_iter_previous(model, &previter)) {
    121 		/* No previous iter, are we already on top? */
    122 		return;
    123 	}
    124 
    125 	gtk_list_store_move_before(GTK_LIST_STORE(model), &iter, &previter);
    126 
    127 	set_selected(dialog);
    128 }
    129 
    130 static void movedown_clicked(GtkWidget *widget, FolderSortDialog *dialog)
    131 {
    132 	GtkTreeSelection *sel;
    133 	GtkTreeModel *model;
    134 	GtkTreeIter iter, nextiter;
    135 
    136 	/* Get currently selected iter */
    137 	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->folderlist));
    138 	if (!gtk_tree_selection_get_selected(sel, &model, &iter))
    139 		return;
    140 
    141 	/* Now get the iter above it, if any */
    142 	nextiter = iter;
    143 	if (!gtk_tree_model_iter_next(model, &nextiter)) {
    144 		/* No next iter, are we already on the bottom? */
    145 		return;
    146 	}
    147 
    148 	gtk_list_store_move_after(GTK_LIST_STORE(model), &iter, &nextiter);
    149 
    150 	set_selected(dialog);
    151 }
    152 
    153 static void folderlist_cursor_changed_cb(GtkTreeView *view, gpointer user_data)
    154 {
    155 	FolderSortDialog *dialog = (FolderSortDialog *)user_data;
    156 	set_selected(dialog);
    157 }
    158 
    159 static void folderlist_row_inserted_cb(GtkTreeModel *model,
    160 		GtkTreePath *path, GtkTreeIter *iter,
    161 		gpointer user_data)
    162 {
    163 	FolderSortDialog *dialog = (FolderSortDialog *)user_data;
    164 	GtkTreeSelection *sel;
    165 
    166 	/* The only time "row-inserted" signal should be fired is when
    167 	 * a row is reordered using drag&drop. So we want to select
    168 	 * the recently moved row, and call set_selected(), to update
    169 	 * the up/down button sensitivity. */
    170 	sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(dialog->folderlist));
    171 	gtk_tree_selection_select_iter(sel, iter);
    172 
    173 	set_selected(dialog);
    174 }
    175 
    176 static gint delete_event(GtkWidget *widget, GdkEventAny *event, FolderSortDialog *dialog)
    177 {
    178 	destroy_dialog(dialog);
    179 	return TRUE;
    180 }
    181 
    182 static void foldersort_size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation)
    183 {
    184 	cm_return_if_fail(allocation != NULL);
    185 
    186 	gtk_window_get_size(GTK_WINDOW(widget),
    187 		&prefs_common.foldersortwin_width, &prefs_common.foldersortwin_height);
    188 }
    189 
    190 void foldersort_open()
    191 {
    192 	FolderSortDialog *dialog = g_new0(FolderSortDialog, 1);
    193 	GList *flist;
    194 
    195 	GtkWidget *window;
    196 	GtkWidget *vbox;
    197 	GtkWidget *vbox1;
    198 	GtkWidget *label1;
    199 	GtkWidget *hbox;
    200 	GtkWidget *hbox2;
    201 	GtkWidget *ok_btn;
    202 	GtkWidget *cancel_btn;
    203 	GtkWidget *confirm_area;
    204 	GtkWidget *moveup_btn;
    205 	GtkWidget *movedown_btn;
    206 	GtkWidget *btn_vbox;
    207 	GtkWidget *scrolledwindow1;
    208 	GtkWidget *folderlist;
    209 	GtkTreeViewColumn *col;
    210 	GtkListStore *store;
    211 	GtkCellRenderer *rdr;
    212 	GtkTreeSelection *selector;
    213 	GtkTreeIter iter;
    214 	static GdkGeometry geometry;
    215 
    216 	window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "foldersort");
    217 	g_object_set_data(G_OBJECT(window), "window", window);
    218 	gtk_container_set_border_width(GTK_CONTAINER(window), 8);
    219 	gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    220 	gtk_window_set_title(GTK_WINDOW(window), _("Set mailbox order"));
    221 	gtk_window_set_modal(GTK_WINDOW(window), TRUE);
    222 	gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
    223 	g_signal_connect(G_OBJECT(window), "delete_event",
    224 			 G_CALLBACK(delete_event), dialog);
    225 	g_signal_connect (G_OBJECT(window), "size_allocate",
    226 			 G_CALLBACK (foldersort_size_allocate_cb), NULL);
    227 
    228 	vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
    229 	gtk_widget_show(vbox);
    230 	gtk_container_add(GTK_CONTAINER(window), vbox);
    231 
    232 	gtkut_stock_button_set_create(&confirm_area, &cancel_btn, NULL, _("_Cancel"),
    233 				      &ok_btn, NULL, _("_OK"),
    234 				      NULL, NULL, NULL);
    235 	gtk_widget_show(confirm_area);
    236 	gtk_box_pack_end(GTK_BOX(vbox), confirm_area, FALSE, FALSE, 0);
    237 	gtk_widget_grab_focus(ok_btn);
    238 
    239 	g_signal_connect(G_OBJECT(ok_btn), "clicked",
    240                          G_CALLBACK(ok_clicked), dialog);
    241 	g_signal_connect(G_OBJECT(cancel_btn), "clicked",
    242                          G_CALLBACK(cancel_clicked), dialog);
    243 
    244 	vbox1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8);
    245 	gtk_widget_show(vbox1);
    246 	gtk_box_pack_start(GTK_BOX(vbox), vbox1, TRUE, TRUE, 0);
    247 	gtk_container_set_border_width(GTK_CONTAINER(vbox1), 2);
    248 
    249 	hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
    250 	gtk_widget_show(hbox);
    251 	gtk_box_pack_start(GTK_BOX(vbox1), hbox, FALSE, FALSE, 0);
    252 
    253 	label1 = gtk_label_new(_
    254 		("Move mailboxes up or down to change the sort order "
    255 		 "in the Folder list."));
    256 	gtk_widget_show(label1);
    257 	gtk_widget_set_size_request(GTK_WIDGET(label1), 392, -1);
    258 	gtk_label_set_line_wrap(GTK_LABEL(label1), TRUE);
    259 	gtk_box_pack_start(GTK_BOX(hbox), label1, FALSE, FALSE, 0);
    260 
    261 	hbox2 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
    262 	gtk_widget_show(hbox2);
    263 	gtk_box_pack_start(GTK_BOX(vbox1), hbox2, TRUE, TRUE, 0);
    264 
    265 	scrolledwindow1 = gtk_scrolled_window_new(NULL, NULL);
    266 	gtk_widget_show(scrolledwindow1);
    267 	gtk_widget_set_size_request(scrolledwindow1, -1, 150);
    268 	gtk_box_pack_start(GTK_BOX(hbox2), scrolledwindow1,
    269 			   TRUE, TRUE, 0);
    270 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrolledwindow1),
    271 				       GTK_POLICY_AUTOMATIC,
    272 				       GTK_POLICY_AUTOMATIC);
    273 
    274 	/* Create the list store */
    275 	store = gtk_list_store_new(N_FOLDERSORT_COLS,
    276 			G_TYPE_STRING, G_TYPE_POINTER, -1);
    277 
    278 	/* Create the view widget */
    279 	folderlist = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
    280 
    281 	gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(folderlist), TRUE);
    282 	gtk_tree_view_set_reorderable(GTK_TREE_VIEW(folderlist), TRUE);
    283 	selector = gtk_tree_view_get_selection(GTK_TREE_VIEW(folderlist));
    284 	gtk_tree_selection_set_mode(selector, GTK_SELECTION_BROWSE);
    285 
    286 	/* The only column for the view widget */
    287 	rdr = gtk_cell_renderer_text_new();
    288 	col = gtk_tree_view_column_new_with_attributes(_("Mailboxes"),
    289 			rdr, "markup", FOLDERSORT_COL_NAME, NULL);
    290 	gtk_tree_view_column_set_min_width(col, 80);
    291 	gtk_tree_view_append_column(GTK_TREE_VIEW(folderlist), col);
    292 
    293 	gtk_widget_show(folderlist);
    294 	gtk_container_add(GTK_CONTAINER(scrolledwindow1), folderlist);
    295 
    296 	btn_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8);
    297 	gtk_widget_show(btn_vbox);
    298 	gtk_box_pack_start(GTK_BOX(hbox2), btn_vbox, FALSE, FALSE, 0);
    299 
    300 	moveup_btn = gtkut_stock_button("go-up", _("_Up"));
    301 	gtk_widget_show(moveup_btn);
    302 	gtk_box_pack_start(GTK_BOX(btn_vbox), moveup_btn, FALSE, FALSE, 0);
    303 	CLAWS_SET_TIP(moveup_btn,
    304 			_("Move the selected mailbox up"));
    305 
    306 	movedown_btn =  gtkut_stock_button("go-down", _("_Down"));
    307 	gtk_widget_show(movedown_btn);
    308 	gtk_box_pack_start(GTK_BOX(btn_vbox), movedown_btn, FALSE, FALSE, 0);
    309 	CLAWS_SET_TIP(movedown_btn,
    310 			_("Move the selected mailbox down"));
    311 
    312 	if (!geometry.min_height) {
    313 		geometry.min_width = 400;
    314 		geometry.min_height = 300;
    315 	}
    316 
    317 	gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
    318 				      GDK_HINT_MIN_SIZE);
    319 	gtk_window_set_default_size(GTK_WINDOW(window),
    320 				    prefs_common.foldersortwin_width,
    321 				    prefs_common.foldersortwin_height);
    322 
    323 	dialog->window = window;
    324 	dialog->moveup_btn = moveup_btn;
    325 	dialog->movedown_btn = movedown_btn;
    326 	dialog->folderlist = folderlist;
    327 
    328 	gtk_widget_show(window);
    329 	gtk_widget_set_sensitive(moveup_btn, FALSE);
    330 	gtk_widget_set_sensitive(movedown_btn, FALSE);
    331 
    332 	/* Connect up the signals for the up/down buttons */
    333 	g_signal_connect(G_OBJECT(moveup_btn), "clicked",
    334                          G_CALLBACK(moveup_clicked), dialog);
    335 	g_signal_connect(G_OBJECT(movedown_btn), "clicked",
    336                          G_CALLBACK(movedown_clicked), dialog);
    337 
    338 //	g_signal_connect(G_OBJECT(folderlist), "select-row",
    339 //			 G_CALLBACK(row_selected), dialog);
    340 //	g_signal_connect(G_OBJECT(folderlist), "unselect-row",
    341 //			 G_CALLBACK(row_unselected), dialog);
    342 //	g_signal_connect(G_OBJECT(folderlist), "row-move",
    343 //			 G_CALLBACK(row_moved), dialog);
    344 
    345 	/* Populate the list with mailboxes */
    346 	dialog->rows = 0;
    347 	for (flist = folder_get_list(); flist != NULL; flist = g_list_next(flist)) {
    348 		Folder *folder = flist->data;
    349 
    350 		gtk_list_store_append(store, &iter);
    351 		gtk_list_store_set(store, &iter,
    352 				FOLDERSORT_COL_NAME, folder->name,
    353 				FOLDERSORT_COL_PTR, folder,
    354 				-1);
    355 		dialog->rows++;
    356 	}
    357 
    358 	/* Connect up the signals for the folderlist */
    359 	g_signal_connect(G_OBJECT(folderlist), "cursor-changed",
    360 			G_CALLBACK(folderlist_cursor_changed_cb), dialog);
    361 	g_signal_connect(G_OBJECT(store), "row-inserted",
    362 			G_CALLBACK(folderlist_row_inserted_cb), dialog);
    363 
    364 	/* Select the first row and adjust the sensitivity of
    365 	 * the up/down buttons */
    366 	if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter)) {
    367 		gtk_tree_selection_select_iter(selector, &iter);
    368 		set_selected(dialog);
    369 	}
    370 	g_object_unref(store);
    371 	inc_lock();
    372 }