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