1 /* EasyTAG - tag editor for audio files
2  * Copyright (C) 2014-2015  David King <amigadave@amigadave.com>
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License as published by the Free
6  * Software Foundation; either version 2 of the License, or (at your option)
7  * any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12  * more details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program; if not, write to the Free Software Foundation, Inc., 51
16  * Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  */
18 
19 #include "config.h"
20 
21 #include "application_window.h"
22 
23 #include <glib/gi18n.h>
24 
25 #include "browser.h"
26 #include "cddb_dialog.h"
27 #include "charset.h"
28 #include "easytag.h"
29 #include "file_area.h"
30 #include "file_list.h"
31 #ifdef ENABLE_FLAC
32 #include "flac_header.h"
33 #endif
34 #include "load_files_dialog.h"
35 #include "log.h"
36 #include "misc.h"
37 #ifdef ENABLE_MP4
38 #include "mp4_header.h"
39 #endif
40 #include "mpeg_header.h"
41 #include "monkeyaudio_header.h"
42 #include "musepack_header.h"
43 #ifdef ENABLE_OGG
44 #include "ogg_header.h"
45 #endif
46 #ifdef ENABLE_OPUS
47 #include "opus_header.h"
48 #endif
49 #include "picture.h"
50 #include "playlist_dialog.h"
51 #include "preferences_dialog.h"
52 #include "progress_bar.h"
53 #include "search_dialog.h"
54 #include "scan.h"
55 #include "scan_dialog.h"
56 #include "setting.h"
57 #include "status_bar.h"
58 #include "tag_area.h"
59 #ifdef ENABLE_WAVPACK
60 #include "wavpack_header.h"
61 #endif
62 
63 typedef struct
64 {
65     GtkWidget *browser;
66 
67     GtkWidget *file_area;
68     GtkWidget *log_area;
69     GtkWidget *tag_area;
70     GtkWidget *progress_bar;
71     GtkWidget *status_bar;
72 
73     GtkWidget *cddb_dialog;
74     GtkWidget *load_files_dialog;
75     GtkWidget *playlist_dialog;
76     GtkWidget *preferences_dialog;
77     GtkWidget *scan_dialog;
78     GtkWidget *search_dialog;
79 
80     GtkWidget *hpaned;
81     GtkWidget *vpaned;
82 
83     GdkCursor *cursor;
84 
85     gboolean is_maximized;
86     gint height;
87     gint width;
88     gint paned_position;
89 } EtApplicationWindowPrivate;
90 
G_DEFINE_TYPE_WITH_PRIVATE(EtApplicationWindow,et_application_window,GTK_TYPE_APPLICATION_WINDOW)91 G_DEFINE_TYPE_WITH_PRIVATE (EtApplicationWindow, et_application_window, GTK_TYPE_APPLICATION_WINDOW)
92 
93 /* Used to force to hide the msgbox when deleting file */
94 static gboolean SF_HideMsgbox_Delete_File;
95 /* To remember which button was pressed when deleting file */
96 static gint SF_ButtonPressed_Delete_File;
97 
98 static gboolean
99 on_main_window_delete_event (GtkWidget *window,
100                              GdkEvent *event,
101                              gpointer user_data)
102 {
103     et_application_window_quit (ET_APPLICATION_WINDOW (window));
104 
105     /* Handled the event, so stop propagation. */
106     return GDK_EVENT_STOP;
107 }
108 
109 static void
save_state(EtApplicationWindow * self)110 save_state (EtApplicationWindow *self)
111 {
112     EtApplicationWindowPrivate *priv;
113     gchar *path;
114     GKeyFile *keyfile;
115     gchar *buffer;
116     gsize length;
117     GError *error = NULL;
118 
119     priv = et_application_window_get_instance_private (self);
120     keyfile = g_key_file_new ();
121     path = g_build_filename (g_get_user_cache_dir (), PACKAGE_TARNAME,
122                              "state", NULL);
123 
124     /* Try to preserve comments by loading an existing keyfile. */
125     if (!g_key_file_load_from_file (keyfile, path, G_KEY_FILE_KEEP_COMMENTS,
126                                     &error))
127     {
128         g_debug ("Error loading window state during saving: %s",
129                  error->message);
130         g_clear_error (&error);
131     }
132 
133     g_key_file_set_integer (keyfile, "EtApplicationWindow", "width",
134                             priv->width);
135     g_key_file_set_integer (keyfile, "EtApplicationWindow", "height",
136                             priv->height);
137     g_key_file_set_boolean (keyfile, "EtApplicationWindow", "is_maximized",
138                             priv->is_maximized);
139 
140     if (priv->is_maximized)
141     {
142         gint width;
143 
144         /* Calculate the paned position based on the unmaximized window state,
145          * as that is the state at which the window starts. */
146         gtk_window_get_size (GTK_WINDOW (self), &width, NULL);
147         priv->paned_position -= (width - priv->width);
148     }
149 
150     g_key_file_set_integer (keyfile, "EtApplicationWindow", "paned_position",
151                             priv->paned_position);
152 
153     /* TODO; Use g_key_file_save_to_file() in GLib 2.40. */
154     buffer = g_key_file_to_data (keyfile, &length, NULL);
155 
156     if (!g_file_set_contents (path, buffer, length, &error))
157     {
158         g_warning ("Error saving window state: %s", error->message);
159         g_error_free (error);
160     }
161 
162     g_free (buffer);
163     g_free (path);
164     g_key_file_free (keyfile);
165 }
166 
167 static void
restore_state(EtApplicationWindow * self)168 restore_state (EtApplicationWindow *self)
169 {
170     EtApplicationWindowPrivate *priv;
171     GtkWindow *window;
172     GKeyFile *keyfile;
173     gchar *path;
174     GError *error = NULL;
175 
176     priv = et_application_window_get_instance_private (self);
177     window = GTK_WINDOW (self);
178 
179     keyfile = g_key_file_new ();
180     path = g_build_filename (g_get_user_cache_dir (), PACKAGE_TARNAME,
181                              "state", NULL);
182 
183     if (!g_key_file_load_from_file (keyfile, path, G_KEY_FILE_KEEP_COMMENTS,
184                                     &error))
185     {
186         g_debug ("Error loading window state: %s", error->message);
187         g_error_free (error);
188         g_key_file_free (keyfile);
189         g_free (path);
190         return;
191     }
192 
193     g_free (path);
194 
195     /* Ignore errors, as the default values are fine. */
196     priv->width = g_key_file_get_integer (keyfile, "EtApplicationWindow",
197                                           "width", NULL);
198     priv->height = g_key_file_get_integer (keyfile, "EtApplicationWindow",
199                                            "height", NULL);
200     priv->is_maximized = g_key_file_get_boolean (keyfile,
201                                                  "EtApplicationWindow",
202                                                  "is_maximized", NULL);
203     priv->paned_position = g_key_file_get_integer (keyfile,
204                                                    "EtApplicationWindow",
205                                                    "paned_position", NULL);
206 
207     gtk_window_set_default_size (window, priv->width, priv->height);
208 
209     /* Only set the unmaximized position, as the maximized position should only
210      * be set after the window manager has maximized the window. */
211     gtk_paned_set_position (GTK_PANED (priv->hpaned), priv->paned_position);
212 
213     if (priv->is_maximized)
214     {
215         gtk_window_maximize (window);
216     }
217 
218     g_key_file_free (keyfile);
219 }
220 
221 static gboolean
on_configure_event(GtkWidget * window,GdkEvent * event,gpointer user_data)222 on_configure_event (GtkWidget *window,
223                     GdkEvent *event,
224                     gpointer user_data)
225 {
226     EtApplicationWindow *self;
227     EtApplicationWindowPrivate *priv;
228     GdkEventConfigure *configure_event;
229 
230     self = ET_APPLICATION_WINDOW (window);
231     priv = et_application_window_get_instance_private (self);
232     configure_event = (GdkEventConfigure *)event;
233 
234     if (!priv->is_maximized)
235     {
236         priv->width = configure_event->width;
237         priv->height = configure_event->height;
238     }
239 
240     return GDK_EVENT_PROPAGATE;
241 }
242 
243 static gboolean
on_window_state_event(GtkWidget * window,GdkEvent * event,gpointer user_data)244 on_window_state_event (GtkWidget *window,
245                        GdkEvent *event,
246                        gpointer user_data)
247 {
248     EtApplicationWindow *self;
249     EtApplicationWindowPrivate *priv;
250     GdkEventWindowState *state_event;
251 
252     self = ET_APPLICATION_WINDOW (window);
253     priv = et_application_window_get_instance_private (self);
254     state_event = (GdkEventWindowState *)event;
255 
256     if (state_event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED)
257     {
258         priv->is_maximized = (state_event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) != 0;
259     }
260 
261     return GDK_EVENT_PROPAGATE;
262 }
263 
264 static void
on_paned_notify_position(EtApplicationWindow * self,GParamSpec * pspec,gpointer user_data)265 on_paned_notify_position (EtApplicationWindow *self,
266                           GParamSpec *pspec,
267                           gpointer user_data)
268 {
269     EtApplicationWindowPrivate *priv;
270 
271     priv = et_application_window_get_instance_private (self);
272 
273     priv->paned_position = gtk_paned_get_position (GTK_PANED (priv->hpaned));
274 }
275 
276 File_Tag *
et_application_window_tag_area_create_file_tag(EtApplicationWindow * self)277 et_application_window_tag_area_create_file_tag (EtApplicationWindow *self)
278 {
279     EtApplicationWindowPrivate *priv;
280 
281     g_return_val_if_fail (ET_APPLICATION_WINDOW (self), NULL);
282 
283     priv = et_application_window_get_instance_private (self);
284 
285     return et_tag_area_create_file_tag (ET_TAG_AREA (priv->tag_area));
286 }
287 
288 gboolean
et_application_window_tag_area_display_et_file(EtApplicationWindow * self,const ET_File * ETFile)289 et_application_window_tag_area_display_et_file (EtApplicationWindow *self,
290                                                 const ET_File *ETFile)
291 {
292     EtApplicationWindowPrivate *priv;
293 
294     g_return_val_if_fail (ET_APPLICATION_WINDOW (self), FALSE);
295 
296     priv = et_application_window_get_instance_private (self);
297 
298     return et_tag_area_display_et_file (ET_TAG_AREA (priv->tag_area), ETFile);
299 }
300 
301 /* Clear the entries of tag area. */
302 void
et_application_window_tag_area_clear(EtApplicationWindow * self)303 et_application_window_tag_area_clear (EtApplicationWindow *self)
304 {
305     EtApplicationWindowPrivate *priv;
306 
307     g_return_if_fail (ET_APPLICATION_WINDOW (self));
308 
309     priv = et_application_window_get_instance_private (self);
310 
311     et_tag_area_clear (ET_TAG_AREA (priv->tag_area));
312 }
313 
314 static void
et_application_window_show_cddb_dialog(EtApplicationWindow * self)315 et_application_window_show_cddb_dialog (EtApplicationWindow *self)
316 {
317     EtApplicationWindowPrivate *priv;
318 
319     priv = et_application_window_get_instance_private (self);
320 
321     if (priv->cddb_dialog)
322     {
323         gtk_widget_show (priv->cddb_dialog);
324     }
325     else
326     {
327         priv->cddb_dialog = GTK_WIDGET (et_cddb_dialog_new ());
328         gtk_widget_show_all (priv->cddb_dialog);
329     }
330 }
331 
332 /*
333  * Delete the file ETFile
334  */
335 static gint
delete_file(ET_File * ETFile,gboolean multiple_files,GError ** error)336 delete_file (ET_File *ETFile, gboolean multiple_files, GError **error)
337 {
338     GtkWidget *msgdialog;
339     GtkWidget *msgdialog_check_button = NULL;
340     const gchar *cur_filename;
341     const gchar *cur_filename_utf8;
342     gchar *basename_utf8;
343     gint response;
344     gint stop_loop;
345 
346     g_return_val_if_fail (ETFile != NULL, FALSE);
347     g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
348 
349     /* Filename of the file to delete. */
350     cur_filename      = ((File_Name *)(ETFile->FileNameCur)->data)->value;
351     cur_filename_utf8 = ((File_Name *)(ETFile->FileNameCur)->data)->value_utf8;
352     basename_utf8 = g_path_get_basename (cur_filename_utf8);
353 
354     /*
355      * Remove the file
356      */
357     if (g_settings_get_boolean (MainSettings, "confirm-delete-file")
358         && !SF_HideMsgbox_Delete_File)
359     {
360         if (multiple_files)
361         {
362             GtkWidget *message_area;
363             msgdialog = gtk_message_dialog_new(GTK_WINDOW(MainWindow),
364                                                GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
365                                                GTK_MESSAGE_QUESTION,
366                                                GTK_BUTTONS_NONE,
367                                                _("Do you really want to delete the file ‘%s’?"),
368                                                basename_utf8);
369             message_area = gtk_message_dialog_get_message_area(GTK_MESSAGE_DIALOG(msgdialog));
370             msgdialog_check_button = gtk_check_button_new_with_label(_("Repeat action for the remaining files"));
371             gtk_container_add(GTK_CONTAINER(message_area),msgdialog_check_button);
372             gtk_dialog_add_buttons (GTK_DIALOG (msgdialog), _("_Skip"),
373                                     GTK_RESPONSE_NO, _("_Cancel"),
374                                     GTK_RESPONSE_CANCEL, _("_Delete"),
375                                     GTK_RESPONSE_YES, NULL);
376             gtk_window_set_title(GTK_WINDOW(msgdialog),_("Delete File"));
377             //GTK_TOGGLE_BUTTON(msgbox_check_button)->active = TRUE; // Checked by default
378         }else
379         {
380             msgdialog = gtk_message_dialog_new(GTK_WINDOW(MainWindow),
381                                                GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
382                                                GTK_MESSAGE_QUESTION,
383                                                GTK_BUTTONS_NONE,
384                                                _("Do you really want to delete the file ‘%s’?"),
385                                                basename_utf8);
386             gtk_window_set_title(GTK_WINDOW(msgdialog),_("Delete File"));
387             gtk_dialog_add_buttons (GTK_DIALOG (msgdialog), _("_Cancel"),
388                                     GTK_RESPONSE_NO, _("_Delete"),
389                                     GTK_RESPONSE_YES, NULL);
390         }
391         gtk_dialog_set_default_response (GTK_DIALOG (msgdialog),
392                                          GTK_RESPONSE_YES);
393         SF_ButtonPressed_Delete_File = response = gtk_dialog_run(GTK_DIALOG(msgdialog));
394         if (msgdialog_check_button && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(msgdialog_check_button)))
395             SF_HideMsgbox_Delete_File = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(msgdialog_check_button));
396         gtk_widget_destroy(msgdialog);
397     }else
398     {
399         if (SF_HideMsgbox_Delete_File)
400             response = SF_ButtonPressed_Delete_File;
401         else
402             response = GTK_RESPONSE_YES;
403     }
404 
405     switch (response)
406     {
407         case GTK_RESPONSE_YES:
408         {
409             GFile *cur_file = g_file_new_for_path (cur_filename);
410 
411             if (g_file_delete (cur_file, NULL, error))
412             {
413                 gchar *msg = g_strdup_printf(_("File ‘%s’ deleted"), basename_utf8);
414                 et_application_window_status_bar_message (ET_APPLICATION_WINDOW (MainWindow),
415                                                           msg, FALSE);
416                 g_free(msg);
417                 g_free(basename_utf8);
418                 g_object_unref (cur_file);
419                 g_assert (error == NULL || *error == NULL);
420                 return 1;
421             }
422 
423             /* Error in deleting file. */
424             g_assert (error == NULL || *error != NULL);
425             break;
426         }
427         case GTK_RESPONSE_NO:
428             break;
429         case GTK_RESPONSE_CANCEL:
430         case GTK_RESPONSE_DELETE_EVENT:
431             stop_loop = -1;
432             g_free(basename_utf8);
433             return stop_loop;
434             break;
435         default:
436             g_assert_not_reached ();
437             break;
438     }
439 
440     g_free(basename_utf8);
441     return 0;
442 }
443 
444 static void
on_open_with(GSimpleAction * action,GVariant * variant,gpointer user_data)445 on_open_with (GSimpleAction *action,
446               GVariant *variant,
447               gpointer user_data)
448 {
449     EtApplicationWindowPrivate *priv;
450     EtApplicationWindow *self = ET_APPLICATION_WINDOW (user_data);
451 
452     priv = et_application_window_get_instance_private (self);
453 
454     et_browser_show_open_files_with_dialog (ET_BROWSER (priv->browser));
455 }
456 
457 static void
on_run_player(GSimpleAction * action,GVariant * variant,gpointer user_data)458 on_run_player (GSimpleAction *action,
459                GVariant *variant,
460                gpointer user_data)
461 {
462     EtApplicationWindowPrivate *priv;
463     EtApplicationWindow *self = ET_APPLICATION_WINDOW (user_data);
464 
465     priv = et_application_window_get_instance_private (self);
466 
467     et_browser_run_player_for_selection (ET_BROWSER (priv->browser));
468 }
469 
470 static void
on_invert_selection(GSimpleAction * action,GVariant * variant,gpointer user_data)471 on_invert_selection (GSimpleAction *action,
472                      GVariant *variant,
473                      gpointer user_data)
474 {
475     EtApplicationWindowPrivate *priv;
476     EtApplicationWindow *self = ET_APPLICATION_WINDOW (user_data);
477 
478     priv = et_application_window_get_instance_private (self);
479 
480     et_application_window_update_et_file_from_ui (self);
481 
482     et_browser_invert_selection (ET_BROWSER (priv->browser));
483     et_application_window_update_actions (self);
484 }
485 
486 static void
on_delete(GSimpleAction * action,GVariant * variant,gpointer user_data)487 on_delete (GSimpleAction *action,
488            GVariant *variant,
489            gpointer user_data)
490 {
491     EtApplicationWindow *self;
492     EtApplicationWindowPrivate *priv;
493     GList *selfilelist;
494     GList *rowreflist = NULL;
495     GList *l;
496     gint   progress_bar_index;
497     gint   saving_answer;
498     gint   nb_files_to_delete;
499     gint   nb_files_deleted = 0;
500     gchar *msg;
501     gchar progress_bar_text[30];
502     double fraction;
503     GtkTreeModel *treemodel;
504     GtkTreeRowReference *rowref;
505     GtkTreeSelection *selection;
506     GError *error = NULL;
507 
508     g_return_if_fail (ETCore->ETFileDisplayedList != NULL);
509 
510     self = ET_APPLICATION_WINDOW (user_data);
511     priv = et_application_window_get_instance_private (self);
512 
513     et_application_window_update_et_file_from_ui (self);
514 
515     /* Number of files to save */
516     selection = et_application_window_browser_get_selection (self);
517     nb_files_to_delete = gtk_tree_selection_count_selected_rows (selection);
518 
519     /* Initialize status bar */
520     et_application_window_progress_set_fraction (self, 0.0);
521     progress_bar_index = 0;
522     g_snprintf(progress_bar_text, 30, "%d/%d", progress_bar_index, nb_files_to_delete);
523     et_application_window_progress_set_text (self, progress_bar_text);
524 
525     /* Set to unsensitive all command buttons (except Quit button) */
526     et_application_window_disable_command_actions (self);
527     et_application_window_browser_set_sensitive (self, FALSE);
528     et_application_window_tag_area_set_sensitive (self, FALSE);
529     et_application_window_file_area_set_sensitive (self, FALSE);
530 
531     /* Show msgbox (if needed) to ask confirmation */
532     SF_HideMsgbox_Delete_File = 0;
533 
534     selfilelist = gtk_tree_selection_get_selected_rows (selection, &treemodel);
535 
536     for (l = selfilelist; l != NULL; l = g_list_next (l))
537     {
538         rowref = gtk_tree_row_reference_new (treemodel, l->data);
539         rowreflist = g_list_prepend (rowreflist, rowref);
540     }
541 
542     g_list_free_full (selfilelist, (GDestroyNotify)gtk_tree_path_free);
543     rowreflist = g_list_reverse (rowreflist);
544 
545     for (l = rowreflist; l != NULL; l = g_list_next (l))
546     {
547         GtkTreePath *path;
548         ET_File *ETFile;
549 
550         path = gtk_tree_row_reference_get_path (l->data);
551         ETFile = et_browser_get_et_file_from_path (ET_BROWSER (priv->browser),
552                                                    path);
553         gtk_tree_path_free (path);
554 
555         et_application_window_display_et_file (self, ETFile);
556         et_application_window_browser_select_file_by_et_file (self, ETFile,
557                                                               FALSE);
558         fraction = (++progress_bar_index) / (double) nb_files_to_delete;
559         et_application_window_progress_set_fraction (self, fraction);
560         g_snprintf (progress_bar_text, 30, "%d/%d", progress_bar_index,
561                     nb_files_to_delete);
562         et_application_window_progress_set_text (self, progress_bar_text);
563         /* FIXME: Needed to refresh status bar */
564         while (gtk_events_pending ())
565         {
566             gtk_main_iteration ();
567         }
568 
569         saving_answer = delete_file (ETFile,
570                                      nb_files_to_delete > 1 ? TRUE : FALSE,
571                                      &error);
572 
573         switch (saving_answer)
574         {
575             case 1:
576                 nb_files_deleted += saving_answer;
577                 /* Remove file in the browser (corresponding line in the
578                  * clist). */
579                 et_browser_remove_file (ET_BROWSER (priv->browser), ETFile);
580                 /* Remove file from file list. */
581                 ET_Remove_File_From_File_List (ETFile);
582                 break;
583             case 0:
584                 /* Distinguish between the file being skipped, and there being
585                  * an error during deletion. */
586                 if (error)
587                 {
588                     Log_Print (LOG_ERROR, _("Cannot delete file ‘%s’"),
589                                error->message);
590                     g_clear_error (&error);
591                 }
592                 break;
593             case -1:
594                 /* Stop deleting files + reinit progress bar. */
595                 et_application_window_progress_set_fraction (self, 0.0);
596                 /* To update state of command buttons. */
597                 et_application_window_update_actions (self);
598                 et_application_window_browser_set_sensitive (self, TRUE);
599                 et_application_window_tag_area_set_sensitive (self, TRUE);
600                 et_application_window_file_area_set_sensitive (self, TRUE);
601 
602                 return; /*We stop all actions. */
603             default:
604                 g_assert_not_reached ();
605                 break;
606         }
607     }
608 
609     g_list_free_full (rowreflist, (GDestroyNotify)gtk_tree_row_reference_free);
610 
611     if (nb_files_deleted < nb_files_to_delete)
612         msg = g_strdup (_("Some files were not deleted"));
613     else
614         msg = g_strdup (_("All files have been deleted"));
615 
616     /* It's important to displayed the new item, as it'll check the changes in et_browser_toggle_display_mode. */
617     if (ETCore->ETFileDisplayed)
618     {
619         et_application_window_display_et_file (self, ETCore->ETFileDisplayed);
620     }
621     /*else if (ET_Displayed_File_List_Current())
622         ET_Display_File_Data_To_UI((ET_File *)ET_Displayed_File_List_Current()->data);*/
623 
624     /* Load list... */
625     et_browser_load_file_list (ET_BROWSER (priv->browser),
626                                ETCore->ETFileDisplayedList, NULL);
627     /* Rebuild the list... */
628     /*et_browser_toggle_display_mode (ET_BROWSER (priv->browser));*/
629 
630     /* To update state of command buttons */
631     et_application_window_update_actions (self);
632     et_application_window_browser_set_sensitive (self, TRUE);
633     et_application_window_tag_area_set_sensitive (self, TRUE);
634     et_application_window_file_area_set_sensitive (self, TRUE);
635 
636     et_application_window_progress_set_text (self, "");
637     et_application_window_progress_set_fraction (self, 0.0);
638     et_application_window_status_bar_message (self, msg, TRUE);
639     g_free (msg);
640 
641     return;
642 }
643 
644 static void
on_undo_file_changes(GSimpleAction * action,GVariant * variant,gpointer user_data)645 on_undo_file_changes (GSimpleAction *action,
646                       GVariant *variant,
647                       gpointer user_data)
648 {
649     EtApplicationWindow *self;
650     EtApplicationWindowPrivate *priv;
651     GList *selfilelist = NULL;
652     GList *l;
653     gboolean state = FALSE;
654     ET_File *etfile;
655     GtkTreeSelection *selection;
656 
657     g_return_if_fail (ETCore->ETFileDisplayedList != NULL);
658 
659     self = ET_APPLICATION_WINDOW (user_data);
660     priv = et_application_window_get_instance_private (self);
661 
662     et_application_window_update_et_file_from_ui (self);
663 
664     selection = et_application_window_browser_get_selection (self);
665     selfilelist = gtk_tree_selection_get_selected_rows(selection, NULL);
666 
667     for (l = selfilelist; l != NULL; l = g_list_next (l))
668     {
669         etfile = et_browser_get_et_file_from_path (ET_BROWSER (priv->browser),
670                                                    l->data);
671         state |= ET_Undo_File_Data(etfile);
672     }
673 
674     g_list_free_full (selfilelist, (GDestroyNotify)gtk_tree_path_free);
675 
676     /* Refresh the whole list (faster than file by file) to show changes. */
677     et_application_window_browser_refresh_list (self);
678 
679     /* Display the current file */
680     et_application_window_display_et_file (self, ETCore->ETFileDisplayed);
681     et_application_window_update_actions (self);
682 
683     //ET_Debug_Print_File_List(ETCore->ETFileList,__FILE__,__LINE__,__FUNCTION__);
684 }
685 
686 static void
on_redo_file_changes(GSimpleAction * action,GVariant * variant,gpointer user_data)687 on_redo_file_changes (GSimpleAction *action,
688                       GVariant *variant,
689                       gpointer user_data)
690 {
691     EtApplicationWindow *self;
692     EtApplicationWindowPrivate *priv;
693     GList *selfilelist = NULL;
694     GList *l;
695     gboolean state = FALSE;
696     ET_File *etfile;
697     GtkTreeSelection *selection;
698 
699     g_return_if_fail (ETCore->ETFileDisplayedList != NULL);
700 
701     self = ET_APPLICATION_WINDOW (user_data);
702     priv = et_application_window_get_instance_private (self);
703 
704     et_application_window_update_et_file_from_ui (self);
705 
706     selection = et_application_window_browser_get_selection (ET_APPLICATION_WINDOW (user_data));
707     selfilelist = gtk_tree_selection_get_selected_rows(selection, NULL);
708 
709     for (l = selfilelist; l != NULL; l = g_list_next (l))
710     {
711         etfile = et_browser_get_et_file_from_path (ET_BROWSER (priv->browser),
712                                                    l->data);
713         state |= ET_Redo_File_Data(etfile);
714     }
715 
716     g_list_free_full (selfilelist, (GDestroyNotify)gtk_tree_path_free);
717 
718     /* Refresh the whole list (faster than file by file) to show changes. */
719     et_application_window_browser_refresh_list (ET_APPLICATION_WINDOW (user_data));
720 
721     /* Display the current file */
722     et_application_window_display_et_file (self, ETCore->ETFileDisplayed);
723     et_application_window_update_actions (self);
724 }
725 
726 static void
on_save(GSimpleAction * action,GVariant * variant,gpointer user_data)727 on_save (GSimpleAction *action,
728          GVariant *variant,
729          gpointer user_data)
730 {
731     Action_Save_Selected_Files ();
732 }
733 
734 static void
on_save_force(GSimpleAction * action,GVariant * variant,gpointer user_data)735 on_save_force (GSimpleAction *action,
736                GVariant *variant,
737                gpointer user_data)
738 {
739     Action_Force_Saving_Selected_Files ();
740 }
741 
742 static void
on_find(GSimpleAction * action,GVariant * variant,gpointer user_data)743 on_find (GSimpleAction *action,
744          GVariant *variant,
745          gpointer user_data)
746 {
747     EtApplicationWindow *self;
748     EtApplicationWindowPrivate *priv;
749 
750     self = ET_APPLICATION_WINDOW (user_data);
751     priv = et_application_window_get_instance_private (self);
752 
753     if (priv->search_dialog)
754     {
755         gtk_widget_show (priv->search_dialog);
756     }
757     else
758     {
759         priv->search_dialog = GTK_WIDGET (et_search_dialog_new (GTK_WINDOW (self)));
760         gtk_widget_show_all (priv->search_dialog);
761     }
762 }
763 
764 static void
on_select_all(GSimpleAction * action,GVariant * variant,gpointer user_data)765 on_select_all (GSimpleAction *action,
766                GVariant *variant,
767                gpointer user_data)
768 {
769     EtApplicationWindow *self;
770     EtApplicationWindowPrivate *priv;
771     GtkWidget *focused;
772 
773     self = ET_APPLICATION_WINDOW (user_data);
774     priv = et_application_window_get_instance_private (self);
775 
776     /* Use the currently-focused widget and "select all" as appropriate.
777      * https://bugzilla.gnome.org/show_bug.cgi?id=697515 */
778     focused = gtk_window_get_focus (GTK_WINDOW (user_data));
779 
780     if (GTK_IS_EDITABLE (focused))
781     {
782         gtk_editable_select_region (GTK_EDITABLE (focused), 0, -1);
783     }
784     else if (!et_tag_area_select_all_if_focused (ET_TAG_AREA (priv->tag_area),
785                                                  focused))
786     /* Assume that other widgets should select all in the file view. */
787     {
788         et_application_window_update_et_file_from_ui (self);
789 
790         et_browser_select_all (ET_BROWSER (priv->browser));
791         et_application_window_update_actions (self);
792     }
793 }
794 
795 static void
on_unselect_all(GSimpleAction * action,GVariant * variant,gpointer user_data)796 on_unselect_all (GSimpleAction *action,
797                  GVariant *variant,
798                  gpointer user_data)
799 {
800     EtApplicationWindow *self;
801     EtApplicationWindowPrivate *priv;
802     GtkWidget *focused;
803 
804     self = ET_APPLICATION_WINDOW (user_data);
805     priv = et_application_window_get_instance_private (self);
806 
807     focused = gtk_window_get_focus (GTK_WINDOW (user_data));
808 
809     if (GTK_IS_EDITABLE (focused))
810     {
811         GtkEditable *editable;
812         gint pos;
813 
814         editable = GTK_EDITABLE (focused);
815         pos = gtk_editable_get_position (editable);
816         gtk_editable_select_region (editable, 0, 0);
817         gtk_editable_set_position (editable, pos);
818     }
819     else if (!et_tag_area_unselect_all_if_focused (ET_TAG_AREA (priv->tag_area),
820                                                    focused))
821     /* Assume that other widgets should unselect all in the file view. */
822     {
823         et_application_window_update_et_file_from_ui (self);
824 
825         et_browser_unselect_all (ET_BROWSER (priv->browser));
826 
827         ETCore->ETFileDisplayed = NULL;
828     }
829 }
830 
831 static void
on_undo_last_changes(GSimpleAction * action,GVariant * variant,gpointer user_data)832 on_undo_last_changes (GSimpleAction *action,
833                       GVariant *variant,
834                       gpointer user_data)
835 {
836     EtApplicationWindow *self;
837     ET_File *ETFile;
838 
839     self = ET_APPLICATION_WINDOW (user_data);
840 
841     g_return_if_fail (ETCore->ETFileList != NULL);
842 
843     et_application_window_update_et_file_from_ui (self);
844 
845     ETFile = ET_Undo_History_File_Data ();
846 
847     if (ETFile)
848     {
849         et_application_window_display_et_file (self, ETFile);
850         et_application_window_browser_select_file_by_et_file (self, ETFile,
851                                                               TRUE);
852         et_application_window_browser_refresh_file_in_list (self, ETFile);
853     }
854 
855     et_application_window_update_actions (self);
856 }
857 
858 static void
on_redo_last_changes(GSimpleAction * action,GVariant * variant,gpointer user_data)859 on_redo_last_changes (GSimpleAction *action,
860                       GVariant *variant,
861                       gpointer user_data)
862 {
863     EtApplicationWindow *self;
864     ET_File *ETFile;
865 
866     self = ET_APPLICATION_WINDOW (user_data);
867 
868     g_return_if_fail (ETCore->ETFileDisplayedList != NULL);
869 
870     et_application_window_update_et_file_from_ui (self);
871 
872     ETFile = ET_Redo_History_File_Data ();
873 
874     if (ETFile)
875     {
876         et_application_window_display_et_file (self, ETFile);
877         et_application_window_browser_select_file_by_et_file (self, ETFile,
878                                                               TRUE);
879         et_application_window_browser_refresh_file_in_list (self, ETFile);
880     }
881 
882     et_application_window_update_actions (self);
883 }
884 
885 static void
on_remove_tags(GSimpleAction * action,GVariant * variant,gpointer user_data)886 on_remove_tags (GSimpleAction *action,
887                 GVariant *variant,
888                 gpointer user_data)
889 {
890     EtApplicationWindow *self;
891     EtApplicationWindowPrivate *priv;
892     GList *selfilelist = NULL;
893     GList *l;
894     ET_File *etfile;
895     File_Tag *FileTag;
896     gint progress_bar_index;
897     gint selectcount;
898     double fraction;
899     GtkTreeSelection *selection;
900 
901     g_return_if_fail (ETCore->ETFileDisplayedList != NULL);
902 
903     self = ET_APPLICATION_WINDOW (user_data);
904     priv = et_application_window_get_instance_private (self);
905 
906     et_application_window_update_et_file_from_ui (self);
907 
908     /* Initialize status bar */
909     et_application_window_progress_set_fraction (self, 0.0);
910     selection = et_application_window_browser_get_selection (self);
911     selectcount = gtk_tree_selection_count_selected_rows (selection);
912     progress_bar_index = 0;
913 
914     selfilelist = gtk_tree_selection_get_selected_rows (selection, NULL);
915 
916     for (l = selfilelist; l != NULL; l = g_list_next (l))
917     {
918         etfile = et_browser_get_et_file_from_path (ET_BROWSER (priv->browser),
919                                                    l->data);
920         FileTag = et_file_tag_new ();
921         ET_Manage_Changes_Of_File_Data (etfile, NULL, FileTag);
922 
923         fraction = (++progress_bar_index) / (double) selectcount;
924         et_application_window_progress_set_fraction (self, fraction);
925         /* Needed to refresh status bar */
926         while (gtk_events_pending ())
927         {
928             gtk_main_iteration ();
929         }
930     }
931 
932     g_list_free_full (selfilelist, (GDestroyNotify)gtk_tree_path_free);
933 
934     /* Refresh the whole list (faster than file by file) to show changes. */
935     et_application_window_browser_refresh_list (self);
936 
937     /* Display the current file */
938     et_application_window_display_et_file (self, ETCore->ETFileDisplayed);
939     et_application_window_update_actions (self);
940 
941     et_application_window_progress_set_fraction (self, 0.0);
942     et_application_window_status_bar_message (self,
943                                               _("All tags have been removed"),
944                                               TRUE);
945 }
946 
947 static void
on_preferences(GSimpleAction * action,GVariant * variant,gpointer user_data)948 on_preferences (GSimpleAction *action,
949                 GVariant *variant,
950                 gpointer user_data)
951 {
952     EtApplicationWindow *self;
953     EtApplicationWindowPrivate *priv;
954 
955     self = ET_APPLICATION_WINDOW (user_data);
956     priv = et_application_window_get_instance_private (self);
957 
958     if (priv->preferences_dialog)
959     {
960         gtk_widget_show (priv->preferences_dialog);
961     }
962     else
963     {
964         priv->preferences_dialog = GTK_WIDGET (et_preferences_dialog_new (GTK_WINDOW (self)));
965         gtk_widget_show_all (priv->preferences_dialog);
966     }
967 }
968 
969 static void
on_action_toggle(GSimpleAction * action,GVariant * variant,gpointer user_data)970 on_action_toggle (GSimpleAction *action,
971                   GVariant *variant,
972                   gpointer user_data)
973 {
974     GVariant *state;
975 
976     /* Toggle the current state. */
977     state = g_action_get_state (G_ACTION (action));
978     g_action_change_state (G_ACTION (action),
979                            g_variant_new_boolean (!g_variant_get_boolean (state)));
980     g_variant_unref (state);
981 }
982 
983 static void
on_action_radio(GSimpleAction * action,GVariant * variant,gpointer user_data)984 on_action_radio (GSimpleAction *action,
985                  GVariant *variant,
986                  gpointer user_data)
987 {
988     /* Set the action state to the just-activated state. */
989     g_action_change_state (G_ACTION (action), variant);
990 }
991 
992 static void
on_scanner_change(GSimpleAction * action,GVariant * variant,gpointer user_data)993 on_scanner_change (GSimpleAction *action,
994                    GVariant *variant,
995                    gpointer user_data)
996 {
997     EtApplicationWindow *self;
998     EtApplicationWindowPrivate *priv;
999     gboolean active;
1000 
1001     self = ET_APPLICATION_WINDOW (user_data);
1002     priv = et_application_window_get_instance_private (self);
1003     active = g_variant_get_boolean (variant);
1004 
1005     if (!active)
1006     {
1007         if (priv->scan_dialog)
1008         {
1009             gtk_widget_hide (priv->scan_dialog);
1010         }
1011         else
1012         {
1013             return;
1014         }
1015     }
1016     else
1017     {
1018         if (priv->scan_dialog)
1019         {
1020             gtk_widget_show (priv->scan_dialog);
1021         }
1022         else
1023         {
1024             priv->scan_dialog = GTK_WIDGET (et_scan_dialog_new (GTK_WINDOW (self)));
1025             gtk_widget_show (priv->scan_dialog);
1026         }
1027     }
1028 
1029     g_simple_action_set_state (action, variant);
1030 }
1031 
1032 static void
on_file_artist_view_change(GSimpleAction * action,GVariant * variant,gpointer user_data)1033 on_file_artist_view_change (GSimpleAction *action,
1034                             GVariant *variant,
1035                             gpointer user_data)
1036 {
1037     EtApplicationWindow *self;
1038     EtApplicationWindowPrivate *priv;
1039     const gchar *state;
1040 
1041     self = ET_APPLICATION_WINDOW (user_data);
1042     priv = et_application_window_get_instance_private (self);
1043     state = g_variant_get_string (variant, NULL);
1044 
1045     g_return_if_fail (ETCore->ETFileDisplayedList != NULL);
1046 
1047     et_application_window_update_et_file_from_ui (self);
1048 
1049     if (strcmp (state, "file") == 0)
1050     {
1051         et_browser_set_display_mode (ET_BROWSER (priv->browser),
1052                                      ET_BROWSER_MODE_FILE);
1053     }
1054     else if (strcmp (state, "artist") == 0)
1055     {
1056         et_browser_set_display_mode (ET_BROWSER (priv->browser),
1057                                      ET_BROWSER_MODE_ARTIST);
1058     }
1059     else
1060     {
1061         g_assert_not_reached ();
1062     }
1063 
1064     g_simple_action_set_state (action, variant);
1065 
1066     et_application_window_update_actions (ET_APPLICATION_WINDOW (user_data));
1067 }
1068 
1069 static void
on_collapse_tree(GSimpleAction * action,GVariant * variant,gpointer user_data)1070 on_collapse_tree (GSimpleAction *action,
1071                   GVariant *variant,
1072                   gpointer user_data)
1073 {
1074     EtApplicationWindowPrivate *priv;
1075     EtApplicationWindow *self = ET_APPLICATION_WINDOW (user_data);
1076 
1077     priv = et_application_window_get_instance_private (self);
1078 
1079     et_browser_collapse (ET_BROWSER (priv->browser));
1080 }
1081 
1082 static void
on_reload_tree(GSimpleAction * action,GVariant * variant,gpointer user_data)1083 on_reload_tree (GSimpleAction *action,
1084                 GVariant *variant,
1085                 gpointer user_data)
1086 {
1087     EtApplicationWindowPrivate *priv;
1088     EtApplicationWindow *self = ET_APPLICATION_WINDOW (user_data);
1089 
1090     priv = et_application_window_get_instance_private (self);
1091 
1092     et_browser_reload (ET_BROWSER (priv->browser));
1093 }
1094 
1095 static void
on_reload_directory(GSimpleAction * action,GVariant * variant,gpointer user_data)1096 on_reload_directory (GSimpleAction *action,
1097                      GVariant *variant,
1098                      gpointer user_data)
1099 {
1100     EtApplicationWindowPrivate *priv;
1101     EtApplicationWindow *self = ET_APPLICATION_WINDOW (user_data);
1102 
1103     priv = et_application_window_get_instance_private (self);
1104 
1105     et_browser_reload_directory (ET_BROWSER (priv->browser));
1106 }
1107 
1108 static void
on_set_default_path(GSimpleAction * action,GVariant * variant,gpointer user_data)1109 on_set_default_path (GSimpleAction *action,
1110                      GVariant *variant,
1111                      gpointer user_data)
1112 {
1113     EtApplicationWindow *self;
1114     EtApplicationWindowPrivate *priv;
1115 
1116     self = ET_APPLICATION_WINDOW (user_data);
1117     priv = et_application_window_get_instance_private (self);
1118 
1119     et_browser_set_current_path_default (ET_BROWSER (priv->browser));
1120 }
1121 
1122 static void
on_rename_directory(GSimpleAction * action,GVariant * variant,gpointer user_data)1123 on_rename_directory (GSimpleAction *action,
1124                      GVariant *variant,
1125                      gpointer user_data)
1126 {
1127     EtApplicationWindow *self;
1128     EtApplicationWindowPrivate *priv;
1129 
1130     self = ET_APPLICATION_WINDOW (user_data);
1131     priv = et_application_window_get_instance_private (self);
1132 
1133     et_browser_show_rename_directory_dialog (ET_BROWSER (priv->browser));
1134 }
1135 
1136 static void
on_browse_directory(GSimpleAction * action,GVariant * variant,gpointer user_data)1137 on_browse_directory (GSimpleAction *action,
1138                      GVariant *variant,
1139                      gpointer user_data)
1140 {
1141     EtApplicationWindow *self;
1142     EtApplicationWindowPrivate *priv;
1143 
1144     self = ET_APPLICATION_WINDOW (user_data);
1145     priv = et_application_window_get_instance_private (self);
1146 
1147     et_browser_show_open_directory_with_dialog (ET_BROWSER (priv->browser));
1148 }
1149 
1150 static void
on_show_cddb(GSimpleAction * action,GVariant * variant,gpointer user_data)1151 on_show_cddb (GSimpleAction *action,
1152               GVariant *variant,
1153               gpointer user_data)
1154 {
1155     EtApplicationWindow *self;
1156 
1157     self = ET_APPLICATION_WINDOW (user_data);
1158 
1159     et_application_window_show_cddb_dialog (self);
1160 }
1161 
1162 static void
on_show_load_filenames(GSimpleAction * action,GVariant * variant,gpointer user_data)1163 on_show_load_filenames (GSimpleAction *action,
1164                         GVariant *variant,
1165                         gpointer user_data)
1166 {
1167     EtApplicationWindowPrivate *priv;
1168     EtApplicationWindow *self;
1169 
1170     self = ET_APPLICATION_WINDOW (user_data);
1171     priv = et_application_window_get_instance_private (self);
1172 
1173     if (priv->load_files_dialog)
1174     {
1175         gtk_widget_show (priv->load_files_dialog);
1176     }
1177     else
1178     {
1179         priv->load_files_dialog = GTK_WIDGET (et_load_files_dialog_new (GTK_WINDOW (self)));
1180         gtk_widget_show_all (priv->load_files_dialog);
1181     }
1182 }
1183 
1184 static void
on_show_playlist(GSimpleAction * action,GVariant * variant,gpointer user_data)1185 on_show_playlist (GSimpleAction *action,
1186                   GVariant *variant,
1187                   gpointer user_data)
1188 {
1189     EtApplicationWindowPrivate *priv;
1190     EtApplicationWindow *self;
1191 
1192     self = ET_APPLICATION_WINDOW (user_data);
1193     priv = et_application_window_get_instance_private (self);
1194 
1195     if (priv->playlist_dialog)
1196     {
1197         gtk_widget_show (priv->playlist_dialog);
1198     }
1199     else
1200     {
1201         priv->playlist_dialog = GTK_WIDGET (et_playlist_dialog_new (GTK_WINDOW (self)));
1202         gtk_widget_show_all (priv->playlist_dialog);
1203     }
1204 }
1205 
1206 static void
on_go_home(GSimpleAction * action,GVariant * variant,gpointer user_data)1207 on_go_home (GSimpleAction *action,
1208             GVariant *variant,
1209             gpointer user_data)
1210 {
1211     EtApplicationWindowPrivate *priv;
1212     EtApplicationWindow *self;
1213 
1214     self = ET_APPLICATION_WINDOW (user_data);
1215     priv = et_application_window_get_instance_private (self);
1216 
1217     et_browser_go_home (ET_BROWSER (priv->browser));
1218 }
1219 
1220 static void
on_go_desktop(GSimpleAction * action,GVariant * variant,gpointer user_data)1221 on_go_desktop (GSimpleAction *action,
1222                GVariant *variant,
1223                gpointer user_data)
1224 {
1225     EtApplicationWindowPrivate *priv;
1226     EtApplicationWindow *self;
1227 
1228     self = ET_APPLICATION_WINDOW (user_data);
1229     priv = et_application_window_get_instance_private (self);
1230 
1231     et_browser_go_desktop (ET_BROWSER (priv->browser));
1232 }
1233 
1234 static void
on_go_documents(GSimpleAction * action,GVariant * variant,gpointer user_data)1235 on_go_documents (GSimpleAction *action,
1236                  GVariant *variant,
1237                  gpointer user_data)
1238 {
1239     EtApplicationWindowPrivate *priv;
1240     EtApplicationWindow *self;
1241 
1242     self = ET_APPLICATION_WINDOW (user_data);
1243     priv = et_application_window_get_instance_private (self);
1244 
1245     et_browser_go_documents (ET_BROWSER (priv->browser));
1246 }
1247 
1248 static void
on_go_downloads(GSimpleAction * action,GVariant * variant,gpointer user_data)1249 on_go_downloads (GSimpleAction *action,
1250                  GVariant *variant,
1251                  gpointer user_data)
1252 {
1253     EtApplicationWindowPrivate *priv;
1254     EtApplicationWindow *self;
1255 
1256     self = ET_APPLICATION_WINDOW (user_data);
1257     priv = et_application_window_get_instance_private (self);
1258 
1259     et_browser_go_downloads (ET_BROWSER (priv->browser));
1260 }
1261 
1262 static void
on_go_music(GSimpleAction * action,GVariant * variant,gpointer user_data)1263 on_go_music (GSimpleAction *action,
1264              GVariant *variant,
1265              gpointer user_data)
1266 {
1267     EtApplicationWindowPrivate *priv;
1268     EtApplicationWindow *self;
1269 
1270     self = ET_APPLICATION_WINDOW (user_data);
1271     priv = et_application_window_get_instance_private (self);
1272 
1273     et_browser_go_music (ET_BROWSER (priv->browser));
1274 }
1275 
1276 static void
on_go_parent(GSimpleAction * action,GVariant * variant,gpointer user_data)1277 on_go_parent (GSimpleAction *action,
1278               GVariant *variant,
1279               gpointer user_data)
1280 {
1281     EtApplicationWindowPrivate *priv;
1282     EtApplicationWindow *self;
1283 
1284     self = ET_APPLICATION_WINDOW (user_data);
1285     priv = et_application_window_get_instance_private (self);
1286 
1287     et_browser_go_parent (ET_BROWSER (priv->browser));
1288 }
1289 
1290 static void
on_go_default(GSimpleAction * action,GVariant * variant,gpointer user_data)1291 on_go_default (GSimpleAction *action,
1292                GVariant *variant,
1293                gpointer user_data)
1294 {
1295     EtApplicationWindowPrivate *priv;
1296     EtApplicationWindow *self;
1297 
1298     self = ET_APPLICATION_WINDOW (user_data);
1299     priv = et_application_window_get_instance_private (self);
1300 
1301     et_browser_load_default_dir (ET_BROWSER (priv->browser));
1302 }
1303 
1304 static void
update_ui_for_et_file(EtApplicationWindow * self,ET_File * et_file)1305 update_ui_for_et_file (EtApplicationWindow *self,
1306                        ET_File *et_file)
1307 {
1308     EtApplicationWindowPrivate *priv;
1309 
1310     priv = et_application_window_get_instance_private (self);
1311 
1312     if (et_file)
1313     {
1314         /* To avoid the last line still selected. */
1315         et_browser_unselect_all (ET_BROWSER (priv->browser));
1316         et_application_window_browser_select_file_by_et_file (self, et_file,
1317                                                               TRUE);
1318         et_application_window_display_et_file (self, et_file);
1319     }
1320 
1321     et_application_window_update_actions (self);
1322     et_application_window_scan_dialog_update_previews (self);
1323 
1324     if (!g_settings_get_boolean (MainSettings, "tag-preserve-focus"))
1325     {
1326         et_tag_area_title_grab_focus (ET_TAG_AREA (priv->tag_area));
1327     }
1328 }
1329 
1330 static void
on_go_first(GSimpleAction * action,GVariant * variant,gpointer user_data)1331 on_go_first (GSimpleAction *action,
1332              GVariant *variant,
1333              gpointer user_data)
1334 {
1335     EtApplicationWindow *self;
1336     GList *etfilelist;
1337 
1338     self = ET_APPLICATION_WINDOW (user_data);
1339 
1340     g_return_if_fail (ETCore->ETFileDisplayedList);
1341 
1342     et_application_window_update_et_file_from_ui (self);
1343 
1344     /* Go to the first item of the list */
1345     etfilelist = ET_Displayed_File_List_First ();
1346 
1347     update_ui_for_et_file (self, etfilelist ? (ET_File *)etfilelist->data
1348                                             : NULL);
1349 }
1350 
1351 static void
on_go_previous(GSimpleAction * action,GVariant * variant,gpointer user_data)1352 on_go_previous (GSimpleAction *action,
1353                 GVariant *variant,
1354                 gpointer user_data)
1355 {
1356     EtApplicationWindow *self;
1357     GList *etfilelist;
1358 
1359     self = ET_APPLICATION_WINDOW (user_data);
1360 
1361     g_return_if_fail (ETCore->ETFileDisplayedList
1362                       && ETCore->ETFileDisplayedList->prev);
1363 
1364     et_application_window_update_et_file_from_ui (self);
1365 
1366     /* Go to the prev item of the list */
1367     etfilelist = ET_Displayed_File_List_Previous ();
1368 
1369     update_ui_for_et_file (self, etfilelist ? (ET_File *)etfilelist->data
1370                                             : NULL);
1371 }
1372 
1373 static void
on_go_next(GSimpleAction * action,GVariant * variant,gpointer user_data)1374 on_go_next (GSimpleAction *action,
1375             GVariant *variant,
1376             gpointer user_data)
1377 {
1378     EtApplicationWindow *self;
1379     GList *etfilelist;
1380 
1381     self = ET_APPLICATION_WINDOW (user_data);
1382 
1383     g_return_if_fail (ETCore->ETFileDisplayedList
1384                       && ETCore->ETFileDisplayedList->next);
1385 
1386     et_application_window_update_et_file_from_ui (self);
1387 
1388     /* Go to the next item of the list */
1389     etfilelist = ET_Displayed_File_List_Next ();
1390 
1391     update_ui_for_et_file (self, etfilelist ? (ET_File *)etfilelist->data
1392                                             : NULL);
1393 }
1394 
1395 static void
on_go_last(GSimpleAction * action,GVariant * variant,gpointer user_data)1396 on_go_last (GSimpleAction *action,
1397             GVariant *variant,
1398             gpointer user_data)
1399 {
1400     EtApplicationWindow *self;
1401     GList *etfilelist;
1402 
1403     self = ET_APPLICATION_WINDOW (user_data);
1404 
1405     g_return_if_fail (ETCore->ETFileDisplayedList
1406                       && ETCore->ETFileDisplayedList->next);
1407 
1408     et_application_window_update_et_file_from_ui (self);
1409 
1410     /* Go to the last item of the list */
1411     etfilelist = ET_Displayed_File_List_Last ();
1412 
1413     update_ui_for_et_file (self, etfilelist ? (ET_File *)etfilelist->data
1414                                             : NULL);
1415 }
1416 
1417 static void
on_show_cddb_selection(GSimpleAction * action,GVariant * variant,gpointer user_data)1418 on_show_cddb_selection (GSimpleAction *action,
1419                         GVariant *variant,
1420                         gpointer user_data)
1421 {
1422     EtApplicationWindowPrivate *priv;
1423     EtApplicationWindow *self = ET_APPLICATION_WINDOW (user_data);
1424 
1425     priv = et_application_window_get_instance_private (self);
1426 
1427     et_application_window_show_cddb_dialog (self);
1428     et_cddb_dialog_search_from_selection (ET_CDDB_DIALOG (priv->cddb_dialog));
1429 }
1430 
1431 static void
on_clear_log(GSimpleAction * action,GVariant * variant,gpointer user_data)1432 on_clear_log (GSimpleAction *action,
1433               GVariant *variant,
1434               gpointer user_data)
1435 {
1436     EtApplicationWindowPrivate *priv;
1437     EtApplicationWindow *self = ET_APPLICATION_WINDOW (user_data);
1438 
1439     priv = et_application_window_get_instance_private (self);
1440 
1441     et_log_area_clear (ET_LOG_AREA (priv->log_area));
1442 }
1443 
1444 static void
on_run_player_album(GSimpleAction * action,GVariant * variant,gpointer user_data)1445 on_run_player_album (GSimpleAction *action,
1446                      GVariant *variant,
1447                      gpointer user_data)
1448 {
1449     EtApplicationWindowPrivate *priv;
1450     EtApplicationWindow *self = ET_APPLICATION_WINDOW (user_data);
1451 
1452     priv = et_application_window_get_instance_private (self);
1453 
1454     et_browser_run_player_for_album_list (ET_BROWSER (priv->browser));
1455 }
1456 
1457 static void
on_run_player_artist(GSimpleAction * action,GVariant * variant,gpointer user_data)1458 on_run_player_artist (GSimpleAction *action,
1459                       GVariant *variant,
1460                       gpointer user_data)
1461 {
1462     EtApplicationWindowPrivate *priv;
1463     EtApplicationWindow *self = ET_APPLICATION_WINDOW (user_data);
1464 
1465     priv = et_application_window_get_instance_private (self);
1466 
1467     et_browser_run_player_for_artist_list (ET_BROWSER (priv->browser));
1468 }
1469 
1470 static gboolean
run_audio_player_using_directory(GError ** error)1471 run_audio_player_using_directory (GError **error)
1472 {
1473     GList *l;
1474     GList *file_list = NULL;
1475     gboolean res;
1476 
1477     for (l = ETCore->ETFileList; l != NULL; l = g_list_next (l))
1478     {
1479         ET_File *etfile = (ET_File *)l->data;
1480         const gchar *path = ((File_Name *)etfile->FileNameCur->data)->value;
1481         file_list = g_list_prepend (file_list, g_file_new_for_path (path));
1482     }
1483 
1484     file_list = g_list_reverse (file_list);
1485 
1486     res = et_run_audio_player (file_list, error);
1487 
1488     g_list_free_full (file_list, g_object_unref);
1489 
1490     return res;
1491 }
1492 
1493 static void
on_run_player_directory(GSimpleAction * action,GVariant * variant,gpointer user_data)1494 on_run_player_directory (GSimpleAction *action,
1495                          GVariant *variant,
1496                          gpointer user_data)
1497 {
1498     GError *error = NULL;
1499 
1500     if (!run_audio_player_using_directory (&error))
1501     {
1502         Log_Print (LOG_ERROR, _("Failed to launch program ‘%s’"),
1503                    error->message);
1504         g_error_free (error);
1505     }
1506 }
1507 
1508 static void
on_stop(GSimpleAction * action,GVariant * variant,gpointer user_data)1509 on_stop (GSimpleAction *action,
1510          GVariant *variant,
1511          gpointer user_data)
1512 {
1513     Action_Main_Stop_Button_Pressed ();
1514 }
1515 
1516 static const GActionEntry actions[] =
1517 {
1518     /* File menu. */
1519     { "open-with", on_open_with },
1520     { "run-player", on_run_player },
1521     { "invert-selection", on_invert_selection },
1522     { "delete", on_delete },
1523     { "undo-file-changes", on_undo_file_changes },
1524     { "redo-file-changes", on_redo_file_changes },
1525     { "save", on_save },
1526     { "save-force", on_save_force },
1527     /* Edit menu. */
1528     { "find", on_find },
1529     { "select-all", on_select_all },
1530     { "unselect-all", on_unselect_all },
1531     { "undo-last-changes", on_undo_last_changes },
1532     { "redo-last-changes", on_redo_last_changes },
1533     { "remove-tags", on_remove_tags },
1534     { "preferences", on_preferences },
1535     /* View menu. */
1536     { "scanner", on_action_toggle, NULL, "false", on_scanner_change },
1537     /* { "scan-mode", on_action_radio, NULL, "false", on_scan_mode_change },
1538      * Created from GSetting. */
1539     /* { "sort-mode", on_action_radio, "s", "'ascending-filename'",
1540      * on_sort_mode_change }, Created from GSetting */
1541     { "file-artist-view", on_action_radio, "s", "'file'",
1542       on_file_artist_view_change },
1543     { "collapse-tree", on_collapse_tree },
1544     { "reload-tree", on_reload_tree },
1545     { "reload-directory", on_reload_directory },
1546     /* { "browse-show-hidden", on_action_toggle, NULL, "true",
1547       on_browse_show_hidden_change }, Created from GSetting. */
1548     /* Browser menu. */
1549     { "set-default-path", on_set_default_path },
1550     { "rename-directory", on_rename_directory },
1551     { "browse-directory", on_browse_directory },
1552     /* { "browse-subdir", on_browse_subdir }, Created from GSetting. */
1553     /* Miscellaneous menu. */
1554     { "show-cddb", on_show_cddb },
1555     { "show-load-filenames", on_show_load_filenames },
1556     { "show-playlist", on_show_playlist },
1557     /* Go menu. */
1558     { "go-home", on_go_home },
1559     { "go-desktop", on_go_desktop },
1560     { "go-documents", on_go_documents },
1561     { "go-downloads", on_go_downloads },
1562     { "go-music", on_go_music },
1563     { "go-parent", on_go_parent },
1564     { "go-default", on_go_default },
1565     { "go-first", on_go_first },
1566     { "go-previous", on_go_previous },
1567     { "go-next", on_go_next },
1568     { "go-last", on_go_last },
1569     /* Popup menus. */
1570     { "show-cddb-selection", on_show_cddb_selection },
1571     { "clear-log", on_clear_log },
1572     { "run-player-album", on_run_player_album },
1573     { "run-player-artist", on_run_player_artist },
1574     { "run-player-directory", on_run_player_directory },
1575     /* Toolbar. */
1576     { "stop", on_stop }
1577 };
1578 
1579 static void
et_application_window_dispose(GObject * object)1580 et_application_window_dispose (GObject *object)
1581 {
1582     EtApplicationWindow *self;
1583     EtApplicationWindowPrivate *priv;
1584 
1585     self = ET_APPLICATION_WINDOW (object);
1586     priv = et_application_window_get_instance_private (self);
1587 
1588     save_state (self);
1589 
1590     if (ETCore)
1591     {
1592         ET_Core_Free ();
1593     }
1594 
1595     if (priv->cddb_dialog)
1596     {
1597         gtk_widget_destroy (priv->cddb_dialog);
1598         priv->cddb_dialog = NULL;
1599     }
1600 
1601     if (priv->load_files_dialog)
1602     {
1603         gtk_widget_destroy (priv->load_files_dialog);
1604         priv->load_files_dialog = NULL;
1605     }
1606 
1607     if (priv->playlist_dialog)
1608     {
1609         gtk_widget_destroy (priv->playlist_dialog);
1610         priv->playlist_dialog = NULL;
1611     }
1612 
1613     if (priv->preferences_dialog)
1614     {
1615         gtk_widget_destroy (priv->preferences_dialog);
1616         priv->preferences_dialog = NULL;
1617     }
1618 
1619     if (priv->scan_dialog)
1620     {
1621         gtk_widget_destroy (priv->scan_dialog);
1622         priv->scan_dialog = NULL;
1623     }
1624 
1625     if (priv->search_dialog)
1626     {
1627         gtk_widget_destroy (priv->search_dialog);
1628         priv->search_dialog = NULL;
1629     }
1630 
1631     if (priv->cursor)
1632     {
1633         g_object_unref (priv->cursor);
1634         priv->cursor = NULL;
1635     }
1636 
1637     G_OBJECT_CLASS (et_application_window_parent_class)->dispose (object);
1638 }
1639 
1640 static void
et_application_window_init(EtApplicationWindow * self)1641 et_application_window_init (EtApplicationWindow *self)
1642 {
1643     EtApplicationWindowPrivate *priv;
1644     GAction *action;
1645     GtkWindow *window;
1646     GtkWidget *main_vbox;
1647     GtkWidget *hbox;
1648     GtkWidget *grid;
1649 
1650     priv = et_application_window_get_instance_private (self);
1651 
1652     g_action_map_add_action_entries (G_ACTION_MAP (self), actions,
1653                                      G_N_ELEMENTS (actions), self);
1654 
1655     action = g_settings_create_action (MainSettings, "browse-show-hidden");
1656     g_action_map_add_action (G_ACTION_MAP (self), action);
1657     g_object_unref (action);
1658     action = g_settings_create_action (MainSettings, "browse-subdir");
1659     g_action_map_add_action (G_ACTION_MAP (self), action);
1660     g_object_unref (action);
1661     action = g_settings_create_action (MainSettings, "scan-mode");
1662     g_action_map_add_action (G_ACTION_MAP (self), action);
1663     g_object_unref (action);
1664     action = g_settings_create_action (MainSettings, "sort-mode");
1665     g_action_map_add_action (G_ACTION_MAP (self), action);
1666     g_object_unref (action);
1667 
1668     window = GTK_WINDOW (self);
1669 
1670     gtk_window_set_icon_name (window, PACKAGE_TARNAME);
1671     gtk_window_set_title (window, _(PACKAGE_NAME));
1672 
1673     g_signal_connect (self, "configure-event",
1674                       G_CALLBACK (on_configure_event), NULL);
1675     g_signal_connect (self, "delete-event",
1676                       G_CALLBACK (on_main_window_delete_event), NULL);
1677     g_signal_connect (self, "window-state-event",
1678                       G_CALLBACK (on_window_state_event), NULL);
1679 
1680     /* Mainvbox for Menu bar + Tool bar + "Browser Area & FileArea & TagArea" + Log Area + "Status bar & Progress bar" */
1681     main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
1682     gtk_container_add (GTK_CONTAINER (self), main_vbox);
1683 
1684     /* Menu bar and tool bar. */
1685     {
1686         GtkBuilder *builder;
1687         GtkWidget *toolbar;
1688 
1689         builder = gtk_builder_new_from_resource ("/org/gnome/EasyTAG/toolbar.ui");
1690 
1691         toolbar = GTK_WIDGET (gtk_builder_get_object (builder, "main_toolbar"));
1692         gtk_box_pack_start (GTK_BOX (main_vbox), toolbar, FALSE, FALSE, 0);
1693 
1694         g_object_unref (builder);
1695     }
1696 
1697     /* The two panes: BrowserArea on the left, FileArea+TagArea on the right */
1698     priv->hpaned = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
1699 
1700     /* Browser (Tree + File list + Entry) */
1701     priv->browser = GTK_WIDGET (et_browser_new ());
1702     gtk_paned_pack1 (GTK_PANED (priv->hpaned), priv->browser, TRUE, TRUE);
1703 
1704     /* Vertical box for FileArea + TagArea */
1705     grid = gtk_grid_new ();
1706     gtk_orientable_set_orientation (GTK_ORIENTABLE (grid),
1707                                     GTK_ORIENTATION_VERTICAL);
1708     gtk_paned_pack2 (GTK_PANED (priv->hpaned), grid, FALSE, FALSE);
1709 
1710     /* File */
1711     priv->file_area = et_file_area_new ();
1712     gtk_container_add (GTK_CONTAINER (grid), priv->file_area);
1713 
1714     /* Tag */
1715     priv->tag_area = et_tag_area_new ();
1716     gtk_container_add (GTK_CONTAINER (grid), priv->tag_area);
1717 
1718     /* Update the stored paned position whenever it is changed (after configure
1719      * and windows state events have been processed). */
1720     g_signal_connect_swapped (priv->hpaned, "notify::position",
1721                               G_CALLBACK (on_paned_notify_position), self);
1722     restore_state (self);
1723 
1724     /* Vertical pane for Browser Area + FileArea + TagArea */
1725     priv->vpaned = gtk_paned_new (GTK_ORIENTATION_VERTICAL);
1726     gtk_box_pack_start (GTK_BOX (main_vbox), priv->vpaned, TRUE, TRUE, 0);
1727     gtk_paned_pack1 (GTK_PANED (priv->vpaned), priv->hpaned, TRUE,
1728                      FALSE);
1729 
1730 
1731     /* Log */
1732     priv->log_area = et_log_area_new ();
1733     gtk_paned_pack2 (GTK_PANED (priv->vpaned), priv->log_area, FALSE, FALSE);
1734 
1735     /* Horizontal box for Status bar + Progress bar */
1736     hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
1737     gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
1738     gtk_widget_show (hbox);
1739 
1740     /* Status bar */
1741     priv->status_bar = et_status_bar_new ();
1742     gtk_box_pack_start (GTK_BOX (hbox), priv->status_bar, TRUE, TRUE, 0);
1743 
1744     /* Progress bar */
1745     priv->progress_bar = et_progress_bar_new ();
1746     gtk_box_pack_end (GTK_BOX (hbox), priv->progress_bar, FALSE, FALSE, 0);
1747 
1748     gtk_widget_show_all (GTK_WIDGET (main_vbox));
1749 
1750     /* Bind the setting after the log area has been shown, to avoid
1751      * force-enabling the visibility on startup. */
1752     g_settings_bind (MainSettings, "log-show", priv->log_area, "visible",
1753                      G_SETTINGS_BIND_DEFAULT);
1754 }
1755 
1756 static void
et_application_window_class_init(EtApplicationWindowClass * klass)1757 et_application_window_class_init (EtApplicationWindowClass *klass)
1758 {
1759     G_OBJECT_CLASS (klass)->dispose = et_application_window_dispose;
1760 }
1761 
1762 /*
1763  * et_application_window_new:
1764  *
1765  * Create a new EtApplicationWindow instance.
1766  *
1767  * Returns: a new #EtApplicationWindow
1768  */
1769 EtApplicationWindow *
et_application_window_new(GtkApplication * application)1770 et_application_window_new (GtkApplication *application)
1771 {
1772     g_return_val_if_fail (GTK_IS_APPLICATION (application), NULL);
1773 
1774     return g_object_new (ET_TYPE_APPLICATION_WINDOW, "application",
1775                          application, NULL);
1776 }
1777 
1778 void
et_application_window_scan_dialog_update_previews(EtApplicationWindow * self)1779 et_application_window_scan_dialog_update_previews (EtApplicationWindow *self)
1780 {
1781     EtApplicationWindowPrivate *priv;
1782 
1783     g_return_if_fail (self != NULL);
1784 
1785     priv = et_application_window_get_instance_private (self);
1786 
1787     if (priv->scan_dialog)
1788     {
1789         et_scan_dialog_update_previews (ET_SCAN_DIALOG (priv->scan_dialog));
1790     }
1791 }
1792 
1793 void
et_application_window_progress_set_fraction(EtApplicationWindow * self,gdouble fraction)1794 et_application_window_progress_set_fraction (EtApplicationWindow *self,
1795                                              gdouble fraction)
1796 {
1797     EtApplicationWindowPrivate *priv;
1798 
1799     g_return_if_fail (ET_APPLICATION_WINDOW (self));
1800 
1801     priv = et_application_window_get_instance_private (self);
1802 
1803     gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (priv->progress_bar),
1804                                    fraction);
1805 }
1806 
1807 void
et_application_window_progress_set_text(EtApplicationWindow * self,const gchar * text)1808 et_application_window_progress_set_text (EtApplicationWindow *self,
1809                                          const gchar *text)
1810 {
1811     EtApplicationWindowPrivate *priv;
1812 
1813     g_return_if_fail (ET_APPLICATION_WINDOW (self));
1814 
1815     priv = et_application_window_get_instance_private (self);
1816 
1817     gtk_progress_bar_set_text (GTK_PROGRESS_BAR (priv->progress_bar), text);
1818 }
1819 
1820 void
et_application_window_status_bar_message(EtApplicationWindow * self,const gchar * message,gboolean with_timer)1821 et_application_window_status_bar_message (EtApplicationWindow *self,
1822                                           const gchar *message,
1823                                           gboolean with_timer)
1824 {
1825     EtApplicationWindowPrivate *priv;
1826 
1827     g_return_if_fail (ET_APPLICATION_WINDOW (self));
1828 
1829     priv = et_application_window_get_instance_private (self);
1830 
1831     et_status_bar_message (ET_STATUS_BAR (priv->status_bar), message,
1832                            with_timer);
1833 }
1834 
1835 GtkWidget *
et_application_window_get_log_area(EtApplicationWindow * self)1836 et_application_window_get_log_area (EtApplicationWindow *self)
1837 {
1838     EtApplicationWindowPrivate *priv;
1839 
1840     g_return_val_if_fail (self != NULL, NULL);
1841 
1842     priv = et_application_window_get_instance_private (self);
1843 
1844     return priv->log_area;
1845 }
1846 
1847 void
et_application_window_show_preferences_dialog_scanner(EtApplicationWindow * self)1848 et_application_window_show_preferences_dialog_scanner (EtApplicationWindow *self)
1849 {
1850     EtApplicationWindowPrivate *priv;
1851 
1852     g_return_if_fail (ET_APPLICATION_WINDOW (self));
1853 
1854     priv = et_application_window_get_instance_private (self);
1855 
1856     if (!priv->preferences_dialog)
1857     {
1858         priv->preferences_dialog = GTK_WIDGET (et_preferences_dialog_new (GTK_WINDOW (self)));
1859     }
1860 
1861     et_preferences_dialog_show_scanner (ET_PREFERENCES_DIALOG (priv->preferences_dialog));
1862 }
1863 
1864 void
et_application_window_browser_toggle_display_mode(EtApplicationWindow * self)1865 et_application_window_browser_toggle_display_mode (EtApplicationWindow *self)
1866 {
1867     EtApplicationWindowPrivate *priv;
1868     GVariant *variant;
1869 
1870     priv = et_application_window_get_instance_private (self);
1871 
1872     variant = g_action_group_get_action_state (G_ACTION_GROUP (self),
1873                                                "file-artist-view");
1874 
1875     if (strcmp (g_variant_get_string (variant, NULL), "file") == 0)
1876     {
1877         et_browser_set_display_mode (ET_BROWSER (priv->browser),
1878                                      ET_BROWSER_MODE_FILE);
1879     }
1880     else if (strcmp (g_variant_get_string (variant, NULL), "artist") == 0)
1881     {
1882         et_browser_set_display_mode (ET_BROWSER (priv->browser),
1883                                      ET_BROWSER_MODE_ARTIST);
1884     }
1885     else
1886     {
1887         g_assert_not_reached ();
1888     }
1889 
1890     g_variant_unref (variant);
1891 }
1892 
1893 void
et_application_window_browser_set_sensitive(EtApplicationWindow * self,gboolean sensitive)1894 et_application_window_browser_set_sensitive (EtApplicationWindow *self,
1895                                              gboolean sensitive)
1896 {
1897     EtApplicationWindowPrivate *priv;
1898 
1899     g_return_if_fail (ET_APPLICATION_WINDOW (self));
1900 
1901     priv = et_application_window_get_instance_private (self);
1902 
1903     g_return_if_fail (priv->browser != NULL);
1904 
1905     et_browser_set_sensitive (ET_BROWSER (priv->browser), sensitive);
1906 }
1907 
1908 void
et_application_window_browser_clear(EtApplicationWindow * self)1909 et_application_window_browser_clear (EtApplicationWindow *self)
1910 {
1911     EtApplicationWindowPrivate *priv;
1912 
1913     g_return_if_fail (ET_APPLICATION_WINDOW (self));
1914 
1915     priv = et_application_window_get_instance_private (self);
1916 
1917     g_return_if_fail (priv->browser != NULL);
1918 
1919     et_browser_clear (ET_BROWSER (priv->browser));
1920 }
1921 
1922 void
et_application_window_browser_clear_album_model(EtApplicationWindow * self)1923 et_application_window_browser_clear_album_model (EtApplicationWindow *self)
1924 {
1925     EtApplicationWindowPrivate *priv;
1926 
1927     g_return_if_fail (ET_APPLICATION_WINDOW (self));
1928 
1929     priv = et_application_window_get_instance_private (self);
1930 
1931     g_return_if_fail (priv->browser != NULL);
1932 
1933     et_browser_clear_album_model (ET_BROWSER (priv->browser));
1934 }
1935 
1936 void
et_application_window_browser_clear_artist_model(EtApplicationWindow * self)1937 et_application_window_browser_clear_artist_model (EtApplicationWindow *self)
1938 {
1939     EtApplicationWindowPrivate *priv;
1940 
1941     g_return_if_fail (ET_APPLICATION_WINDOW (self));
1942 
1943     priv = et_application_window_get_instance_private (self);
1944 
1945     g_return_if_fail (priv->browser != NULL);
1946 
1947     et_browser_clear_artist_model (ET_BROWSER (priv->browser));
1948 }
1949 
1950 void
et_application_window_select_dir(EtApplicationWindow * self,GFile * file)1951 et_application_window_select_dir (EtApplicationWindow *self,
1952                                   GFile *file)
1953 {
1954     EtApplicationWindowPrivate *priv;
1955 
1956     priv = et_application_window_get_instance_private (self);
1957 
1958     et_browser_select_dir (ET_BROWSER (priv->browser), file);
1959 }
1960 
1961 /*
1962  * Select a file in the "main list" using the ETFile address of each item.
1963  */
1964 void
et_application_window_select_file_by_et_file(EtApplicationWindow * self,ET_File * ETFile)1965 et_application_window_select_file_by_et_file (EtApplicationWindow *self,
1966                                               ET_File *ETFile)
1967 {
1968     if (!ETCore->ETFileDisplayedList)
1969         return;
1970 
1971     et_application_window_update_et_file_from_ui (self);
1972 
1973     /* Display the item */
1974     et_application_window_browser_select_file_by_et_file (self, ETFile, TRUE);
1975     /* Just to update 'ETFileDisplayedList'. */
1976     ET_Displayed_File_List_By_Etfile (ETFile);
1977     et_application_window_display_et_file (self, ETFile);
1978 
1979     et_application_window_update_actions (self);
1980     et_application_window_scan_dialog_update_previews (self);
1981 }
1982 
1983 /*
1984  * Save displayed filename into list if it had been changed. Generates also an history list for undo/redo.
1985  *  - ETFile : the current etfile that we want to save,
1986  *  - FileName : where is 'temporary' saved the new filename.
1987  *
1988  * Note : it builds new filename (with path) from strings encoded into file system
1989  *        encoding, not UTF-8 (it preserves file system encoding of parent directories).
1990  */
1991 static void
et_application_window_update_file_name_from_ui(EtApplicationWindow * self,const ET_File * ETFile,File_Name * FileName)1992 et_application_window_update_file_name_from_ui (EtApplicationWindow *self,
1993                                                 const ET_File *ETFile,
1994                                                 File_Name *FileName)
1995 {
1996     gchar *filename_new = NULL;
1997     gchar *dirname = NULL;
1998     gchar *filename;
1999     const gchar *filename_utf8;
2000     gchar *extension;
2001 
2002     g_return_if_fail (ETFile != NULL && FileName != NULL);
2003 
2004     filename_utf8 = et_application_window_file_area_get_filename (self);
2005     filename = filename_from_display (filename_utf8);
2006 
2007     if (!filename)
2008     {
2009         /* If conversion fails... */
2010         GtkWidget *msgdialog;
2011         gchar *filename_escaped_utf8 = g_strescape(filename_utf8, NULL);
2012         msgdialog = gtk_message_dialog_new (GTK_WINDOW (self),
2013                                             GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
2014                                             GTK_MESSAGE_ERROR,
2015                                             GTK_BUTTONS_CLOSE,
2016                                             _("Could not convert filename ‘%s’ to system filename encoding"),
2017                                             filename_escaped_utf8);
2018         gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (msgdialog),
2019                                                   _("Try setting the environment variable G_FILENAME_ENCODING."));
2020         gtk_window_set_title (GTK_WINDOW (msgdialog),
2021                               _("Filename translation"));
2022 
2023         gtk_dialog_run (GTK_DIALOG (msgdialog));
2024         gtk_widget_destroy (msgdialog);
2025         g_free (filename_escaped_utf8);
2026         return;
2027     }
2028 
2029     /* Get the current path to the file. */
2030     dirname = g_path_get_dirname (((File_Name *)ETFile->FileNameNew->data)->value);
2031 
2032     /* Convert filename extension (lower or upper). */
2033     extension = ET_File_Format_File_Extension (ETFile);
2034 
2035     // Check length of filename (limit ~255 characters)
2036     //ET_File_Name_Check_Length(ETFile,filename);
2037 
2038     /* Filename (in file system encoding!). */
2039     if (!et_str_empty (filename))
2040     {
2041         /* Regenerate the new filename (without path). */
2042         filename_new = g_strconcat (filename, extension, NULL);
2043     }
2044     else
2045     {
2046         /* Keep the 'last' filename (if a 'blank' filename was entered in the
2047          * fileentry for example). */
2048         filename_new = g_path_get_basename (((File_Name *)ETFile->FileNameNew->data)->value);
2049     }
2050 
2051     g_free (filename);
2052     g_free (extension);
2053 
2054     et_file_name_set_from_components (FileName, filename_new, dirname,
2055                                       g_settings_get_boolean (MainSettings,
2056                                                               "rename-replace-illegal-chars"));
2057 
2058     g_free (filename_new);
2059     g_free (dirname);
2060     return;
2061 }
2062 
2063 void
et_application_window_update_et_file_from_ui(EtApplicationWindow * self)2064 et_application_window_update_et_file_from_ui (EtApplicationWindow *self)
2065 {
2066     const ET_File_Description *description;
2067     ET_File *et_file;
2068     File_Name *FileName;
2069     File_Tag  *FileTag;
2070     const gchar *cur_filename_utf8;
2071 
2072     if (!ETCore->ETFileDisplayed)
2073     {
2074         return;
2075     }
2076 
2077     et_file = ETCore->ETFileDisplayed;
2078 
2079     g_return_if_fail (et_file != NULL && et_file->FileNameCur != NULL
2080                       && et_file->FileNameCur->data != NULL);
2081 
2082     /* Save the current displayed data */
2083     cur_filename_utf8 = ((File_Name *)((GList *)et_file->FileNameCur)->data)->value_utf8;
2084     description = et_file->ETFileDescription;
2085 
2086     /* Save filename and generate undo for filename. */
2087     FileName = et_file_name_new ();
2088     et_application_window_update_file_name_from_ui (self, et_file, FileName);
2089 
2090     switch (description->TagType)
2091     {
2092 #ifdef ENABLE_MP3
2093         case ID3_TAG:
2094 #endif
2095 #ifdef ENABLE_OGG
2096         case OGG_TAG:
2097 #endif
2098 #ifdef ENABLE_FLAC
2099         case FLAC_TAG:
2100 #endif
2101 #ifdef ENABLE_MP4
2102         case MP4_TAG:
2103 #endif
2104 #ifdef ENABLE_WAVPACK
2105         case WAVPACK_TAG:
2106 #endif
2107 #ifdef ENABLE_OPUS
2108         case OPUS_TAG:
2109 #endif
2110         case APE_TAG:
2111             FileTag = et_application_window_tag_area_create_file_tag (self);
2112             et_file_tag_copy_other_into (et_file->FileTag->data, FileTag);
2113             break;
2114 #ifndef ENABLE_MP3
2115         case ID3_TAG:
2116 #endif
2117 #ifndef ENABLE_OGG
2118         case OGG_TAG:
2119 #endif
2120 #ifndef ENABLE_FLAC
2121         case FLAC_TAG:
2122 #endif
2123 #ifndef ENABLE_MP4
2124         case MP4_TAG:
2125 #endif
2126 #ifndef ENABLE_WAVPACK
2127         case WAVPACK_TAG:
2128 #endif
2129 #ifndef ENABLE_OPUS
2130         case OPUS_TAG:
2131 #endif
2132         case UNKNOWN_TAG:
2133         default:
2134             FileTag = et_file_tag_new ();
2135             Log_Print (LOG_ERROR,
2136                        "FileTag: Undefined tag type %d for file %s.",
2137                        (gint)description->TagType, cur_filename_utf8);
2138             break;
2139     }
2140 
2141     /*
2142      * Generate undo for the file and the main undo list.
2143      * If no changes detected, FileName and FileTag item are deleted.
2144      */
2145     ET_Manage_Changes_Of_File_Data (et_file, FileName, FileTag);
2146 
2147     /* Refresh file into browser list */
2148     et_application_window_browser_refresh_file_in_list (self, et_file);
2149 }
2150 
2151 static void
et_file_header_fields_free(EtFileHeaderFields * fields)2152 et_file_header_fields_free (EtFileHeaderFields *fields)
2153 {
2154     g_free (fields->version);
2155     g_free (fields->bitrate);
2156     g_free (fields->samplerate);
2157     g_free (fields->mode);
2158     g_free (fields->size);
2159     g_free (fields->duration);
2160     g_slice_free (EtFileHeaderFields, fields);
2161 }
2162 
2163 static void
et_application_window_display_file_name(EtApplicationWindow * self,const ET_File * ETFile)2164 et_application_window_display_file_name (EtApplicationWindow *self,
2165                                          const ET_File *ETFile)
2166 {
2167     const gchar *new_filename_utf8;
2168     gchar *dirname_utf8;
2169     gchar *text;
2170 
2171     g_return_if_fail (ETFile != NULL);
2172 
2173     new_filename_utf8 = ((File_Name *)((GList *)ETFile->FileNameNew)->data)->value_utf8;
2174 
2175     /*
2176      * Set the path to the file into BrowserEntry (dirbrowser)
2177      */
2178     dirname_utf8 = g_path_get_dirname (new_filename_utf8);
2179     et_application_window_browser_entry_set_text (self, dirname_utf8);
2180 
2181     // And refresh the number of files in this directory
2182     text = g_strdup_printf (ngettext ("One file", "%u files",
2183                                       et_file_list_get_n_files_in_path (ETCore->ETFileList,
2184                                                                         dirname_utf8)),
2185                             et_file_list_get_n_files_in_path (ETCore->ETFileList,
2186                                                               dirname_utf8));
2187     et_application_window_browser_label_set_text (self, text);
2188     g_free(dirname_utf8);
2189     g_free(text);
2190 }
2191 
2192 /*
2193  * "Default" way to display File Info to the user interface.
2194  */
2195 static EtFileHeaderFields *
et_header_fields_new_from_unknown(const ET_File * ETFile)2196 et_header_fields_new_from_unknown (const ET_File *ETFile)
2197 {
2198     EtFileHeaderFields *fields;
2199     ET_File_Info *info;
2200     gchar *time  = NULL;
2201     gchar *time1 = NULL;
2202     gchar *size  = NULL;
2203     gchar *size1 = NULL;
2204 
2205     info = ETFile->ETFileInfo;
2206     fields = g_slice_new (EtFileHeaderFields);
2207 
2208     fields->description = _("File");
2209 
2210     /* MPEG, Layer versions */
2211     fields->version = g_strdup_printf ("%d, Layer %" G_GSIZE_FORMAT,
2212                                        info->version, info->layer);
2213 
2214     /* Bitrate */
2215     fields->bitrate = g_strdup_printf (_("%d kb/s"), info->bitrate);
2216 
2217     /* Samplerate */
2218     fields->samplerate = g_strdup_printf (_("%d Hz"), info->samplerate);
2219 
2220     /* Mode */
2221     fields->mode = g_strdup_printf ("%d", info->mode);
2222 
2223     /* Size */
2224     size = g_format_size (info->size);
2225     size1 = g_format_size (ETCore->ETFileDisplayedList_TotalSize);
2226     fields->size = g_strdup_printf ("%s (%s)", size, size1);
2227     g_free (size);
2228     g_free (size1);
2229 
2230     /* Duration */
2231     time = Convert_Duration (info->duration);
2232     time1 = Convert_Duration (ETCore->ETFileDisplayedList_TotalDuration);
2233     fields->duration = g_strdup_printf ("%s (%s)", time, time1);
2234     g_free (time);
2235     g_free (time1);
2236 
2237     return fields;
2238 }
2239 
2240 /*
2241  * Display information of the file (Position + Header + Tag) to the user interface.
2242  * Before doing it, it saves data of the file currently displayed
2243  */
2244 void
et_application_window_display_et_file(EtApplicationWindow * self,ET_File * ETFile)2245 et_application_window_display_et_file (EtApplicationWindow *self,
2246                                        ET_File *ETFile)
2247 {
2248     const ET_File_Description *description;
2249     const gchar *cur_filename_utf8;
2250     gchar *msg;
2251     EtFileHeaderFields *fields;
2252 
2253     g_return_if_fail (ETFile != NULL &&
2254                       ((GList *)ETFile->FileNameCur)->data != NULL);
2255                       /* For the case where ETFile is an "empty" structure. */
2256 
2257     cur_filename_utf8 = ((File_Name *)((GList *)ETFile->FileNameCur)->data)->value_utf8;
2258     description = ETFile->ETFileDescription;
2259 
2260     /* Save the current displayed file */
2261     ETCore->ETFileDisplayed = ETFile;
2262 
2263     /* Display position in list + show/hide icon if file writable/read_only (cur_filename) */
2264     et_application_window_file_area_set_file_fields (self, ETFile);
2265 
2266     /* Display filename (and his path) (value in FileNameNew) */
2267     et_application_window_display_file_name (self, ETFile);
2268 
2269     /* Display tag data */
2270     et_application_window_tag_area_display_et_file (self, ETFile);
2271 
2272     /* Display controls in tag area */
2273     et_application_window_tag_area_display_controls (self, ETFile);
2274 
2275     /* Display file data, header data and file type */
2276     switch (description->FileType)
2277     {
2278 #if defined ENABLE_MP3 && defined ENABLE_ID3LIB
2279         case MP3_FILE:
2280         case MP2_FILE:
2281             fields = et_mpeg_header_display_file_info_to_ui (ETFile);
2282             et_application_window_file_area_set_header_fields (self, fields);
2283             et_mpeg_file_header_fields_free (fields);
2284             break;
2285 #endif
2286 #ifdef ENABLE_OGG
2287         case OGG_FILE:
2288             fields = et_ogg_header_display_file_info_to_ui (ETFile);
2289             et_application_window_file_area_set_header_fields (self, fields);
2290             et_ogg_file_header_fields_free (fields);
2291             break;
2292 #endif
2293 #ifdef ENABLE_SPEEX
2294         case SPEEX_FILE:
2295             fields = et_ogg_header_display_file_info_to_ui (ETFile);
2296             et_application_window_file_area_set_header_fields (self, fields);
2297             et_ogg_file_header_fields_free (fields);
2298             break;
2299 #endif
2300 #ifdef ENABLE_FLAC
2301         case FLAC_FILE:
2302             fields = et_flac_header_display_file_info_to_ui (ETFile);
2303             et_application_window_file_area_set_header_fields (self, fields);
2304             et_flac_file_header_fields_free (fields);
2305             break;
2306 #endif
2307         case MPC_FILE:
2308             fields = et_mpc_header_display_file_info_to_ui (ETFile);
2309             et_application_window_file_area_set_header_fields (self, fields);
2310             et_mpc_file_header_fields_free (fields);
2311             break;
2312         case MAC_FILE:
2313             fields = et_mac_header_display_file_info_to_ui (ETFile);
2314             et_application_window_file_area_set_header_fields (self, fields);
2315             et_mac_file_header_fields_free (fields);
2316             break;
2317 #ifdef ENABLE_MP4
2318         case MP4_FILE:
2319             fields = et_mp4_header_display_file_info_to_ui (ETFile);
2320             et_application_window_file_area_set_header_fields (self, fields);
2321             et_mp4_file_header_fields_free (fields);
2322             break;
2323 #endif
2324 #ifdef ENABLE_WAVPACK
2325         case WAVPACK_FILE:
2326             fields = et_wavpack_header_display_file_info_to_ui (ETFile);
2327             et_application_window_file_area_set_header_fields (self, fields);
2328             et_wavpack_file_header_fields_free (fields);
2329             break;
2330 #endif
2331 #ifdef ENABLE_OPUS
2332         case OPUS_FILE:
2333             fields = et_opus_header_display_file_info_to_ui (ETFile);
2334             et_application_window_file_area_set_header_fields (self, fields);
2335             et_opus_file_header_fields_free (fields);
2336             break;
2337 #endif
2338         case OFR_FILE:
2339 #if !defined ENABLE_MP3 && !defined ENABLE_ID3LIB
2340         case MP3_FILE:
2341         case MP2_FILE:
2342 #endif
2343 #ifndef ENABLE_OGG
2344         case OGG_FILE:
2345 #endif
2346 #ifndef ENABLE_SPEEX
2347         case SPEEX_FILE:
2348 #endif
2349 #ifndef ENABLE_FLAC
2350         case FLAC_FILE:
2351 #endif
2352 #ifndef ENABLE_MP4
2353         case MP4_FILE:
2354 #endif
2355 #ifndef ENABLE_WAVPACK
2356         case WAVPACK_FILE:
2357 #endif
2358 #ifndef ENABLE_OPUS
2359         case OPUS_FILE:
2360 #endif
2361         case UNKNOWN_FILE:
2362         default:
2363             /* Default displaying. */
2364             fields = et_header_fields_new_from_unknown (ETFile);
2365             et_application_window_file_area_set_header_fields (self, fields);
2366             et_file_header_fields_free (fields);
2367             Log_Print (LOG_ERROR,
2368                        "ETFileInfo: Undefined file type %d for file %s.",
2369                        (gint)description->FileType, cur_filename_utf8);
2370             break;
2371     }
2372 
2373     msg = g_strdup_printf (_("File: ‘%s’"), cur_filename_utf8);
2374     et_application_window_status_bar_message (self, msg, FALSE);
2375     g_free (msg);
2376 }
2377 
2378 GFile *
et_application_window_get_current_path(EtApplicationWindow * self)2379 et_application_window_get_current_path (EtApplicationWindow *self)
2380 {
2381     EtApplicationWindowPrivate *priv;
2382 
2383     g_return_val_if_fail (ET_APPLICATION_WINDOW (self), NULL);
2384 
2385     priv = et_application_window_get_instance_private (self);
2386 
2387     return et_browser_get_current_path (ET_BROWSER (priv->browser));
2388 }
2389 
2390 GtkWidget *
et_application_window_get_scan_dialog(EtApplicationWindow * self)2391 et_application_window_get_scan_dialog (EtApplicationWindow *self)
2392 {
2393     EtApplicationWindowPrivate *priv;
2394 
2395     g_return_val_if_fail (self != NULL, NULL);
2396 
2397     priv = et_application_window_get_instance_private (self);
2398 
2399     return priv->scan_dialog;
2400 }
2401 
2402 void
et_application_window_apply_changes(EtApplicationWindow * self)2403 et_application_window_apply_changes (EtApplicationWindow *self)
2404 {
2405     EtApplicationWindowPrivate *priv;
2406 
2407     g_return_if_fail (ET_APPLICATION_WINDOW (self));
2408 
2409     priv = et_application_window_get_instance_private (self);
2410 
2411     if (priv->scan_dialog)
2412     {
2413         et_scan_dialog_apply_changes (ET_SCAN_DIALOG (priv->scan_dialog));
2414     }
2415 
2416     if (priv->search_dialog)
2417     {
2418         et_search_dialog_apply_changes (ET_SEARCH_DIALOG (priv->search_dialog));
2419     }
2420 }
2421 
2422 /*
2423  * Disable (FALSE) / Enable (TRUE) all user widgets in the tag area
2424  */
2425 void
et_application_window_tag_area_set_sensitive(EtApplicationWindow * self,gboolean sensitive)2426 et_application_window_tag_area_set_sensitive (EtApplicationWindow *self,
2427                                               gboolean sensitive)
2428 {
2429     EtApplicationWindowPrivate *priv;
2430 
2431     g_return_if_fail (ET_APPLICATION_WINDOW (self));
2432 
2433     priv = et_application_window_get_instance_private (self);
2434 
2435     g_return_if_fail (priv->tag_area != NULL);
2436 
2437     /* TAG Area (entries + buttons). */
2438     gtk_widget_set_sensitive (gtk_bin_get_child (GTK_BIN (priv->tag_area)),
2439                               sensitive);
2440 }
2441 
2442 void
et_application_window_file_area_clear(EtApplicationWindow * self)2443 et_application_window_file_area_clear (EtApplicationWindow *self)
2444 {
2445     EtApplicationWindowPrivate *priv;
2446 
2447     g_return_if_fail (ET_APPLICATION_WINDOW (self));
2448 
2449     priv = et_application_window_get_instance_private (self);
2450 
2451     et_file_area_clear (ET_FILE_AREA (priv->file_area));
2452 }
2453 
2454 const gchar *
et_application_window_file_area_get_filename(EtApplicationWindow * self)2455 et_application_window_file_area_get_filename (EtApplicationWindow *self)
2456 {
2457     EtApplicationWindowPrivate *priv;
2458 
2459     g_return_val_if_fail (ET_APPLICATION_WINDOW (self), NULL);
2460 
2461     priv = et_application_window_get_instance_private (self);
2462 
2463     return et_file_area_get_filename (ET_FILE_AREA (priv->file_area));
2464 }
2465 
2466 void
et_application_window_file_area_set_file_fields(EtApplicationWindow * self,const ET_File * ETFile)2467 et_application_window_file_area_set_file_fields (EtApplicationWindow *self,
2468                                                  const ET_File *ETFile)
2469 {
2470     EtApplicationWindowPrivate *priv;
2471 
2472     g_return_if_fail (ET_APPLICATION_WINDOW (self));
2473 
2474     priv = et_application_window_get_instance_private (self);
2475 
2476     et_file_area_set_file_fields (ET_FILE_AREA (priv->file_area), ETFile);
2477 }
2478 
2479 void
et_application_window_file_area_set_header_fields(EtApplicationWindow * self,EtFileHeaderFields * fields)2480 et_application_window_file_area_set_header_fields (EtApplicationWindow *self,
2481                                                    EtFileHeaderFields *fields)
2482 {
2483     EtApplicationWindowPrivate *priv;
2484 
2485     g_return_if_fail (ET_APPLICATION_WINDOW (self));
2486 
2487     priv = et_application_window_get_instance_private (self);
2488 
2489     et_file_area_set_header_fields (ET_FILE_AREA (priv->file_area), fields);
2490 }
2491 
2492 /*
2493  * Disable (FALSE) / Enable (TRUE) all user widgets in the file area
2494  */
2495 void
et_application_window_file_area_set_sensitive(EtApplicationWindow * self,gboolean sensitive)2496 et_application_window_file_area_set_sensitive (EtApplicationWindow *self,
2497                                                gboolean sensitive)
2498 {
2499     EtApplicationWindowPrivate *priv;
2500 
2501     g_return_if_fail (ET_APPLICATION_WINDOW (self));
2502 
2503     priv = et_application_window_get_instance_private (self);
2504 
2505     g_return_if_fail (priv->file_area != NULL);
2506 
2507     /* File Area. */
2508     gtk_widget_set_sensitive (gtk_bin_get_child (GTK_BIN (priv->file_area)),
2509                               sensitive);
2510 }
2511 
2512 static void
set_action_state(EtApplicationWindow * self,const gchar * action_name,gboolean enabled)2513 set_action_state (EtApplicationWindow *self,
2514                   const gchar *action_name,
2515                   gboolean enabled)
2516 {
2517     GSimpleAction *action;
2518 
2519     action = G_SIMPLE_ACTION (g_action_map_lookup_action (G_ACTION_MAP (self),
2520                                                           action_name));
2521 
2522     if (action == NULL)
2523     {
2524         g_error ("Unable to find action '%s' in application window",
2525                  action_name);
2526     }
2527 
2528     g_simple_action_set_enabled (action, enabled);
2529 }
2530 
2531 /* et_application_window_disable_command_actions:
2532  * Disable buttons when saving files (do not disable Quit button).
2533  */
2534 void
et_application_window_disable_command_actions(EtApplicationWindow * self)2535 et_application_window_disable_command_actions (EtApplicationWindow *self)
2536 {
2537     GtkDialog *dialog;
2538 
2539     dialog = GTK_DIALOG (et_application_window_get_scan_dialog (self));
2540 
2541     /* Scanner Window */
2542     if (dialog)
2543     {
2544         gtk_dialog_set_response_sensitive (dialog, GTK_RESPONSE_APPLY, FALSE);
2545     }
2546 
2547     /* "File" menu commands */
2548     set_action_state (self, "open-with", FALSE);
2549     set_action_state (self, "invert-selection", FALSE);
2550     set_action_state (self, "delete", FALSE);
2551     set_action_state (self, "go-first", FALSE);
2552     set_action_state (self, "go-previous", FALSE);
2553     set_action_state (self, "go-next", FALSE);
2554     set_action_state (self, "go-last", FALSE);
2555     set_action_state (self, "remove-tags", FALSE);
2556     set_action_state (self, "undo-file-changes", FALSE);
2557     set_action_state (self, "redo-file-changes", FALSE);
2558     set_action_state (self, "save", FALSE);
2559     set_action_state (self, "save-force", FALSE);
2560     set_action_state (self, "undo-last-changes", FALSE);
2561     set_action_state (self, "redo-last-changes", FALSE);
2562 
2563     /* FIXME: "Scanner" menu commands */
2564     /*set_action_state (self, "scan-mode", FALSE);*/
2565 }
2566 
2567 
2568 /* et_application_window_update_actions:
2569  * Set to sensitive/unsensitive the state of each button into
2570  * the commands area and menu items in function of state of the "main list".
2571  */
2572 void
et_application_window_update_actions(EtApplicationWindow * self)2573 et_application_window_update_actions (EtApplicationWindow *self)
2574 {
2575     GtkDialog *dialog;
2576 
2577     dialog = GTK_DIALOG (et_application_window_get_scan_dialog (self));
2578 
2579     if (!ETCore->ETFileDisplayedList)
2580     {
2581         /* No file found */
2582 
2583         /* File and Tag frames */
2584         et_application_window_file_area_set_sensitive (self, FALSE);
2585         et_application_window_tag_area_set_sensitive (self, FALSE);
2586 
2587         /* Tool bar buttons (the others are covered by the menu) */
2588         set_action_state (self, "stop", FALSE);
2589 
2590         /* Scanner Window */
2591         if (dialog)
2592         {
2593             gtk_dialog_set_response_sensitive (dialog, GTK_RESPONSE_APPLY,
2594                                                FALSE);
2595         }
2596 
2597         /* Menu commands */
2598         set_action_state (self, "open-with", FALSE);
2599         set_action_state (self, "invert-selection", FALSE);
2600         set_action_state (self, "delete", FALSE);
2601         /* FIXME: set_action_state (self, "sort-mode", FALSE); */
2602         set_action_state (self, "go-previous", FALSE);
2603         set_action_state (self, "go-next", FALSE);
2604         set_action_state (self, "go-first", FALSE);
2605         set_action_state (self, "go-last", FALSE);
2606         set_action_state (self, "remove-tags", FALSE);
2607         set_action_state (self, "undo-file-changes", FALSE);
2608         set_action_state (self, "redo-file-changes", FALSE);
2609         set_action_state (self, "save", FALSE);
2610         set_action_state (self, "save-force", FALSE);
2611         set_action_state (self, "undo-last-changes", FALSE);
2612         set_action_state (self, "redo-last-changes", FALSE);
2613         set_action_state (self, "find", FALSE);
2614         set_action_state (self, "show-load-filenames", FALSE);
2615         set_action_state (self, "show-playlist", FALSE);
2616         set_action_state (self, "run-player", FALSE);
2617         /* FIXME set_action_state (self, "scan-mode", FALSE);*/
2618         set_action_state (self, "file-artist-view", FALSE);
2619 
2620         return;
2621     }else
2622     {
2623         GList *selfilelist = NULL;
2624         ET_File *etfile;
2625         gboolean has_undo = FALSE;
2626         gboolean has_redo = FALSE;
2627         //gboolean has_to_save = FALSE;
2628         GtkTreeSelection *selection;
2629 
2630         /* File and Tag frames */
2631         et_application_window_file_area_set_sensitive (self, TRUE);
2632         et_application_window_tag_area_set_sensitive (self, TRUE);
2633 
2634         /* Tool bar buttons */
2635         set_action_state (self, "stop", FALSE);
2636 
2637         /* Scanner Window */
2638         if (dialog)
2639         {
2640             gtk_dialog_set_response_sensitive (dialog, GTK_RESPONSE_APPLY,
2641                                                TRUE);
2642         }
2643 
2644         /* Commands into menu */
2645         set_action_state (self, "open-with", TRUE);
2646         set_action_state (self, "invert-selection", TRUE);
2647         set_action_state (self, "delete", TRUE);
2648         /* FIXME set_action_state (self, "sort-mode", TRUE); */
2649         set_action_state (self, "remove-tags", TRUE);
2650         set_action_state (self, "find", TRUE);
2651         set_action_state (self, "show-load-filenames", TRUE);
2652         set_action_state (self, "show-playlist", TRUE);
2653         set_action_state (self, "run-player", TRUE);
2654         /* FIXME set_action_state (self, "scan-mode", TRUE); */
2655         set_action_state (self, "file-artist-view", TRUE);
2656 
2657         /* Check if one of the selected files has undo or redo data */
2658         {
2659             GList *l;
2660 
2661             selection = et_application_window_browser_get_selection (self);
2662             selfilelist = gtk_tree_selection_get_selected_rows(selection, NULL);
2663 
2664             for (l = selfilelist; l != NULL; l = g_list_next (l))
2665             {
2666                 etfile = et_application_window_browser_get_et_file_from_path (self,
2667                                                                               l->data);
2668                 has_undo    |= ET_File_Data_Has_Undo_Data(etfile);
2669                 has_redo    |= ET_File_Data_Has_Redo_Data(etfile);
2670                 /* has_to_save |= et_file_check_saved (etfile); */
2671                 if ((has_undo && has_redo /*&& has_to_save*/) || !l->next) // Useless to check the other files
2672                     break;
2673             }
2674 
2675             g_list_free_full (selfilelist, (GDestroyNotify)gtk_tree_path_free);
2676         }
2677 
2678         /* Enable undo commands if there are undo data */
2679         if (has_undo)
2680         {
2681             set_action_state (self, "undo-file-changes", TRUE);
2682         }
2683         else
2684         {
2685             set_action_state (self, "undo-file-changes", FALSE);
2686         }
2687 
2688         /* Enable redo commands if there are redo data */
2689         if (has_redo)
2690         {
2691             set_action_state (self, "redo-file-changes", TRUE);
2692         }
2693         else
2694         {
2695             set_action_state (self, "redo-file-changes", FALSE);
2696         }
2697 
2698         /* Enable save file command if file has been changed */
2699         // Desactivated because problem with only one file in the list, as we can't change the selected file => can't mark file as changed
2700         /*if (has_to_save)
2701             ui_widget_set_sensitive(MENU_FILE, AM_SAVE, FALSE);
2702         else*/
2703             set_action_state (self, "save", TRUE);
2704 
2705         set_action_state (self, "save-force", TRUE);
2706 
2707         /* Enable undo command if there are data into main undo list (history list) */
2708         if (et_history_list_has_undo (ETCore->ETHistoryFileList))
2709         {
2710             set_action_state (self, "undo-last-changes", TRUE);
2711         }
2712         else
2713         {
2714             set_action_state (self, "undo-last-changes", FALSE);
2715         }
2716 
2717         /* Enable redo commands if there are data into main redo list (history list) */
2718         if (et_history_list_has_redo (ETCore->ETHistoryFileList))
2719         {
2720             set_action_state (self, "redo-last-changes", TRUE);
2721         }
2722         else
2723         {
2724             set_action_state (self, "redo-last-changes", FALSE);
2725         }
2726 
2727         {
2728             GVariant *variant;
2729             const gchar *state;
2730 
2731             variant = g_action_group_get_action_state (G_ACTION_GROUP (self),
2732                                                      "file-artist-view");
2733 
2734             state = g_variant_get_string (variant, NULL);
2735 
2736             if (strcmp (state, "artist") == 0)
2737             {
2738                 set_action_state (self, "collapse-tree", FALSE);
2739                 set_action_state (self, "reload-tree", FALSE);
2740             }
2741             else if (strcmp (state, "file") == 0)
2742             {
2743                 set_action_state (self, "collapse-tree", TRUE);
2744                 set_action_state (self, "reload-tree", TRUE);
2745             }
2746             else
2747             {
2748                 g_assert_not_reached ();
2749             }
2750 
2751             g_variant_unref (variant);
2752         }
2753     }
2754 
2755     if (!ETCore->ETFileDisplayedList->prev)    /* Is it the 1st item ? */
2756     {
2757         set_action_state (self, "go-previous", FALSE);
2758         set_action_state (self, "go-first", FALSE);
2759     }
2760     else
2761     {
2762         set_action_state (self, "go-previous", TRUE);
2763         set_action_state (self, "go-first", TRUE);
2764     }
2765 
2766     if (!ETCore->ETFileDisplayedList->next)    /* Is it the last item ? */
2767     {
2768         set_action_state (self, "go-next", FALSE);
2769         set_action_state (self, "go-last", FALSE);
2770     }
2771     else
2772     {
2773         set_action_state (self, "go-next", TRUE);
2774         set_action_state (self, "go-last", TRUE);
2775     }
2776 }
2777 
2778 void
et_application_window_set_busy_cursor(EtApplicationWindow * self)2779 et_application_window_set_busy_cursor (EtApplicationWindow *self)
2780 {
2781     EtApplicationWindowPrivate *priv;
2782 
2783     g_return_if_fail (ET_APPLICATION_WINDOW (self));
2784 
2785     priv = et_application_window_get_instance_private (self);
2786 
2787     if (!priv->cursor)
2788     {
2789         priv->cursor = gdk_cursor_new_for_display (gdk_window_get_display (gtk_widget_get_window (GTK_WIDGET (self))),
2790                                                    GDK_WATCH);
2791 
2792     }
2793 
2794     gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (self)),
2795                            priv->cursor);
2796 }
2797 
2798 void
et_application_window_set_normal_cursor(EtApplicationWindow * self)2799 et_application_window_set_normal_cursor (EtApplicationWindow *self)
2800 {
2801     g_return_if_fail (ET_APPLICATION_WINDOW (self));
2802 
2803     /* Back to standard cursor */
2804     gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (self)), NULL);
2805 }
2806 
2807 /*
2808  * Display controls according the kind of tag... (Hide some controls if not available for a tag type)
2809  */
2810 void
et_application_window_tag_area_display_controls(EtApplicationWindow * self,const ET_File * ETFile)2811 et_application_window_tag_area_display_controls (EtApplicationWindow *self,
2812                                                  const ET_File *ETFile)
2813 {
2814     EtApplicationWindowPrivate *priv;
2815 
2816     g_return_if_fail (ET_APPLICATION_WINDOW (self));
2817     g_return_if_fail (ETFile != NULL && ETFile->ETFileDescription != NULL);
2818 
2819     priv = et_application_window_get_instance_private (self);
2820 
2821     et_tag_area_update_controls (ET_TAG_AREA (priv->tag_area), ETFile);
2822 }
2823 
2824 void
et_application_window_browser_entry_set_text(EtApplicationWindow * self,const gchar * text)2825 et_application_window_browser_entry_set_text (EtApplicationWindow *self,
2826                                               const gchar *text)
2827 {
2828     EtApplicationWindowPrivate *priv;
2829 
2830     priv = et_application_window_get_instance_private (self);
2831 
2832     et_browser_entry_set_text (ET_BROWSER (priv->browser), text);
2833 }
2834 
2835 void
et_application_window_browser_label_set_text(EtApplicationWindow * self,const gchar * text)2836 et_application_window_browser_label_set_text (EtApplicationWindow *self,
2837                                               const gchar *text)
2838 {
2839     EtApplicationWindowPrivate *priv;
2840 
2841     priv = et_application_window_get_instance_private (self);
2842 
2843     et_browser_label_set_text (ET_BROWSER (priv->browser), text);
2844 }
2845 
2846 ET_File *
et_application_window_browser_get_et_file_from_path(EtApplicationWindow * self,GtkTreePath * path)2847 et_application_window_browser_get_et_file_from_path (EtApplicationWindow *self,
2848                                                      GtkTreePath *path)
2849 {
2850     EtApplicationWindowPrivate *priv;
2851 
2852     priv = et_application_window_get_instance_private (self);
2853 
2854     return et_browser_get_et_file_from_path (ET_BROWSER (priv->browser), path);
2855 }
2856 
2857 ET_File *
et_application_window_browser_get_et_file_from_iter(EtApplicationWindow * self,GtkTreeIter * iter)2858 et_application_window_browser_get_et_file_from_iter (EtApplicationWindow *self,
2859                                                      GtkTreeIter *iter)
2860 {
2861     EtApplicationWindowPrivate *priv;
2862 
2863     priv = et_application_window_get_instance_private (self);
2864 
2865     return et_browser_get_et_file_from_iter (ET_BROWSER (priv->browser), iter);
2866 }
2867 
2868 GtkTreeSelection *
et_application_window_browser_get_selection(EtApplicationWindow * self)2869 et_application_window_browser_get_selection (EtApplicationWindow *self)
2870 {
2871     EtApplicationWindowPrivate *priv;
2872 
2873     priv = et_application_window_get_instance_private (self);
2874 
2875     return et_browser_get_selection (ET_BROWSER (priv->browser));
2876 }
2877 
2878 GtkTreeViewColumn *
et_application_window_browser_get_column_for_column_id(EtApplicationWindow * self,gint column_id)2879 et_application_window_browser_get_column_for_column_id (EtApplicationWindow *self,
2880                                                         gint column_id)
2881 {
2882     EtApplicationWindowPrivate *priv;
2883 
2884     priv = et_application_window_get_instance_private (self);
2885 
2886     return et_browser_get_column_for_column_id (ET_BROWSER (priv->browser),
2887                                                 column_id);
2888 }
2889 
2890 GtkSortType
et_application_window_browser_get_sort_order_for_column_id(EtApplicationWindow * self,gint column_id)2891 et_application_window_browser_get_sort_order_for_column_id (EtApplicationWindow *self,
2892                                                             gint column_id)
2893 {
2894     EtApplicationWindowPrivate *priv;
2895 
2896     priv = et_application_window_get_instance_private (self);
2897 
2898     return et_browser_get_sort_order_for_column_id (ET_BROWSER (priv->browser),
2899                                                     column_id);
2900 }
2901 
2902 void
et_application_window_browser_select_file_by_iter_string(EtApplicationWindow * self,const gchar * iter_string,gboolean select)2903 et_application_window_browser_select_file_by_iter_string (EtApplicationWindow *self,
2904                                                           const gchar *iter_string,
2905                                                           gboolean select)
2906 {
2907     EtApplicationWindowPrivate *priv;
2908 
2909     priv = et_application_window_get_instance_private (self);
2910 
2911     et_browser_select_file_by_iter_string (ET_BROWSER (priv->browser),
2912                                            iter_string, select);
2913 }
2914 
2915 void
et_application_window_browser_select_file_by_et_file(EtApplicationWindow * self,const ET_File * file,gboolean select)2916 et_application_window_browser_select_file_by_et_file (EtApplicationWindow *self,
2917                                                       const ET_File *file,
2918                                                       gboolean select)
2919 {
2920     EtApplicationWindowPrivate *priv;
2921 
2922     priv = et_application_window_get_instance_private (self);
2923 
2924     return et_browser_select_file_by_et_file (ET_BROWSER (priv->browser), file,
2925                                               select);
2926 }
2927 
2928 GtkTreePath *
et_application_window_browser_select_file_by_et_file2(EtApplicationWindow * self,const ET_File * file,gboolean select,GtkTreePath * start_path)2929 et_application_window_browser_select_file_by_et_file2 (EtApplicationWindow *self,
2930                                                        const ET_File *file,
2931                                                        gboolean select,
2932                                                        GtkTreePath *start_path)
2933 {
2934     EtApplicationWindowPrivate *priv;
2935 
2936     priv = et_application_window_get_instance_private (self);
2937 
2938     return et_browser_select_file_by_et_file2 (ET_BROWSER (priv->browser),
2939                                                file, select, start_path);
2940 }
2941 
2942 ET_File *
et_application_window_browser_select_file_by_dlm(EtApplicationWindow * self,const gchar * string,gboolean select)2943 et_application_window_browser_select_file_by_dlm (EtApplicationWindow *self,
2944                                                   const gchar *string,
2945                                                   gboolean select)
2946 {
2947     EtApplicationWindowPrivate *priv;
2948 
2949     priv = et_application_window_get_instance_private (self);
2950 
2951     return et_browser_select_file_by_dlm (ET_BROWSER (priv->browser), string,
2952                                           select);
2953 }
2954 
2955 void
et_application_window_browser_unselect_all(EtApplicationWindow * self)2956 et_application_window_browser_unselect_all (EtApplicationWindow *self)
2957 {
2958     EtApplicationWindowPrivate *priv;
2959 
2960     priv = et_application_window_get_instance_private (self);
2961 
2962     et_application_window_update_et_file_from_ui (self);
2963 
2964     et_browser_unselect_all (ET_BROWSER (priv->browser));
2965     ETCore->ETFileDisplayed = NULL;
2966 }
2967 
2968 void
et_application_window_browser_refresh_list(EtApplicationWindow * self)2969 et_application_window_browser_refresh_list (EtApplicationWindow *self)
2970 {
2971     EtApplicationWindowPrivate *priv;
2972 
2973     g_return_if_fail (ET_APPLICATION_WINDOW (self));
2974 
2975     priv = et_application_window_get_instance_private (self);
2976 
2977     et_browser_refresh_list (ET_BROWSER (priv->browser));
2978 }
2979 
2980 void
et_application_window_browser_refresh_file_in_list(EtApplicationWindow * self,const ET_File * file)2981 et_application_window_browser_refresh_file_in_list (EtApplicationWindow *self,
2982                                                     const ET_File *file)
2983 {
2984     EtApplicationWindowPrivate *priv;
2985 
2986     g_return_if_fail (ET_APPLICATION_WINDOW (self));
2987 
2988     priv = et_application_window_get_instance_private (self);
2989 
2990     et_browser_refresh_file_in_list (ET_BROWSER (priv->browser), file);
2991 }
2992 
2993 static void
quit_confirmed(EtApplicationWindow * self)2994 quit_confirmed (EtApplicationWindow *self)
2995 {
2996     /* Save the configuration when exiting. */
2997     et_application_window_apply_changes (self);
2998 
2999     /* Quit EasyTAG. */
3000     Log_Print (LOG_OK, _("Normal exit"));
3001 
3002     gtk_widget_destroy (GTK_WIDGET (self));
3003 }
3004 
3005 static void
save_and_quit(EtApplicationWindow * self)3006 save_and_quit (EtApplicationWindow *self)
3007 {
3008     /* Save modified tags */
3009     if (Save_All_Files_With_Answer (FALSE) == -1)
3010         return;
3011 
3012     quit_confirmed (self);
3013 }
3014 
3015 void
et_application_window_quit(EtApplicationWindow * self)3016 et_application_window_quit (EtApplicationWindow *self)
3017 {
3018     GtkWidget *msgbox;
3019     gint response;
3020 
3021     /* If you change the displayed data and quit immediately */
3022     et_application_window_update_et_file_from_ui (self);
3023 
3024     /* Check if all files have been saved before exit */
3025     if (g_settings_get_boolean (MainSettings, "confirm-when-unsaved-files")
3026         && et_file_list_check_all_saved (ETCore->ETFileList) != TRUE)
3027     {
3028         /* Some files haven't been saved */
3029         msgbox = gtk_message_dialog_new (GTK_WINDOW (self),
3030                                          GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
3031                                          GTK_MESSAGE_QUESTION,
3032                                          GTK_BUTTONS_NONE,
3033                                          "%s",
3034                                          _("Some files have been modified but not saved"));
3035         gtk_dialog_add_buttons (GTK_DIALOG (msgbox), _("_Discard"),
3036                                 GTK_RESPONSE_NO, _("_Cancel"),
3037                                 GTK_RESPONSE_CANCEL, _("_Save"),
3038                                 GTK_RESPONSE_YES, NULL);
3039         gtk_dialog_set_default_response (GTK_DIALOG (msgbox),
3040                                          GTK_RESPONSE_YES);
3041         gtk_window_set_title (GTK_WINDOW (msgbox), _("Quit"));
3042         gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (msgbox),
3043                                                   "%s",
3044                                                   _("Do you want to save them before quitting?"));
3045         response = gtk_dialog_run (GTK_DIALOG (msgbox));
3046         gtk_widget_destroy (msgbox);
3047 
3048         switch (response)
3049         {
3050             case GTK_RESPONSE_YES:
3051                 save_and_quit (self);
3052                 break;
3053             case GTK_RESPONSE_NO:
3054                 quit_confirmed (self);
3055                 break;
3056             case GTK_RESPONSE_CANCEL:
3057             case GTK_RESPONSE_DELETE_EVENT:
3058                 return;
3059                 break;
3060             default:
3061                 g_assert_not_reached ();
3062                 break;
3063         }
3064 
3065     }
3066     else
3067     {
3068         quit_confirmed (self);
3069     }
3070 }
3071