PR #1139: Remove some of deprecated GTK stuff
[geeqie.git] / src / bar-sort.cc
1 /*
2  * Copyright (C) 2004 John Ellis
3  * Copyright (C) 2008 - 2016 The Geeqie Team
4  *
5  * Author: John Ellis
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include "main.h"
23 #include "bar-sort.h"
24
25 #include "collect.h"
26 #include "collect-io.h"
27 #include "filedata.h"
28 #include "history-list.h"
29 #include "layout.h"
30 #include "layout-image.h"
31 #include "utilops.h"
32 #include "editors.h"
33 #include "ui-bookmark.h"
34 #include "ui-fileops.h"
35 #include "ui-misc.h"
36 #include "rcfile.h"
37 #include "window.h"
38
39
40 /*
41   *-------------------------------------------------------------------
42   * sort bar
43   *-------------------------------------------------------------------
44   */
45
46 struct SortData
47 {
48         GtkWidget *vbox;
49         GtkWidget *bookmarks;
50         LayoutWindow *lw;
51
52         FileDialog *dialog;
53         GtkWidget *dialog_name_entry;
54
55         SortModeType mode;
56         SortActionType action;
57         gchar *filter_key;
58
59         SortSelectionType selection;
60
61         GtkWidget *folder_group;
62         GtkWidget *collection_group;
63
64         GtkWidget *add_button;
65         GtkWidget *help_button;
66         GtkWidget *undo_button;
67         SortActionType undo_action;
68         GList *undo_src_list;
69         GList *undo_dest_list;
70         gchar *undo_collection;
71 };
72
73
74 #define SORT_KEY_FOLDERS     "sort_manager"
75 #define SORT_KEY_COLLECTIONS "sort_manager_collections"
76
77
78 static void bar_sort_undo_set(SortData *sd, GList *src_list, const gchar *dest);
79 static void bar_sort_add_close(SortData *sd);
80
81
82 static void bar_sort_collection_list_build(GtkWidget *bookmarks)
83 {
84         FileData *dir_fd;
85         GList *list;
86         GList *work;
87
88         history_list_free_key(SORT_KEY_COLLECTIONS);
89         bookmark_list_set_key(bookmarks, SORT_KEY_COLLECTIONS);
90
91         dir_fd = file_data_new_dir(get_collections_dir());
92         filelist_read(dir_fd, &list, nullptr);
93         file_data_unref(dir_fd);
94
95         list = filelist_sort_path(list);
96
97         work = list;
98         while (work)
99                 {
100                 FileData *fd;
101                 gchar *name;
102
103                 fd = static_cast<FileData *>(work->data);
104                 work = work->next;
105
106                 if (file_extension_match(fd->path, GQ_COLLECTION_EXT))
107                         {
108                         name = remove_extension_from_path(fd->name);
109                         }
110                 else
111                         {
112                         name = g_strdup(fd->name);
113                         }
114                 bookmark_list_add(bookmarks, name, fd->path);
115                 g_free(name);
116                 }
117
118         filelist_free(list);
119 }
120
121 static void bar_sort_mode_sync(SortData *sd, SortModeType mode)
122 {
123         gboolean folder_mode;
124
125         if (sd->mode == mode) return;
126         sd->mode = mode;
127
128         folder_mode = (sd->mode == BAR_SORT_MODE_FOLDER);
129
130         bookmark_list_set_no_defaults(sd->bookmarks, !folder_mode);
131         bookmark_list_set_editable(sd->bookmarks, folder_mode);
132         bookmark_list_set_only_directories(sd->bookmarks, folder_mode);
133
134         if (folder_mode)
135                 {
136                 gtk_widget_hide(sd->collection_group);
137                 gtk_widget_show(sd->folder_group);
138                 bookmark_list_set_key(sd->bookmarks, SORT_KEY_FOLDERS);
139                 }
140         else
141                 {
142                 gtk_widget_hide(sd->folder_group);
143                 gtk_widget_show(sd->collection_group);
144                 bar_sort_collection_list_build(sd->bookmarks);
145                 }
146
147         bar_sort_add_close(sd);
148
149         bar_sort_undo_set(sd, nullptr, nullptr);
150 }
151
152 static void bar_sort_mode_cb(GtkWidget *combo, gpointer data)
153 {
154         auto sd = static_cast<SortData *>(data);
155
156         if (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)) == BAR_SORT_MODE_FOLDER)
157                 {
158                 bar_sort_mode_sync(sd, BAR_SORT_MODE_FOLDER);
159                 }
160         else
161                 {
162                 bar_sort_mode_sync(sd, BAR_SORT_MODE_COLLECTION);
163                 }
164 }
165
166 /* this takes control of src_list */
167 static void bar_sort_undo_set(SortData *sd, GList *src_list, const gchar *dest)
168 {
169         g_list_free_full(sd->undo_src_list, g_free);
170         sd->undo_src_list = filelist_to_path_list(src_list);
171
172         if (src_list)
173                 {
174                 /* we should create the undo_dest_list to use it later... */
175                 g_list_free_full(sd->undo_dest_list, g_free);
176                 sd->undo_dest_list=nullptr;
177
178                 GList *work = sd->undo_src_list;
179                 while(work)
180                         {
181                         gchar *filename = g_strdup(filename_from_path(static_cast<const gchar *>(work->data)));
182                         gchar *dest_path = g_build_filename(g_strdup(dest), filename, NULL);
183                         sd->undo_dest_list = g_list_prepend(sd->undo_dest_list, g_strdup(dest_path));
184                         work = work->next;
185                         }
186                 sd->undo_dest_list = g_list_reverse(sd->undo_dest_list);
187                 }
188
189         sd->undo_action = sd->action;
190
191         if (sd->undo_button)
192                 {
193                 gtk_widget_set_sensitive(sd->undo_button,
194                                         ((sd->undo_src_list ) && sd->undo_dest_list));
195                 }
196 }
197
198 static void bar_sort_undo_folder(SortData *sd, GtkWidget *button)
199 {
200         gchar *origin;
201
202         if (!(sd->undo_src_list && sd->undo_dest_list)) return;
203
204         switch (sd->undo_action)
205                 {
206                 case BAR_SORT_MOVE:
207                         {
208                         GList *list;
209                         gchar *src_dir;
210                         gchar *src_path;
211
212                         if (sd->undo_src_list)
213                                 {
214                                 GList *work = nullptr;
215
216                                 src_path = g_strdup(static_cast<const gchar *>(sd->undo_src_list->data));
217                                 src_dir = remove_level_from_path(src_path);
218                                 list = sd->undo_dest_list;
219                                 while (list)
220                                         {
221                                         work = g_list_prepend(work, file_data_new_group(static_cast<const gchar *>(list->data)));
222                                         list=list->next;
223                                         }
224                                 file_util_move_simple(work, src_dir, sd->lw->window);
225                                 g_free(src_dir);
226                                 g_free(src_path);
227                                 }
228                         }
229                         break;
230
231                 case BAR_SORT_COPY:
232                 case BAR_SORT_FILTER:
233                         if (sd->undo_src_list)
234                                 {
235                                 GList *delete_list;
236                                 GList *work = nullptr;
237
238                                 delete_list = sd->undo_dest_list;
239                                 while (delete_list)
240                                         {
241                                         work = g_list_append(work, file_data_new_group(static_cast<const gchar *>(delete_list->data)));
242                                         delete_list = delete_list->next;
243                                         }
244                                 options->file_ops.safe_delete_enable = TRUE;
245                                 file_util_delete(nullptr, work, button);
246                                 }
247                         break;
248
249                 default:
250                         break;
251                 }
252
253         layout_refresh(sd->lw);
254         origin = static_cast<gchar *>((sd->undo_src_list)->data);
255
256         if (isfile(origin))
257                 {
258                 layout_image_set_fd(sd->lw, file_data_new_group(origin));
259                 }
260
261         bar_sort_undo_set(sd, nullptr, nullptr);
262 }
263
264 static void bar_sort_undo_collection(SortData *sd)
265 {
266         GList *work;
267
268         work = sd->undo_src_list;
269         while (work)
270                 {
271                 gchar *source;
272                 source = static_cast<gchar *>(work->data);
273                 work = work->next;
274                 collect_manager_remove(file_data_new_group(source), sd->undo_collection);
275                 }
276
277         bar_sort_undo_set(sd, nullptr,  nullptr);
278 }
279
280 static void bar_sort_undo_cb(GtkWidget *button, gpointer data)
281 {
282         auto sd = static_cast<SortData *>(data);
283
284         if (sd->mode == BAR_SORT_MODE_FOLDER)
285                 {
286                 bar_sort_undo_folder(sd, button);
287                 }
288         else
289                 {
290                 bar_sort_undo_collection(sd);
291                 }
292 }
293
294 static void bar_sort_bookmark_select_folder(SortData *sd, FileData *, const gchar *path)
295 {
296         GList *orig_list;
297         GList *action_list;
298         GList *undo_src_list;
299
300         if (!isdir(path)) return;
301
302         orig_list = layout_selection_list(sd->lw);
303         action_list = orig_list;
304         undo_src_list = orig_list;
305         orig_list = nullptr;
306
307         bar_sort_undo_set(sd, undo_src_list, path);
308
309         switch (sd->action)
310                 {
311                 case BAR_SORT_COPY:
312                         file_util_copy_simple(action_list, path, sd->lw->window);
313                         action_list = nullptr;
314                         layout_image_next(sd->lw);
315                         break;
316
317                 case BAR_SORT_MOVE:
318                         file_util_move_simple(action_list, path, sd->lw->window);
319                         action_list = nullptr;
320                         break;
321
322                 case BAR_SORT_FILTER:
323                         file_util_start_filter_from_filelist(sd->filter_key, action_list, path, sd->lw->window);
324                         layout_image_next(sd->lw);
325                         break;
326
327                 default:
328                         break;
329                 }
330 }
331
332 static void bar_sort_bookmark_select_collection(SortData *sd, FileData *source, const gchar *path)
333 {
334         GList *list = nullptr;
335
336         switch (sd->selection)
337                 {
338                 case BAR_SORT_SELECTION_IMAGE:
339                         list = g_list_append(nullptr, file_data_ref(source));
340                         break;
341                 case BAR_SORT_SELECTION_SELECTED:
342                         list = layout_selection_list(sd->lw);
343                         break;
344                 default:
345                         break;
346                 }
347
348         if (!list)
349                 {
350                 bar_sort_undo_set(sd, nullptr, nullptr);
351                 return;
352                 }
353
354         bar_sort_undo_set(sd, list, path);
355         sd->undo_collection = g_strdup(path);
356
357         while (list)
358                 {
359                 FileData *image_fd;
360
361                 image_fd = static_cast<FileData *>(list->data);
362                 list = list->next;
363                 collect_manager_add(image_fd, path);
364                 }
365 }
366
367 static void bar_sort_bookmark_select(const gchar *path, gpointer data)
368 {
369         auto sd = static_cast<SortData *>(data);
370         FileData *source;
371
372         source = layout_image_get_fd(sd->lw);
373         if (!path || !source) return;
374
375         if (sd->mode == BAR_SORT_MODE_FOLDER)
376                 {
377                 bar_sort_bookmark_select_folder(sd, source, path);
378                 }
379         else
380                 {
381                 bar_sort_bookmark_select_collection(sd, source, path);
382                 }
383 }
384
385 static void bar_sort_set_action(SortData *sd, SortActionType action, const gchar *filter_key)
386 {
387         sd->action = action;
388         if (action == BAR_SORT_FILTER)
389                 {
390                 if (!filter_key) filter_key = "";
391                 sd->filter_key = g_strdup(filter_key);
392                 }
393         else
394                 {
395                 sd->filter_key = nullptr;
396                 }
397 }
398
399 static void bar_sort_set_copy_cb(GtkWidget *button, gpointer data)
400 {
401         auto sd = static_cast<SortData *>(data);
402         if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) return;
403         bar_sort_set_action(sd, BAR_SORT_COPY, nullptr);
404 }
405
406 static void bar_sort_set_move_cb(GtkWidget *button, gpointer data)
407 {
408         auto sd = static_cast<SortData *>(data);
409         if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) return;
410         bar_sort_set_action(sd, BAR_SORT_MOVE, nullptr);
411 }
412
413 static void bar_sort_set_filter_cb(GtkWidget *button, gpointer data)
414 {
415         auto sd = static_cast<SortData *>(data);
416         const gchar *key;
417
418         if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) return;
419         key = static_cast<const gchar *>(g_object_get_data(G_OBJECT(button), "filter_key"));
420         bar_sort_set_action(sd, BAR_SORT_FILTER, key);
421 }
422
423 static void bar_filter_help_cb(GenericDialog *, gpointer)
424 {
425         help_window_show("GuidePluginsConfig.html#Geeqieextensions");
426 }
427
428 static void bar_filter_help_dialog()
429 {
430         GenericDialog *gd;
431
432         gd = generic_dialog_new(_("Sort Manager Operations"),
433                                 "sort_manager_operations", nullptr, TRUE, nullptr, nullptr);
434         generic_dialog_add_message(gd, GTK_STOCK_DIALOG_INFO,
435                                 "Sort Manager Operations", _("Additional operations utilising plugins\nmay be included by setting:\n\nX-Geeqie-Filter=true\n\nin the plugin file."), TRUE);
436         generic_dialog_add_button(gd, GQ_ICON_HELP, _("Help"), bar_filter_help_cb, TRUE);
437         generic_dialog_add_button(gd, GQ_ICON_OK, "OK", NULL, TRUE);
438
439         gtk_widget_show(gd->dialog);
440 }
441
442 static gboolean bar_filter_message_cb(GtkWidget *, GdkEventButton *event, gpointer)
443 {
444         if (event->button != MOUSE_BUTTON_RIGHT) return FALSE;
445
446         bar_filter_help_dialog();
447
448         return TRUE;
449 }
450
451 static void bar_sort_help_cb(gpointer)
452 {
453         bar_filter_help_dialog();
454 }
455
456 static void bar_sort_set_selection(SortData *sd, SortSelectionType selection)
457 {
458         sd->selection = selection;
459 }
460
461 static void bar_sort_set_selection_image_cb(GtkWidget *button, gpointer data)
462 {
463         auto sd = static_cast<SortData *>(data);
464         if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) return;
465         bar_sort_set_selection(sd, BAR_SORT_SELECTION_IMAGE);
466 }
467
468 static void bar_sort_set_selection_selected_cb(GtkWidget *button, gpointer data)
469 {
470         auto sd = static_cast<SortData *>(data);
471         if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) return;
472         bar_sort_set_selection(sd, BAR_SORT_SELECTION_SELECTED);
473 }
474
475 static void bar_sort_add_close(SortData *sd)
476 {
477         if (sd->dialog) file_dialog_close(sd->dialog);
478         sd->dialog_name_entry = nullptr;
479         sd->dialog = nullptr;
480 }
481
482 static void bar_sort_add_ok_cb(FileDialog *fd, gpointer data)
483 {
484         auto sd = static_cast<SortData *>(data);
485         const gchar *name = gtk_entry_get_text(GTK_ENTRY(sd->dialog_name_entry));
486         gboolean empty_name = (name[0] == '\0');
487
488         name = gtk_entry_get_text(GTK_ENTRY(sd->dialog_name_entry));
489         if (sd->mode == BAR_SORT_MODE_FOLDER)
490                 {
491                 if (empty_name)
492                         {
493                         name = filename_from_path(fd->dest_path);
494                         }
495
496                 bookmark_list_add(sd->bookmarks, name, fd->dest_path);
497                 }
498         else
499                 {
500                 gchar *path;
501                 gboolean has_extension;
502                 auto filename = const_cast<gchar *>(name);
503
504                 if (empty_name) return;
505
506                 has_extension = file_extension_match(name, GQ_COLLECTION_EXT);
507                 if (!has_extension)
508                         {
509                         filename = g_strconcat(name, GQ_COLLECTION_EXT, NULL);
510                         }
511
512                 path = g_build_filename(get_collections_dir(), filename, NULL);
513                 if (isfile(path))
514                         {
515                         gchar *text = g_strdup_printf(_("The collection:\n%s\nalready exists."), filename);
516                         file_util_warning_dialog(_("Collection exists"), text, GTK_STOCK_DIALOG_INFO, nullptr);
517                         g_free(text);
518                         }
519                 else
520                         {
521                         CollectionData *cd;
522
523                         cd = collection_new(path);
524                         if (collection_save(cd, path))
525                                 {
526                                 bar_sort_collection_list_build(sd->bookmarks);
527                                 }
528                         else
529                                 {
530                                 gchar *text = g_strdup_printf(_("Failed to save the collection:\n%s"), path);
531                                 file_util_warning_dialog(_("Save Failed"), text,
532                                                          GTK_STOCK_DIALOG_ERROR, GENERIC_DIALOG(fd)->dialog);
533                                 g_free(text);
534                                 }
535                         collection_unref(cd);
536                         }
537
538                 if (!has_extension) g_free(filename);
539                 g_free(path);
540                 }
541
542         bar_sort_add_close(sd);
543 }
544
545 static void bar_sort_add_cancel_cb(FileDialog *, gpointer data)
546 {
547         auto sd = static_cast<SortData *>(data);
548
549         bar_sort_add_close(sd);
550 }
551
552 static void bar_sort_add_cb(GtkWidget *button, gpointer data)
553 {
554         auto sd = static_cast<SortData *>(data);
555         GtkWidget *hbox;
556         const gchar *title;
557
558         if (sd->dialog)
559                 {
560                 gtk_window_present(GTK_WINDOW(GENERIC_DIALOG(sd->dialog)->dialog));
561                 return;
562                 }
563
564         if (sd->mode == BAR_SORT_MODE_FOLDER)
565                 {
566                 title = _("Add Bookmark");
567                 }
568         else
569                 {
570                 title = _("Add Collection");
571                 }
572
573         sd->dialog = file_util_file_dlg(title,
574                                        "add_bookmark", button,
575                                        bar_sort_add_cancel_cb, sd);
576         file_dialog_add_button(sd->dialog, GQ_ICON_OK, "OK", bar_sort_add_ok_cb, TRUE);
577
578         generic_dialog_add_message(GENERIC_DIALOG(sd->dialog), nullptr, title, nullptr, FALSE);
579
580         if (sd->mode == BAR_SORT_MODE_FOLDER)
581                 {
582                 file_dialog_add_path_widgets(sd->dialog, nullptr, nullptr, "add_bookmark", nullptr, nullptr);
583                 }
584
585         hbox = pref_box_new(GENERIC_DIALOG(sd->dialog)->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_GAP);
586
587         pref_label_new(hbox, _("Name:"));
588
589         sd->dialog_name_entry = gtk_entry_new();
590         gtk_box_pack_start(GTK_BOX(hbox), sd->dialog_name_entry, TRUE, TRUE, 0);
591         generic_dialog_attach_default(GENERIC_DIALOG(sd->dialog), sd->dialog_name_entry);
592         gtk_widget_show(sd->dialog_name_entry);
593
594         if (sd->mode == BAR_SORT_MODE_COLLECTION)
595                 {
596                 gtk_widget_grab_focus(sd->dialog_name_entry);
597                 }
598
599         gtk_widget_show(GENERIC_DIALOG(sd->dialog)->dialog);
600 }
601
602 void bar_sort_close(GtkWidget *bar)
603 {
604         SortData *sd;
605
606         sd = static_cast<SortData *>(g_object_get_data(G_OBJECT(bar), "bar_sort_data"));
607         if (!sd) return;
608
609         gtk_widget_destroy(sd->vbox);
610 }
611
612 static void bar_sort_destroy(GtkWidget *, gpointer data)
613 {
614         auto sd = static_cast<SortData *>(data);
615
616         bar_sort_add_close(sd);
617
618         g_free(sd->filter_key);
619         g_list_free_full(sd->undo_src_list, g_free);
620         g_list_free_full(sd->undo_dest_list, g_free);
621         g_free(sd->undo_collection);
622         g_free(sd);
623 }
624
625 static void bar_sort_edit_button_free(gpointer data)
626 {
627         g_free(data);
628 }
629
630 static GtkWidget *bar_sort_new(LayoutWindow *lw, SortActionType action,
631                                SortModeType mode, SortSelectionType selection,
632                                const gchar *filter_key)
633 {
634         SortData *sd;
635         GtkWidget *buttongrp;
636         GtkWidget *label;
637         GtkWidget *tbar;
638         GtkWidget *combo;
639         GList *editors_list, *work;
640         gboolean have_filter;
641         GtkWidget *button;
642
643         if (!lw) return nullptr;
644
645         sd = g_new0(SortData, 1);
646
647         sd->lw = lw;
648
649         sd->action = action;
650
651         if (sd->action == BAR_SORT_FILTER && (!filter_key || !filter_key[0]))
652                 {
653                 sd->action = BAR_SORT_COPY;
654                 }
655
656         sd->selection = selection;
657         sd->undo_src_list = nullptr;
658         sd->undo_dest_list = nullptr;
659         sd->undo_collection = nullptr;
660
661         sd->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, PREF_PAD_GAP);
662         DEBUG_NAME(sd->vbox);
663         g_object_set_data(G_OBJECT(sd->vbox), "bar_sort_data", sd);
664         g_signal_connect(G_OBJECT(sd->vbox), "destroy",
665                          G_CALLBACK(bar_sort_destroy), sd);
666
667         label = gtk_label_new(_("Sort Manager"));
668         pref_label_bold(label, TRUE, FALSE);
669         gtk_box_pack_start(GTK_BOX(sd->vbox), label, FALSE, FALSE, 0);
670         gtk_widget_show(label);
671
672         combo = gtk_combo_box_text_new();
673         gtk_box_pack_start(GTK_BOX(sd->vbox), combo, FALSE, FALSE, 0);
674         gtk_widget_show(combo);
675
676         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Folders"));
677         gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), _("Collections"));
678
679         g_signal_connect(G_OBJECT(combo), "changed",
680                          G_CALLBACK(bar_sort_mode_cb), sd);
681
682         sd->folder_group = pref_box_new(sd->vbox, FALSE, GTK_ORIENTATION_VERTICAL, 0);
683         DEBUG_NAME(sd->folder_group);
684         gtk_widget_set_tooltip_text(sd->folder_group, _("See the Help file for additional functions"));
685
686         buttongrp = pref_radiobutton_new(sd->folder_group, nullptr,
687                                          _("Copy"), (sd->action == BAR_SORT_COPY),
688                                          G_CALLBACK(bar_sort_set_copy_cb), sd);
689         g_signal_connect(G_OBJECT(buttongrp), "button_press_event", G_CALLBACK(bar_filter_message_cb), NULL);
690         button = pref_radiobutton_new(sd->folder_group, buttongrp,
691                              _("Move"), (sd->action == BAR_SORT_MOVE),
692                              G_CALLBACK(bar_sort_set_move_cb), sd);
693         g_signal_connect(G_OBJECT(button), "button_press_event", G_CALLBACK(bar_filter_message_cb), NULL);
694
695
696         have_filter = FALSE;
697         editors_list = editor_list_get();
698         work = editors_list;
699         while (work)
700                 {
701                 GtkWidget *button;
702                 auto editor = static_cast<EditorDescription *>(work->data);
703                 gchar *key;
704                 gboolean select = FALSE;
705
706                 work = work->next;
707
708                 if (!editor_is_filter(editor->key)) continue;
709
710                 key = g_strdup(editor->key);
711                 if (sd->action == BAR_SORT_FILTER && strcmp(key, filter_key) == 0)
712                         {
713                         bar_sort_set_action(sd, sd->action, key);
714                         select = TRUE;
715                         have_filter = TRUE;
716                         }
717
718                 button = pref_radiobutton_new(sd->folder_group, buttongrp,
719                                               editor->name, select,
720                                               G_CALLBACK(bar_sort_set_filter_cb), sd);
721                 g_signal_connect(G_OBJECT(button), "button_press_event", G_CALLBACK(bar_filter_message_cb), NULL);
722
723                 g_object_set_data_full(G_OBJECT(button), "filter_key", key, bar_sort_edit_button_free);
724                 }
725         g_list_free(editors_list);
726
727         if (sd->action == BAR_SORT_FILTER && !have_filter) sd->action = BAR_SORT_COPY;
728
729         sd->collection_group = pref_box_new(sd->vbox, FALSE, GTK_ORIENTATION_VERTICAL, 0);
730
731         buttongrp = pref_radiobutton_new(sd->collection_group, nullptr,
732                                          _("Add image"), (sd->selection == BAR_SORT_SELECTION_IMAGE),
733                                          G_CALLBACK(bar_sort_set_selection_image_cb), sd);
734         pref_radiobutton_new(sd->collection_group, buttongrp,
735                              _("Add selection"), (sd->selection == BAR_SORT_SELECTION_SELECTED),
736                              G_CALLBACK(bar_sort_set_selection_selected_cb), sd);
737
738         sd->bookmarks = bookmark_list_new(SORT_KEY_FOLDERS, bar_sort_bookmark_select, sd);
739         DEBUG_NAME(sd->bookmarks);
740         gtk_box_pack_start(GTK_BOX(sd->vbox), sd->bookmarks, TRUE, TRUE, 0);
741         gtk_widget_show(sd->bookmarks);
742
743         tbar = pref_toolbar_new(sd->vbox, GTK_TOOLBAR_ICONS);
744         DEBUG_NAME(tbar);
745
746         sd->add_button = pref_toolbar_button(tbar, GQ_ICON_ADD, _("Add"), FALSE,
747                                              _("Add Bookmark"),
748                                              G_CALLBACK(bar_sort_add_cb), sd);
749         sd->undo_button = pref_toolbar_button(tbar, GQ_ICON_UNDO, _("Undo"), FALSE,
750                                               _("Undo last image"),
751                                               G_CALLBACK(bar_sort_undo_cb), sd);
752         sd->help_button = pref_toolbar_button(tbar, GQ_ICON_HELP, _("Help"), FALSE,
753                                               _("Functions additional to Copy and Move"),
754                                               G_CALLBACK(bar_sort_help_cb), sd);
755
756         sd->mode = static_cast<SortModeType>(-1);
757         bar_sort_mode_sync(sd, mode);
758         gtk_combo_box_set_active(GTK_COMBO_BOX(combo), static_cast<gint>(sd->mode));
759
760         return sd->vbox;
761 }
762
763 GtkWidget *bar_sort_new_from_config(LayoutWindow *lw, const gchar **, const gchar **)
764 {
765         GtkWidget *bar;
766
767         bar = bar_sort_new(lw, lw->options.action, lw->options.mode, lw->options.selection, lw->options.filter_key);
768
769         if (lw->bar_sort_enabled) gtk_widget_show(bar);
770         return bar;
771 }
772
773 /**
774  * @brief Sets the bar_sort_enabled flag
775  * @param lw
776  * @param attribute_names
777  * @param attribute_values
778  *
779  * Called from rcfile when processing geeqierc.xml on start-up.
780  * It is necessary to set the bar_sort_enabled flag because
781  * the sort manager and desktop files are set up in the idle loop, and
782  * setup is not yet completed during initialisation.
783  * The flag is checked in layout_editors_reload_idle_cb.
784  */
785 void bar_sort_cold_start(LayoutWindow *lw, const gchar **attribute_names, const gchar **attribute_values)
786 {
787         gboolean enabled = TRUE;
788         gint action = BAR_SORT_COPY;
789         gint mode = BAR_SORT_MODE_FOLDER;
790         gint selection = BAR_SORT_SELECTION_IMAGE;
791         gchar *filter_key = nullptr;
792
793         while (attribute_names && *attribute_names)
794                 {
795                 const gchar *option = *attribute_names++;
796                 const gchar *value = *attribute_values++;
797
798                 if (READ_BOOL_FULL("enabled", enabled)) continue;
799                 if (READ_INT_CLAMP_FULL("action", action, 0, BAR_SORT_ACTION_COUNT - 1)) continue;
800                 if (READ_INT_CLAMP_FULL("mode", mode, 0, BAR_SORT_MODE_COUNT - 1)) continue;
801                 if (READ_INT_CLAMP_FULL("selection", selection, 0, BAR_SORT_SELECTION_COUNT - 1)) continue;
802                 if (READ_CHAR_FULL("filter_key", filter_key)) continue;
803
804                 log_printf("unknown attribute %s = %s\n", option, value);
805                 }
806
807         lw->options.action = static_cast<SortActionType>(action);
808         lw->options.mode = static_cast<SortModeType>(mode);
809         lw->options.selection = static_cast<SortSelectionType>(selection);
810         lw->options.filter_key = g_strdup(filter_key);
811         lw->bar_sort_enabled = enabled;
812
813         g_free(filter_key);
814 }
815
816 GtkWidget *bar_sort_new_default(LayoutWindow *lw)
817 {
818         return bar_sort_new_from_config(lw, nullptr, nullptr);
819 }
820
821 void bar_sort_write_config(GtkWidget *bar, GString *outstr, gint indent)
822 {
823         SortData *sd;
824
825         if (!bar) return;
826         sd = static_cast<SortData *>(g_object_get_data(G_OBJECT(bar), "bar_sort_data"));
827         if (!sd) return;
828
829         WRITE_NL(); WRITE_STRING("<bar_sort ");
830         write_bool_option(outstr, indent, "enabled", gtk_widget_get_visible(bar));
831         WRITE_INT(*sd, mode);
832         WRITE_INT(*sd, action);
833         WRITE_INT(*sd, selection);
834         WRITE_CHAR(*sd, filter_key);
835         WRITE_STRING("/>");
836 }
837
838
839 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */