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 }