1 /* EasyTAG - tag editor for audio files
2 * Copyright (C) 2014 David King <amigadave@amigadave.com>
3 * Copyright (C) 2000-2003 Jerome Couderc <easytag@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the Free
7 * Software Foundation; either version 2 of the License, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 51
17 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20 /* Some parts of this browser are taken from:
21 * XMMS - Cross-platform multimedia player
22 * Copyright (C) 1998-1999 Peter Alm, Mikael Alm, Olle Hallnas,
23 * Thomas Nilsson and 4Front Technologies
24 */
25
26 #include "config.h"
27
28 #include "browser.h"
29
30 #include <gdk/gdkkeysyms.h>
31 #include <glib/gi18n.h>
32 #include <glib/gstdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <errno.h>
36
37 #include "application_window.h"
38 #include "charset.h"
39 #include "dlm.h"
40 #include "easytag.h"
41 #include "et_core.h"
42 #include "file_list.h"
43 #include "scan_dialog.h"
44 #include "log.h"
45 #include "misc.h"
46 #include "setting.h"
47
48 #include "win32/win32dep.h"
49
50 typedef struct
51 {
52 GtkWidget *files_label;
53 GtkWidget *open_button;
54
55 GtkWidget *entry_combo;
56 GtkListStore *entry_model;
57
58 GtkWidget *directory_album_artist_notebook;
59
60 GtkListStore *file_model;
61 GtkWidget *file_view;
62 GtkWidget *file_menu;
63 guint file_selected_handler;
64 EtSortMode file_sort_mode;
65
66 GtkWidget *album_view;
67 GtkWidget *album_menu;
68 GtkListStore *album_model;
69 guint album_selected_handler;
70
71 GtkWidget *artist_view;
72 GtkWidget *artist_menu;
73 GtkListStore *artist_model;
74 guint artist_selected_handler;
75
76 GtkWidget *directory_view; /* Tree of directories. */
77 GtkWidget *directory_view_menu;
78 GtkTreeStore *directory_model;
79
80 GtkListStore *run_program_model;
81
82 GtkWidget *open_directory_with_dialog;
83 GtkWidget *open_directory_with_combobox;
84
85 GtkWidget *open_files_with_dialog;
86 GtkWidget *open_files_with_combobox;
87
88 /* The Rename Directory window. */
89 GtkWidget *rename_directory_dialog;
90 GtkWidget *rename_directory_entry;
91 GtkWidget *rename_directory_mask_toggle;
92 GtkWidget *rename_directory_mask_entry;
93 GtkWidget *rename_directory_preview_label;
94
95 GFile *current_path;
96 } EtBrowserPrivate;
97
98 G_DEFINE_TYPE_WITH_PRIVATE (EtBrowser, et_browser, GTK_TYPE_BIN)
99
100 /*
101 * EtPathState:
102 * @ET_PATH_STATE_OPEN: the path is open or has been read
103 * @ET_PATH_STATE_CLOSED: the path is closed or could not be read
104 *
105 * Whether to generate an icon with an indicaton that the directory is open
106 * (being viewed) or closed (not yet viewed or read).
107 */
108 typedef enum
109 {
110 ET_PATH_STATE_OPEN,
111 ET_PATH_STATE_CLOSED
112 } EtPathState;
113
114 enum
115 {
116 LIST_FILE_NAME,
117 /* Tag fields. */
118 LIST_FILE_TITLE,
119 LIST_FILE_ARTIST,
120 LIST_FILE_ALBUM_ARTIST,
121 LIST_FILE_ALBUM,
122 LIST_FILE_YEAR,
123 LIST_FILE_DISCNO,
124 LIST_FILE_TRACK,
125 LIST_FILE_GENRE,
126 LIST_FILE_COMMENT,
127 LIST_FILE_COMPOSER,
128 LIST_FILE_ORIG_ARTIST,
129 LIST_FILE_COPYRIGHT,
130 LIST_FILE_URL,
131 LIST_FILE_ENCODED_BY,
132 /* End of columns with associated UI columns. */
133 LIST_FILE_POINTER,
134 LIST_FILE_KEY,
135 LIST_FILE_OTHERDIR, /* To change color for alternate directories. */
136 LIST_FONT_WEIGHT,
137 LIST_ROW_BACKGROUND,
138 LIST_ROW_FOREGROUND,
139 LIST_COLUMN_COUNT
140 };
141
142 enum
143 {
144 ALBUM_GICON,
145 ALBUM_NAME,
146 ALBUM_NUM_FILES,
147 ALBUM_ETFILE_LIST_POINTER,
148 ALBUM_FONT_WEIGHT,
149 ALBUM_ROW_FOREGROUND,
150 ALBUM_ALL_ALBUMS_ROW,
151 ALBUM_ALL_ALBUMS_SEPARATOR_ROW,
152 ALBUM_COLUMN_COUNT
153 };
154
155 enum
156 {
157 ARTIST_PIXBUF,
158 ARTIST_NAME,
159 ARTIST_NUM_ALBUMS,
160 ARTIST_NUM_FILES,
161 ARTIST_ALBUM_LIST_POINTER,
162 ARTIST_FONT_WEIGHT,
163 ARTIST_ROW_FOREGROUND,
164 ARTIST_COLUMN_COUNT
165 };
166
167 enum
168 {
169 TREE_COLUMN_DIR_NAME,
170 TREE_COLUMN_FULL_PATH,
171 TREE_COLUMN_SCANNED,
172 TREE_COLUMN_HAS_SUBDIR,
173 TREE_COLUMN_ICON,
174 TREE_COLUMN_COUNT
175 };
176
177 /**************
178 * Prototypes *
179 **************/
180
181 static void Browser_Tree_Handle_Rename (EtBrowser *self,
182 GtkTreeIter *parentnode,
183 const gchar *old_path,
184 const gchar *new_path);
185
186 static void Browser_List_Set_Row_Appearance (EtBrowser *self, GtkTreeIter *iter);
187 static gint Browser_List_Sort_Func (GtkTreeModel *model, GtkTreeIter *a,
188 GtkTreeIter *b, gpointer data);
189 static void Browser_List_Select_File_By_Iter (EtBrowser *self,
190 GtkTreeIter *iter,
191 gboolean select_it);
192
193 static void Browser_Artist_List_Row_Selected (EtBrowser *self,
194 GtkTreeSelection *selection);
195 static void Browser_Artist_List_Set_Row_Appearance (EtBrowser *self, GtkTreeIter *row);
196
197 static void Browser_Album_List_Load_Files (EtBrowser *self, GList *albumlist,
198 ET_File *etfile_to_select);
199 static void Browser_Album_List_Row_Selected (EtBrowser *self,
200 GtkTreeSelection *selection);
201 static void Browser_Album_List_Set_Row_Appearance (EtBrowser *self, GtkTreeIter *row);
202
203 static gboolean check_for_subdir (const gchar *path);
204
205 static GtkTreePath *Find_Child_Node (EtBrowser *self, GtkTreeIter *parent, gchar *searchtext);
206
207 static GIcon *get_gicon_for_path (const gchar *path, EtPathState path_state);
208
209 /* For window to rename a directory */
210 static void Destroy_Rename_Directory_Window (EtBrowser *self);
211 static void Rename_Directory_With_Mask_Toggled (EtBrowser *self);
212
213 /* For window to run a program with the directory */
214 static void Destroy_Run_Program_Tree_Window (EtBrowser *self);
215 static void Run_Program_With_Directory (EtBrowser *self);
216
217 /* For window to run a program with the file */
218 static void Destroy_Run_Program_List_Window (EtBrowser *self);
219
220 static void empty_entry_disable_widget (GtkWidget *widget, GtkEntry *entry);
221
222 static void et_rename_directory_on_response (GtkDialog *dialog,
223 gint response_id,
224 gpointer user_data);
225 static void et_run_program_tree_on_response (GtkDialog *dialog,
226 gint response_id,
227 gpointer user_data);
228 static void et_run_program_list_on_response (GtkDialog *dialog,
229 gint response_id,
230 gpointer user_data);
231
232 static void et_browser_on_column_clicked (GtkTreeViewColumn *column,
233 gpointer data);
234
235
236 /*************
237 * Functions *
238 *************/
239 /*
240 * Load home directory
241 */
242 void
et_browser_go_home(EtBrowser * self)243 et_browser_go_home (EtBrowser *self)
244 {
245 GFile *file;
246
247 file = g_file_new_for_path (g_get_home_dir ());
248 et_browser_select_dir (self, file);
249 g_object_unref (file);
250 }
251
252 /*
253 * Load desktop directory
254 */
255 void
et_browser_go_desktop(EtBrowser * self)256 et_browser_go_desktop (EtBrowser *self)
257 {
258 GFile *file;
259
260 file = g_file_new_for_path (g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP));
261 et_browser_select_dir (self, file);
262 g_object_unref (file);
263 }
264
265 /*
266 * Load documents directory
267 */
268 void
et_browser_go_documents(EtBrowser * self)269 et_browser_go_documents (EtBrowser *self)
270 {
271 GFile *file;
272
273 file = g_file_new_for_path (g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
274 et_browser_select_dir (self, file);
275 g_object_unref (file);
276 }
277
278 /*
279 * Load downloads directory
280 */
281 void
et_browser_go_downloads(EtBrowser * self)282 et_browser_go_downloads (EtBrowser *self)
283 {
284 GFile *file;
285
286 file = g_file_new_for_path (g_get_user_special_dir (G_USER_DIRECTORY_DOWNLOAD));
287 et_browser_select_dir (self, file);
288 g_object_unref (file);
289 }
290
291 /*
292 * Load music directory
293 */
294 void
et_browser_go_music(EtBrowser * self)295 et_browser_go_music (EtBrowser *self)
296 {
297 GFile *file;
298
299 file = g_file_new_for_path (g_get_user_special_dir (G_USER_DIRECTORY_MUSIC));
300 et_browser_select_dir (self, file);
301 g_object_unref (file);
302 }
303
304
305 /*
306 * Load default directory
307 */
308 void
et_browser_load_default_dir(EtBrowser * self)309 et_browser_load_default_dir (EtBrowser *self)
310 {
311 GFile **files;
312 GVariant *default_path;
313 const gchar *path;
314
315 default_path = g_settings_get_value (MainSettings, "default-path");
316 path = g_variant_get_bytestring (default_path);
317
318 files = g_new (GFile *, 1);
319 files[0] = g_file_new_for_path (path);
320 g_application_open (g_application_get_default (), files, 1, "");
321
322 g_object_unref (files[0]);
323 g_variant_unref (default_path);
324 g_free (files);
325 }
326
327 void
et_browser_run_player_for_album_list(EtBrowser * self)328 et_browser_run_player_for_album_list (EtBrowser *self)
329 {
330 EtBrowserPrivate *priv;
331 GtkTreeIter iter;
332 GtkTreeSelection *selection;
333 GList *l;
334 GList *file_list = NULL;
335 GError *error = NULL;
336
337 priv = et_browser_get_instance_private (self);
338
339 g_return_if_fail (priv->album_view != NULL);
340
341 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->album_view));
342
343 if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
344 return;
345
346 gtk_tree_model_get (GTK_TREE_MODEL (priv->album_model), &iter,
347 ALBUM_ETFILE_LIST_POINTER, &l, -1);
348
349 for (; l != NULL; l = g_list_next (l))
350 {
351 ET_File *etfile = (ET_File *)l->data;
352 const gchar *path = ((File_Name *)etfile->FileNameCur->data)->value;
353 file_list = g_list_prepend (file_list, g_file_new_for_path (path));
354 }
355
356 file_list = g_list_reverse (file_list);
357
358 if (!et_run_audio_player (file_list, &error))
359 {
360 Log_Print (LOG_ERROR, _("Failed to launch program ‘%s’"),
361 error->message);
362 g_error_free (error);
363 }
364
365 g_list_free_full (file_list, g_object_unref);
366 }
367
368 void
et_browser_run_player_for_artist_list(EtBrowser * self)369 et_browser_run_player_for_artist_list (EtBrowser *self)
370 {
371 EtBrowserPrivate *priv;
372 GtkTreeIter iter;
373 GtkTreeSelection *selection;
374 GList *l, *m;
375 GList *file_list = NULL;
376 GError *error = NULL;
377
378 priv = et_browser_get_instance_private (self);
379
380 g_return_if_fail (priv->artist_view != NULL);
381
382 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->artist_view));
383 if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
384 return;
385
386 gtk_tree_model_get (GTK_TREE_MODEL (priv->artist_model), &iter,
387 ARTIST_ALBUM_LIST_POINTER, &l, -1);
388
389 for (; l != NULL; l = g_list_next (l))
390 {
391 for (m = l->data; m != NULL; m = g_list_next (m))
392 {
393 ET_File *etfile = (ET_File *)m->data;
394 const gchar *path = ((File_Name *)etfile->FileNameCur->data)->value;
395 file_list = g_list_prepend (file_list, g_file_new_for_path (path));
396 }
397 }
398
399 file_list = g_list_reverse (file_list);
400
401 if (!et_run_audio_player (file_list, &error))
402 {
403 Log_Print (LOG_ERROR, _("Failed to launch program ‘%s’"),
404 error->message);
405 g_error_free (error);
406 }
407
408 g_list_free_full (file_list, g_object_unref);
409 }
410
411 void
et_browser_run_player_for_selection(EtBrowser * self)412 et_browser_run_player_for_selection (EtBrowser *self)
413 {
414 EtBrowserPrivate *priv;
415 GList *selfilelist = NULL;
416 GList *l;
417 GList *file_list = NULL;
418 GtkTreeSelection *selection;
419 GError *error = NULL;
420
421 priv = et_browser_get_instance_private (self);
422
423 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->file_view));
424 selfilelist = gtk_tree_selection_get_selected_rows(selection, NULL);
425
426 for (l = selfilelist; l != NULL; l = g_list_next (l))
427 {
428 ET_File *etfile = et_browser_get_et_file_from_path (self, l->data);
429 const gchar *path = ((File_Name *)etfile->FileNameCur->data)->value;
430 file_list = g_list_prepend (file_list, g_file_new_for_path (path));
431 }
432
433 file_list = g_list_reverse (file_list);
434
435 if (!et_run_audio_player (file_list, &error))
436 {
437 Log_Print (LOG_ERROR, _("Failed to launch program ‘%s’"),
438 error->message);
439 g_error_free (error);
440 }
441
442 g_list_free_full (file_list, g_object_unref);
443 g_list_free_full (selfilelist, (GDestroyNotify)gtk_tree_path_free);
444 }
445
446 /*
447 * Get the path from the selected node (row) in the browser
448 * Warning: return NULL if no row selected int the tree.
449 * Remember to free the value returned from this function!
450 */
451 static gchar *
Browser_Tree_Get_Path_Of_Selected_Node(EtBrowser * self)452 Browser_Tree_Get_Path_Of_Selected_Node (EtBrowser *self)
453 {
454 EtBrowserPrivate *priv;
455 GtkTreeSelection *selection;
456 GtkTreeIter selectedIter;
457 gchar *path;
458
459 priv = et_browser_get_instance_private (self);
460
461 g_return_val_if_fail (priv->directory_view != NULL, NULL);
462
463 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->directory_view));
464 if (selection
465 && gtk_tree_selection_get_selected(selection, NULL, &selectedIter))
466 {
467 gtk_tree_model_get(GTK_TREE_MODEL(priv->directory_model), &selectedIter,
468 TREE_COLUMN_FULL_PATH, &path, -1);
469 return path;
470 }else
471 {
472 return NULL;
473 }
474 }
475
476
477 /*
478 * Set the current path to be shown in the browser.
479 */
480 static void
et_browser_set_current_path(EtBrowser * self,GFile * file)481 et_browser_set_current_path (EtBrowser *self,
482 GFile *file)
483 {
484 EtBrowserPrivate *priv;
485
486 g_return_if_fail (file != NULL);
487
488 priv = et_browser_get_instance_private (self);
489
490 /* Ref the new file first, in case the current file is passed in. */
491 g_object_ref (file);
492
493 if (priv->current_path)
494 {
495 g_object_unref (priv->current_path);
496 }
497
498 priv->current_path = file;
499 }
500
501
502 /*
503 * Return the current path
504 */
505 GFile *
et_browser_get_current_path(EtBrowser * self)506 et_browser_get_current_path (EtBrowser *self)
507 {
508 EtBrowserPrivate *priv;
509
510 g_return_val_if_fail (ET_BROWSER (self), NULL);
511
512 priv = et_browser_get_instance_private (self);
513
514 return priv->current_path;
515 }
516
517 GtkTreeSelection *
et_browser_get_selection(EtBrowser * self)518 et_browser_get_selection (EtBrowser *self)
519 {
520 EtBrowserPrivate *priv;
521
522 g_return_val_if_fail (ET_BROWSER (self), NULL);
523
524 priv = et_browser_get_instance_private (self);
525
526 return gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->file_view));
527 }
528
529 /*
530 * Reload the current directory.
531 */
532 void
et_browser_reload_directory(EtBrowser * self)533 et_browser_reload_directory (EtBrowser *self)
534 {
535 EtBrowserPrivate *priv;
536
537 priv = et_browser_get_instance_private (self);
538
539 if (priv->directory_view && priv->current_path != NULL)
540 {
541 /* Unselect files, to automatically reload the file of the directory. */
542 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->directory_view));
543
544 if (selection)
545 {
546 gtk_tree_selection_unselect_all(selection);
547 }
548
549 et_browser_select_dir (self, priv->current_path);
550 }
551 }
552
553 /*
554 * Set the current path (selected node) in browser as default path (within config variable).
555 */
556 void
et_browser_set_current_path_default(EtBrowser * self)557 et_browser_set_current_path_default (EtBrowser *self)
558 {
559 EtBrowserPrivate *priv;
560 gchar *path;
561
562 g_return_if_fail (ET_BROWSER (self));
563
564 priv = et_browser_get_instance_private (self);
565
566 path = g_file_get_path (priv->current_path);
567 g_settings_set_value (MainSettings, "default-path",
568 g_variant_new_bytestring (path));
569 g_free (path);
570
571 et_application_window_status_bar_message (ET_APPLICATION_WINDOW (MainWindow),
572 _("New default directory selected for browser"),
573 TRUE);
574 }
575
576 /*
577 * When you press the key 'enter' in the BrowserEntry to validate the text (browse the directory)
578 */
579 static void
Browser_Entry_Activated(EtBrowser * self,GtkEntry * entry)580 Browser_Entry_Activated (EtBrowser *self,
581 GtkEntry *entry)
582 {
583 EtBrowserPrivate *priv;
584 const gchar *parse_name;
585 GFile *file;
586
587 priv = et_browser_get_instance_private (self);
588
589 parse_name = gtk_entry_get_text (entry);
590 Add_String_To_Combo_List (GTK_LIST_STORE (priv->entry_model), parse_name);
591
592 file = g_file_parse_name (parse_name);
593
594 et_browser_select_dir (self, file);
595
596 g_object_unref (file);
597 }
598
599 /*
600 * Set a text into the BrowserEntry (and don't activate it)
601 */
602 void
et_browser_entry_set_text(EtBrowser * self,const gchar * text)603 et_browser_entry_set_text (EtBrowser *self, const gchar *text)
604 {
605 EtBrowserPrivate *priv;
606
607 priv = et_browser_get_instance_private (self);
608
609 if (!text || !priv->entry_combo)
610 return;
611
612 gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->entry_combo))),
613 text);
614 }
615
616 /*
617 * Button to go to parent directory
618 */
619 void
et_browser_go_parent(EtBrowser * self)620 et_browser_go_parent (EtBrowser *self)
621 {
622 GFile *parent;
623
624 parent = g_file_get_parent (et_browser_get_current_path (self));
625
626 if (parent)
627 {
628 et_browser_select_dir (self, parent);
629 g_object_unref (parent);
630 }
631 else
632 {
633 g_debug ("%s", "No parent found for current browser path");
634 }
635 }
636
637 /*
638 * Set a text into the priv->files_label
639 */
640 void
et_browser_label_set_text(EtBrowser * self,const gchar * text)641 et_browser_label_set_text (EtBrowser *self, const gchar *text)
642 {
643 EtBrowserPrivate *priv;
644
645 g_return_if_fail (ET_BROWSER (self));
646 g_return_if_fail (text != NULL);
647
648 priv = et_browser_get_instance_private (self);
649
650 gtk_label_set_text (GTK_LABEL (priv->files_label), text);
651 }
652
653 /*
654 * Key Press events into browser tree
655 */
656 static gboolean
Browser_Tree_Key_Press(GtkWidget * tree,GdkEvent * event,gpointer data)657 Browser_Tree_Key_Press (GtkWidget *tree, GdkEvent *event, gpointer data)
658 {
659 GdkEventKey *kevent;
660 GtkTreeIter SelectedNode;
661 GtkTreeModel *treeModel;
662 GtkTreeSelection *treeSelection;
663 GtkTreePath *treePath;
664
665 g_return_val_if_fail (tree != NULL, FALSE);
666
667 treeSelection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
668
669 if (event && event->type==GDK_KEY_PRESS)
670 {
671 if (!gtk_tree_selection_get_selected(treeSelection, &treeModel, &SelectedNode))
672 return FALSE;
673
674 kevent = (GdkEventKey *)event;
675 treePath = gtk_tree_model_get_path(GTK_TREE_MODEL(treeModel), &SelectedNode);
676
677 switch(kevent->keyval)
678 {
679 case GDK_KEY_KP_Enter: /* Enter key in Num Pad */
680 case GDK_KEY_Return: /* 'Normal' Enter key */
681 case GDK_KEY_t: /* Expand/Collapse node */
682 case GDK_KEY_T: /* Expand/Collapse node */
683 if(gtk_tree_view_row_expanded(GTK_TREE_VIEW(tree), treePath))
684 gtk_tree_view_collapse_row(GTK_TREE_VIEW(tree), treePath);
685 else
686 gtk_tree_view_expand_row(GTK_TREE_VIEW(tree), treePath, FALSE);
687
688 gtk_tree_path_free(treePath);
689 return TRUE;
690 break;
691
692 case GDK_KEY_e: /* Expand node */
693 case GDK_KEY_E: /* Expand node */
694 gtk_tree_view_expand_row(GTK_TREE_VIEW(tree), treePath, FALSE);
695 gtk_tree_path_free(treePath);
696 return TRUE;
697 break;
698
699 case GDK_KEY_c: /* Collapse node */
700 case GDK_KEY_C: /* Collapse node */
701 gtk_tree_view_collapse_row(GTK_TREE_VIEW(tree), treePath);
702 gtk_tree_path_free(treePath);
703 return TRUE;
704 break;
705 /* Ignore all other keypresses. */
706 default:
707 break;
708 }
709 gtk_tree_path_free(treePath);
710 }
711 return FALSE;
712 }
713
714 /*
715 * Key press into browser list
716 * - Delete = delete file
717 * Also tries to capture text input and relate it to files
718 */
719 static gboolean
Browser_List_Key_Press(GtkWidget * list,GdkEvent * event,gpointer data)720 Browser_List_Key_Press (GtkWidget *list, GdkEvent *event, gpointer data)
721 {
722 GdkEventKey *kevent;
723 GtkTreeSelection *fileSelection;
724
725 g_return_val_if_fail (list != NULL, FALSE);
726
727 fileSelection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list));
728
729 kevent = (GdkEventKey *)event;
730 if (event && event->type==GDK_KEY_PRESS)
731 {
732 if (gtk_tree_selection_count_selected_rows(fileSelection))
733 {
734 switch(kevent->keyval)
735 {
736 case GDK_KEY_Delete:
737 g_action_group_activate_action (G_ACTION_GROUP (MainWindow),
738 "delete", NULL);
739 return TRUE;
740 /* Ignore all other keypresses. */
741 default:
742 break;
743 }
744 }
745 }
746
747 return FALSE;
748 }
749
750 /*
751 * Collapse (close) tree recursively up to the root node.
752 */
753 void
et_browser_collapse(EtBrowser * self)754 et_browser_collapse (EtBrowser *self)
755 {
756 EtBrowserPrivate *priv;
757 #ifndef G_OS_WIN32
758 GtkTreePath *rootPath;
759 #endif /* !G_OS_WIN32 */
760
761 priv = et_browser_get_instance_private (self);
762
763 g_return_if_fail (priv->directory_view != NULL);
764
765 gtk_tree_view_collapse_all (GTK_TREE_VIEW (priv->directory_view));
766
767 #ifndef G_OS_WIN32
768 /* But keep the main directory opened */
769 rootPath = gtk_tree_path_new_first();
770 gtk_tree_view_expand_to_path (GTK_TREE_VIEW (priv->directory_view),
771 rootPath);
772 gtk_tree_path_free(rootPath);
773 #endif /* !G_OS_WIN32 */
774 }
775
776
777 /*
778 * Set a row (or node) visible in the TreeView (by scrolling the tree)
779 */
780 static void
Browser_Tree_Set_Node_Visible(GtkWidget * directoryView,GtkTreePath * path)781 Browser_Tree_Set_Node_Visible (GtkWidget *directoryView, GtkTreePath *path)
782 {
783 g_return_if_fail (directoryView != NULL || path != NULL);
784
785 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(directoryView), path, NULL, TRUE, 0.5, 0.0);
786 }
787
788
789 /*
790 * Set a row visible in the file list (by scrolling the list)
791 */
792 static void
et_browser_set_row_visible(EtBrowser * self,GtkTreeIter * rowIter)793 et_browser_set_row_visible (EtBrowser *self, GtkTreeIter *rowIter)
794 {
795 EtBrowserPrivate *priv;
796
797 /*
798 * TODO: Make this only scroll to the row if it is not visible
799 * (like in easytag GTK1)
800 * See function gtk_tree_view_get_visible_rect() ??
801 */
802 GtkTreePath *rowPath;
803
804 priv = et_browser_get_instance_private (self);
805
806 g_return_if_fail (rowIter != NULL);
807
808 rowPath = gtk_tree_model_get_path (GTK_TREE_MODEL (priv->file_model),
809 rowIter);
810 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (priv->file_view), rowPath,
811 NULL, FALSE, 0, 0);
812 gtk_tree_path_free (rowPath);
813 }
814
815 /*
816 * Triggers when a new node in the browser tree is selected
817 * Do file-save confirmation, and then prompt the new dir to be loaded
818 */
819 static gboolean
Browser_Tree_Node_Selected(EtBrowser * self,GtkTreeSelection * selection)820 Browser_Tree_Node_Selected (EtBrowser *self, GtkTreeSelection *selection)
821 {
822 EtBrowserPrivate *priv;
823 gchar *pathName;
824 GFile *file;
825 gchar *parse_name;
826 static gboolean first_read = TRUE;
827 GtkTreeIter selectedIter;
828 GtkTreePath *selectedPath;
829
830 priv = et_browser_get_instance_private (self);
831
832 if (!gtk_tree_selection_get_selected(selection, NULL, &selectedIter))
833 return TRUE;
834 selectedPath = gtk_tree_model_get_path(GTK_TREE_MODEL(priv->directory_model), &selectedIter);
835
836 /* Open the node */
837 if (g_settings_get_boolean (MainSettings, "browse-expand-children"))
838 {
839 gtk_tree_view_expand_row (GTK_TREE_VIEW (priv->directory_view),
840 selectedPath, FALSE);
841 }
842 gtk_tree_path_free(selectedPath);
843
844 /* Don't start a new reading, if another one is running... */
845 if (ReadingDirectory == TRUE)
846 return TRUE;
847
848 /* Browser_Tree_Set_Node_Visible (priv->directory_view, selectedPath); */
849 gtk_tree_model_get(GTK_TREE_MODEL(priv->directory_model), &selectedIter,
850 TREE_COLUMN_FULL_PATH, &pathName, -1);
851 if (!pathName)
852 return FALSE;
853
854 et_application_window_update_et_file_from_ui (ET_APPLICATION_WINDOW (MainWindow));
855
856 /* FIXME: Not clean to put this here. */
857 et_application_window_update_actions (ET_APPLICATION_WINDOW (MainWindow));
858
859 /* Check if all files have been saved before changing the directory */
860 if (g_settings_get_boolean (MainSettings, "confirm-when-unsaved-files")
861 && et_file_list_check_all_saved (ETCore->ETFileList) != TRUE)
862 {
863 GtkWidget *msgdialog;
864 gint response;
865
866 msgdialog = gtk_message_dialog_new(GTK_WINDOW(MainWindow),
867 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
868 GTK_MESSAGE_QUESTION,
869 GTK_BUTTONS_NONE,
870 "%s",
871 _("Some files have been modified but not saved"));
872 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (msgdialog),
873 "%s",
874 _("Do you want to save them before changing directory?"));
875 gtk_dialog_add_buttons (GTK_DIALOG (msgdialog), _("_Discard"),
876 GTK_RESPONSE_NO, _("_Cancel"),
877 GTK_RESPONSE_CANCEL, _("_Save"),
878 GTK_RESPONSE_YES, NULL);
879 gtk_dialog_set_default_response (GTK_DIALOG (msgdialog),
880 GTK_RESPONSE_YES);
881 gtk_window_set_title(GTK_WINDOW(msgdialog),_("Confirm Directory Change"));
882
883 response = gtk_dialog_run(GTK_DIALOG(msgdialog));
884 gtk_widget_destroy(msgdialog);
885 switch (response)
886 {
887 case GTK_RESPONSE_YES:
888 if (Save_All_Files_With_Answer(FALSE)==-1)
889 {
890 g_free (pathName);
891 return TRUE;
892 }
893 break;
894 case GTK_RESPONSE_NO:
895 break;
896 case GTK_RESPONSE_CANCEL:
897 case GTK_RESPONSE_DELETE_EVENT:
898 g_free (pathName);
899 return TRUE;
900 break;
901 default:
902 g_assert_not_reached ();
903 break;
904 }
905 }
906
907 /* Memorize the current path */
908 file = g_file_new_for_path (pathName);
909 et_browser_set_current_path (self, file);
910
911 /* Display the selected path into the BrowserEntry */
912 parse_name = g_file_get_parse_name (file);
913 gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->entry_combo))),
914 parse_name);
915 g_free (parse_name);
916
917 /* Start to read the directory */
918 /* Skip loading the file list the first time that it is shown, if the user
919 * has requested the read to be skipped. */
920 if (!first_read
921 || g_settings_get_boolean (MainSettings, "load-on-startup"))
922 {
923 gboolean dir_loaded;
924 GtkTreeIter parentIter;
925
926 dir_loaded = Read_Directory(pathName);
927
928 // If the directory can't be loaded, the directory musn't exist.
929 // So we load the parent node and refresh the children
930 if (dir_loaded == FALSE)
931 {
932 if (gtk_tree_selection_get_selected(selection, NULL, &selectedIter))
933 {
934 /* If the path could not be read, then it is possible that it
935 * has a subdirectory with readable permissions. In that case
936 * do not refresh the children. */
937 if (gtk_tree_model_iter_parent(GTK_TREE_MODEL(priv->directory_model),&parentIter,&selectedIter) )
938 {
939 selectedPath = gtk_tree_model_get_path(GTK_TREE_MODEL(priv->directory_model), &parentIter);
940 gtk_tree_selection_select_iter (selection, &parentIter);
941 if (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (priv->directory_model),
942 &selectedIter) == FALSE
943 && !g_file_query_exists (file, NULL))
944 {
945 gtk_tree_view_collapse_row (GTK_TREE_VIEW (priv->directory_view),
946 selectedPath);
947 if (g_settings_get_boolean (MainSettings,
948 "browse-expand-children"))
949 {
950 gtk_tree_view_expand_row (GTK_TREE_VIEW (priv->directory_view),
951 selectedPath, FALSE);
952 }
953 gtk_tree_path_free (selectedPath);
954 }
955 }
956 }
957 }
958
959 }else
960 {
961 /* As we don't use the function 'Read_Directory' we must add this function here */
962 et_application_window_update_actions (ET_APPLICATION_WINDOW (MainWindow));
963 }
964
965 first_read = FALSE;
966
967 g_object_unref (file);
968 g_free(pathName);
969 return FALSE;
970 }
971
972
973 #ifdef G_OS_WIN32
974 static gboolean
et_browser_win32_get_drive_root(EtBrowser * self,gchar * drive,GtkTreeIter * rootNode,GtkTreePath ** rootPath)975 et_browser_win32_get_drive_root (EtBrowser *self,
976 gchar *drive,
977 GtkTreeIter *rootNode,
978 GtkTreePath **rootPath)
979 {
980 EtBrowserPrivate *priv;
981 gint root_index;
982 gboolean found = FALSE;
983 GtkTreeIter parentNode;
984 gchar *nodeName;
985
986 priv = et_browser_get_instance_private (self);
987
988 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(priv->directory_model), &parentNode);
989
990 // Find root of path, ie: the drive letter
991 root_index = 0;
992
993 do
994 {
995 gtk_tree_model_get(GTK_TREE_MODEL(priv->directory_model), &parentNode,
996 TREE_COLUMN_FULL_PATH, &nodeName, -1);
997 if (strncasecmp(drive,nodeName, strlen(drive)) == 0)
998 {
999 g_free(nodeName);
1000 found = TRUE;
1001 break;
1002 }
1003 root_index++;
1004 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(priv->directory_model), &parentNode));
1005
1006 if (!found) return FALSE;
1007
1008 *rootNode = parentNode;
1009 *rootPath = gtk_tree_path_new_from_indices(root_index, -1);
1010
1011 return TRUE;
1012 }
1013 #endif /* G_OS_WIN32 */
1014
1015
1016 /*
1017 * et_browser_select_dir:
1018 *
1019 * Select the directory corresponding to the 'path' in the tree browser, but it
1020 * doesn't read it! Check if path is correct before selecting it.
1021 */
1022 void
et_browser_select_dir(EtBrowser * self,GFile * file)1023 et_browser_select_dir (EtBrowser *self,
1024 GFile *file)
1025 {
1026 EtBrowserPrivate *priv;
1027 gchar *current_path;
1028 GtkTreePath *rootPath = NULL;
1029 GtkTreeIter parentNode, currentNode;
1030 gint index = 1; // Skip the first token as it is NULL due to leading /
1031 gchar **parts;
1032 gchar *nodeName;
1033 gchar *temp;
1034
1035 priv = et_browser_get_instance_private (self);
1036
1037 g_return_if_fail (priv->directory_view != NULL);
1038
1039 /* Don't check here if the path is valid. It will be done later when
1040 * selecting a node in the tree */
1041
1042 et_browser_set_current_path (self, file);
1043 current_path = g_file_get_path (file);
1044
1045 parts = g_strsplit(current_path, G_DIR_SEPARATOR_S, 0);
1046 g_free (current_path);
1047
1048 // Expand root node (fill parentNode and rootPath)
1049 #ifdef G_OS_WIN32
1050 if (!et_browser_win32_get_drive_root (self, parts[0], &parentNode,
1051 &rootPath))
1052 {
1053 return;
1054 }
1055 #else /* !G_OS_WIN32 */
1056 if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->directory_model),
1057 &parentNode))
1058 {
1059 g_message ("%s", "priv->directory_model is empty");
1060 return;
1061 }
1062
1063 rootPath = gtk_tree_path_new_first();
1064 #endif /* !G_OS_WIN32 */
1065 if (rootPath)
1066 {
1067 gtk_tree_view_expand_to_path (GTK_TREE_VIEW (priv->directory_view),
1068 rootPath);
1069 gtk_tree_path_free(rootPath);
1070 }
1071
1072 while (parts[index]) // it is NULL-terminated
1073 {
1074 if (parts[index] == '\0')
1075 {
1076 index++;
1077 continue;
1078 }
1079
1080 if (!gtk_tree_model_iter_children(GTK_TREE_MODEL(priv->directory_model), ¤tNode, &parentNode))
1081 {
1082 gchar *path, *parent_path;
1083 GFile *directory;
1084
1085 gtk_tree_model_get (GTK_TREE_MODEL (priv->directory_model),
1086 &parentNode, TREE_COLUMN_FULL_PATH,
1087 &parent_path, -1);
1088 path = g_build_filename (parent_path, parts[index], NULL);
1089 g_free (parent_path);
1090
1091 directory = g_file_new_for_path (path);
1092
1093 /* As dir name was not found in any node, check whether it exists
1094 * or not. */
1095 if (g_file_query_file_type (directory, G_FILE_QUERY_INFO_NONE, NULL)
1096 == G_FILE_TYPE_DIRECTORY)
1097 {
1098 /* It exists and is readable permission of parent directory is executable */
1099 GIcon *icon;
1100 GtkTreeIter iter;
1101
1102 /* Create a new node for this directory name. */
1103 icon = get_gicon_for_path (path, ET_PATH_STATE_CLOSED);
1104
1105 gtk_tree_store_insert_with_values (GTK_TREE_STORE (priv->directory_model),
1106 &iter, &parentNode, 0,
1107 TREE_COLUMN_DIR_NAME, parts[index],
1108 TREE_COLUMN_FULL_PATH, path,
1109 TREE_COLUMN_HAS_SUBDIR, check_for_subdir (current_path),
1110 TREE_COLUMN_SCANNED, TRUE,
1111 TREE_COLUMN_ICON, icon, -1);
1112
1113 currentNode = iter;
1114 g_object_unref (icon);
1115 }
1116 else
1117 {
1118 g_object_unref (directory);
1119 g_free (path);
1120 break;
1121 }
1122
1123 g_object_unref (directory);
1124 g_free (path);
1125 }
1126
1127 do
1128 {
1129 gtk_tree_model_get(GTK_TREE_MODEL(priv->directory_model), ¤tNode,
1130 TREE_COLUMN_FULL_PATH, &temp, -1);
1131 nodeName = g_path_get_basename(temp);
1132 g_free(temp);
1133 #ifdef G_OS_WIN32
1134 if (strcasecmp(parts[index],nodeName) == 0)
1135 #else /* !G_OS_WIN32 */
1136 if (strcmp(parts[index],nodeName) == 0)
1137 #endif /* !G_OS_WIN32 */
1138 {
1139 g_free(nodeName);
1140 break;
1141 }
1142 g_free(nodeName);
1143
1144 if (!gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->directory_model),
1145 ¤tNode))
1146 {
1147 /* Path was not found in tree, such as when a hidden path was
1148 * passed in, but hidden paths are set to not be displayed. */
1149 g_strfreev (parts);
1150 return;
1151 }
1152 } while (1);
1153
1154 parentNode = currentNode;
1155 rootPath = gtk_tree_model_get_path(GTK_TREE_MODEL(priv->directory_model), &parentNode);
1156 if (rootPath)
1157 {
1158 gtk_tree_view_expand_to_path (GTK_TREE_VIEW (priv->directory_view),
1159 rootPath);
1160 gtk_tree_path_free(rootPath);
1161 }
1162 index++;
1163 }
1164
1165 rootPath = gtk_tree_model_get_path(GTK_TREE_MODEL(priv->directory_model), &parentNode);
1166 if (rootPath)
1167 {
1168 gtk_tree_view_expand_to_path (GTK_TREE_VIEW (priv->directory_view),
1169 rootPath);
1170 Browser_Tree_Set_Node_Visible (priv->directory_view, rootPath);
1171 /* Select the node to load the corresponding directory. */
1172 gtk_tree_selection_select_path (gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->directory_view)),
1173 rootPath);
1174 gtk_tree_path_free(rootPath);
1175 }
1176
1177 g_strfreev(parts);
1178 return;
1179 }
1180
1181 /*
1182 * Callback to select-row event
1183 * Displays the file info of the lowest selected file in the right-hand pane
1184 */
1185 static void
Browser_List_Row_Selected(EtBrowser * self,GtkTreeSelection * selection)1186 Browser_List_Row_Selected (EtBrowser *self, GtkTreeSelection *selection)
1187 {
1188 EtBrowserPrivate *priv;
1189 gint n_selected;
1190 GtkTreePath *cursor_path;
1191 GtkTreeIter cursor_iter;
1192 ET_File *cursor_et_file;
1193
1194
1195 priv = et_browser_get_instance_private (self);
1196
1197 n_selected = gtk_tree_selection_count_selected_rows (selection);
1198
1199 /*
1200 * After a file is deleted, this function is called :
1201 * So we must handle the situation if no rows are selected
1202 */
1203 if (n_selected == 0)
1204 {
1205 /* TODO: Clear the tag area and file area. */
1206 return;
1207 }
1208
1209 gtk_tree_view_get_cursor (GTK_TREE_VIEW (priv->file_view),
1210 &cursor_path, NULL);
1211
1212 if (!cursor_path)
1213 {
1214 return;
1215 }
1216
1217 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->file_model),
1218 &cursor_iter, cursor_path))
1219 {
1220 if (gtk_tree_selection_iter_is_selected (selection, &cursor_iter))
1221 {
1222 gtk_tree_model_get (GTK_TREE_MODEL (priv->file_model),
1223 &cursor_iter, LIST_FILE_POINTER,
1224 &cursor_et_file, -1);
1225 et_application_window_select_file_by_et_file (ET_APPLICATION_WINDOW (MainWindow),
1226 cursor_et_file);
1227 }
1228 /* TODO: Clear the tag/file area if the cursor row was unselected, such
1229 * as by inverting the selection or Ctrl-clicking. */
1230 }
1231 else
1232 {
1233 g_warning ("%s", "Error getting iter from cursor path");
1234 }
1235
1236 gtk_tree_path_free (cursor_path);
1237 }
1238
1239 /*
1240 * Empty model, disabling Browser_List_Row_Selected () during clear because it
1241 * is called and causes crashes otherwise.
1242 */
1243 static void
et_browser_clear_file_model(EtBrowser * self)1244 et_browser_clear_file_model (EtBrowser *self)
1245 {
1246 EtBrowserPrivate *priv;
1247 GtkTreeSelection *selection;
1248
1249 priv = et_browser_get_instance_private (self);
1250
1251 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->file_view));
1252
1253 g_signal_handler_block (selection, priv->file_selected_handler);
1254
1255 gtk_list_store_clear (priv->file_model);
1256 gtk_tree_view_columns_autosize (GTK_TREE_VIEW (priv->file_view));
1257
1258 g_signal_handler_unblock (selection, priv->file_selected_handler);
1259 }
1260
1261 /*
1262 * Loads the specified etfilelist into the browser list
1263 * Also supports optionally selecting a specific etfile
1264 * but be careful, this does not call Browser_List_Row_Selected !
1265 */
1266 void
et_browser_load_file_list(EtBrowser * self,GList * etfilelist,const ET_File * etfile_to_select)1267 et_browser_load_file_list (EtBrowser *self,
1268 GList *etfilelist,
1269 const ET_File *etfile_to_select)
1270 {
1271 EtBrowserPrivate *priv;
1272 GList *l;
1273 gboolean activate_bg_color = 0;
1274 GtkTreeIter rowIter;
1275
1276 g_return_if_fail (ET_BROWSER (self));
1277
1278 priv = et_browser_get_instance_private (self);
1279
1280 et_browser_clear_file_model (self);
1281
1282 for (l = g_list_first (etfilelist); l != NULL; l = g_list_next (l))
1283 {
1284 guint fileKey = ((ET_File *)l->data)->ETFileKey;
1285 const gchar *current_filename_utf8 = ((File_Name *)((ET_File *)l->data)->FileNameCur->data)->value_utf8;
1286 gchar *basename_utf8 = g_path_get_basename (current_filename_utf8);
1287 File_Tag *FileTag = ((File_Tag *)((ET_File *)l->data)->FileTag->data);
1288 gchar *track;
1289 gchar *disc;
1290
1291 // Change background color when changing directory (the first row must not be changed)
1292 if (gtk_tree_model_iter_n_children(GTK_TREE_MODEL(priv->file_model), NULL) > 0)
1293 {
1294 gchar *dir1_utf8;
1295 gchar *dir2_utf8;
1296 const gchar *previous_filename_utf8 = ((File_Name *)((ET_File *)l->prev->data)->FileNameCur->data)->value_utf8;
1297
1298 dir1_utf8 = g_path_get_dirname(previous_filename_utf8);
1299 dir2_utf8 = g_path_get_dirname(current_filename_utf8);
1300
1301 if (g_utf8_collate(dir1_utf8, dir2_utf8) != 0)
1302 activate_bg_color = !activate_bg_color;
1303
1304 g_free(dir1_utf8);
1305 g_free(dir2_utf8);
1306 }
1307
1308 /* File list displays the current filename (name on disc) and tag
1309 * fields. */
1310 track = g_strconcat(FileTag->track ? FileTag->track : "",FileTag->track_total ? "/" : NULL,FileTag->track_total,NULL);
1311 disc = g_strconcat (FileTag->disc_number ? FileTag->disc_number : "",
1312 FileTag->disc_total ? "/"
1313 : NULL, FileTag->disc_total,
1314 NULL);
1315
1316 gtk_list_store_insert_with_values (priv->file_model, &rowIter, G_MAXINT,
1317 LIST_FILE_NAME, basename_utf8,
1318 LIST_FILE_POINTER, l->data,
1319 LIST_FILE_KEY, fileKey,
1320 LIST_FILE_OTHERDIR,
1321 activate_bg_color,
1322 LIST_FILE_TITLE, FileTag->title,
1323 LIST_FILE_ARTIST, FileTag->artist,
1324 LIST_FILE_ALBUM_ARTIST,
1325 FileTag->album_artist,
1326 LIST_FILE_ALBUM, FileTag->album,
1327 LIST_FILE_YEAR, FileTag->year,
1328 LIST_FILE_DISCNO, disc,
1329 LIST_FILE_TRACK, track,
1330 LIST_FILE_GENRE, FileTag->genre,
1331 LIST_FILE_COMMENT, FileTag->comment,
1332 LIST_FILE_COMPOSER,
1333 FileTag->composer,
1334 LIST_FILE_ORIG_ARTIST,
1335 FileTag->orig_artist,
1336 LIST_FILE_COPYRIGHT,
1337 FileTag->copyright,
1338 LIST_FILE_URL, FileTag->url,
1339 LIST_FILE_ENCODED_BY,
1340 FileTag->encoded_by, -1);
1341 g_free(basename_utf8);
1342 g_free(track);
1343 g_free (disc);
1344
1345 if (etfile_to_select == l->data)
1346 {
1347 Browser_List_Select_File_By_Iter (self, &rowIter, TRUE);
1348 //ET_Display_File_Data_To_UI (l->data);
1349 }
1350
1351 /* Set appearance of the row. */
1352 Browser_List_Set_Row_Appearance (self, &rowIter);
1353 }
1354 }
1355
1356
1357 /*
1358 * Update state of files in the list after changes (without clearing the list model!)
1359 * - Refresh 'filename' is file saved,
1360 * - Change color is something changed on the file
1361 */
1362 void
et_browser_refresh_list(EtBrowser * self)1363 et_browser_refresh_list (EtBrowser *self)
1364 {
1365 EtBrowserPrivate *priv;
1366 //GtkTreeIter iter;
1367 GtkTreePath *currentPath = NULL;
1368 GtkTreeIter iter;
1369 gint row;
1370 gchar *current_basename_utf8;
1371 gchar *track;
1372 gchar *disc;
1373 gboolean valid;
1374 GVariant *variant;
1375
1376 g_return_if_fail (ET_BROWSER (self));
1377
1378 priv = et_browser_get_instance_private (self);
1379
1380 if (!ETCore->ETFileDisplayedList || !priv->file_view
1381 || gtk_tree_model_iter_n_children(GTK_TREE_MODEL(priv->file_model), NULL) == 0)
1382 {
1383 return;
1384 }
1385
1386 // Browse the full list for changes
1387 //gtk_tree_model_get_iter_first(GTK_TREE_MODEL(priv->file_model), &iter);
1388 // g_print("above worked %d rows\n", gtk_tree_model_iter_n_children(GTK_TREE_MODEL(priv->file_model), NULL));
1389
1390 currentPath = gtk_tree_path_new_first();
1391
1392 valid = gtk_tree_model_get_iter(GTK_TREE_MODEL(priv->file_model), &iter, currentPath);
1393 while (valid)
1394 {
1395 const ET_File *ETFile;
1396 const File_Tag *FileTag;
1397 const File_Name *FileName;
1398 // Refresh filename and other fields
1399 gtk_tree_model_get(GTK_TREE_MODEL(priv->file_model), &iter,
1400 LIST_FILE_POINTER, &ETFile, -1);
1401
1402 FileName = (File_Name *)ETFile->FileNameCur->data;
1403 FileTag = (File_Tag *)ETFile->FileTag->data;
1404
1405 current_basename_utf8 = g_path_get_basename(FileName->value_utf8);
1406 track = g_strconcat(FileTag->track ? FileTag->track : "",FileTag->track_total ? "/" : NULL,FileTag->track_total,NULL);
1407 disc = g_strconcat (FileTag->disc_number ? FileTag->disc_number : "",
1408 FileTag->disc_total ? "/" : NULL,
1409 FileTag->disc_total, NULL);
1410
1411 gtk_list_store_set(priv->file_model, &iter,
1412 LIST_FILE_NAME, current_basename_utf8,
1413 LIST_FILE_TITLE, FileTag->title,
1414 LIST_FILE_ARTIST, FileTag->artist,
1415 LIST_FILE_ALBUM_ARTIST, FileTag->album_artist,
1416 LIST_FILE_ALBUM, FileTag->album,
1417 LIST_FILE_YEAR, FileTag->year,
1418 LIST_FILE_DISCNO, disc,
1419 LIST_FILE_TRACK, track,
1420 LIST_FILE_GENRE, FileTag->genre,
1421 LIST_FILE_COMMENT, FileTag->comment,
1422 LIST_FILE_COMPOSER, FileTag->composer,
1423 LIST_FILE_ORIG_ARTIST, FileTag->orig_artist,
1424 LIST_FILE_COPYRIGHT, FileTag->copyright,
1425 LIST_FILE_URL, FileTag->url,
1426 LIST_FILE_ENCODED_BY, FileTag->encoded_by,
1427 -1);
1428 g_free(current_basename_utf8);
1429 g_free(track);
1430 g_free (disc);
1431
1432 Browser_List_Set_Row_Appearance (self, &iter);
1433
1434 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(priv->file_model), &iter);
1435 }
1436 gtk_tree_path_free(currentPath);
1437
1438 variant = g_action_group_get_action_state (G_ACTION_GROUP (MainWindow),
1439 "file-artist-view");
1440
1441 // When displaying Artist + Album lists => refresh also rows color
1442 if (strcmp (g_variant_get_string (variant, NULL), "artist") == 0)
1443 {
1444
1445 for (row = 0; row < gtk_tree_model_iter_n_children (GTK_TREE_MODEL (priv->artist_model), NULL); row++)
1446 {
1447 if (row == 0)
1448 currentPath = gtk_tree_path_new_first();
1449 else
1450 gtk_tree_path_next(currentPath);
1451
1452 gtk_tree_model_get_iter(GTK_TREE_MODEL(priv->artist_model), &iter, currentPath);
1453 Browser_Artist_List_Set_Row_Appearance (self, &iter);
1454 }
1455 gtk_tree_path_free(currentPath);
1456
1457
1458 for (row=0; row < gtk_tree_model_iter_n_children(GTK_TREE_MODEL(priv->album_model), NULL); row++)
1459 {
1460 if (row == 0)
1461 currentPath = gtk_tree_path_new_first();
1462 else
1463 gtk_tree_path_next(currentPath);
1464
1465 gtk_tree_model_get_iter(GTK_TREE_MODEL(priv->album_model), &iter, currentPath);
1466 Browser_Album_List_Set_Row_Appearance (self, &iter);
1467 }
1468 gtk_tree_path_free(currentPath);
1469 }
1470
1471 g_variant_unref (variant);
1472 }
1473
1474
1475 /*
1476 * Update state of one file in the list after changes (without clearing the clist!)
1477 * - Refresh filename is file saved,
1478 * - Change color is something change on the file
1479 */
1480 void
et_browser_refresh_file_in_list(EtBrowser * self,const ET_File * ETFile)1481 et_browser_refresh_file_in_list (EtBrowser *self,
1482 const ET_File *ETFile)
1483 {
1484 EtBrowserPrivate *priv;
1485 GList *selectedRow = NULL;
1486 GVariant *variant;
1487 GtkTreeSelection *selection;
1488 GtkTreeIter selectedIter;
1489 const ET_File *etfile;
1490 const File_Tag *FileTag;
1491 const File_Name *FileName;
1492 gboolean row_found = FALSE;
1493 gchar *current_basename_utf8;
1494 gchar *track;
1495 gchar *disc;
1496 gboolean valid;
1497 gchar *artist, *album;
1498
1499 g_return_if_fail (ET_BROWSER (self));
1500
1501 priv = et_browser_get_instance_private (self);
1502
1503 if (!ETCore->ETFileDisplayedList || !priv->file_view || !ETFile ||
1504 gtk_tree_model_iter_n_children(GTK_TREE_MODEL(priv->file_model), NULL) == 0)
1505 {
1506 return;
1507 }
1508
1509 // Search the row of the modified file to update it (when found: row_found=TRUE)
1510 // 1/3. Get position of ETFile in ETFileList
1511 if (row_found == FALSE)
1512 {
1513 valid = gtk_tree_model_iter_nth_child (GTK_TREE_MODEL(priv->file_model), &selectedIter, NULL, ETFile->IndexKey-1);
1514 if (valid)
1515 {
1516 gtk_tree_model_get(GTK_TREE_MODEL(priv->file_model), &selectedIter,
1517 LIST_FILE_POINTER, &etfile, -1);
1518 if (ETFile->ETFileKey == etfile->ETFileKey)
1519 {
1520 row_found = TRUE;
1521 }
1522 }
1523 }
1524
1525 // 2/3. Try with the selected file in list (works only if we select the same file)
1526 if (row_found == FALSE)
1527 {
1528 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->file_view));
1529 selectedRow = gtk_tree_selection_get_selected_rows(selection, NULL);
1530 if (selectedRow && selectedRow->data != NULL)
1531 {
1532 valid = gtk_tree_model_get_iter(GTK_TREE_MODEL(priv->file_model), &selectedIter,
1533 (GtkTreePath*) selectedRow->data);
1534 if (valid)
1535 {
1536 gtk_tree_model_get(GTK_TREE_MODEL(priv->file_model), &selectedIter,
1537 LIST_FILE_POINTER, &etfile, -1);
1538 if (ETFile->ETFileKey == etfile->ETFileKey)
1539 {
1540 row_found = TRUE;
1541 }
1542 }
1543 }
1544
1545 g_list_free_full (selectedRow, (GDestroyNotify)gtk_tree_path_free);
1546 }
1547
1548 // 3/3. Fails, now we browse the full list to find it
1549 if (row_found == FALSE)
1550 {
1551 valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(priv->file_model), &selectedIter);
1552 while (valid)
1553 {
1554 gtk_tree_model_get(GTK_TREE_MODEL(priv->file_model), &selectedIter,
1555 LIST_FILE_POINTER, &etfile, -1);
1556 if (ETFile->ETFileKey == etfile->ETFileKey)
1557 {
1558 row_found = TRUE;
1559 break;
1560 } else
1561 {
1562 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(priv->file_model), &selectedIter);
1563 }
1564 }
1565 }
1566
1567 // Error somewhere...
1568 if (row_found == FALSE)
1569 return;
1570
1571 // Displayed the filename and refresh other fields
1572 FileName = (File_Name *)etfile->FileNameCur->data;
1573 FileTag = (File_Tag *)etfile->FileTag->data;
1574
1575 current_basename_utf8 = g_path_get_basename(FileName->value_utf8);
1576 track = g_strconcat(FileTag->track ? FileTag->track : "",FileTag->track_total ? "/" : NULL,FileTag->track_total,NULL);
1577 disc = g_strconcat (FileTag->disc_number ? FileTag->disc_number : "",
1578 FileTag->disc_total ? "/" : NULL, FileTag->disc_total,
1579 NULL);
1580
1581 gtk_list_store_set(priv->file_model, &selectedIter,
1582 LIST_FILE_NAME, current_basename_utf8,
1583 LIST_FILE_TITLE, FileTag->title,
1584 LIST_FILE_ARTIST, FileTag->artist,
1585 LIST_FILE_ALBUM_ARTIST, FileTag->album_artist,
1586 LIST_FILE_ALBUM, FileTag->album,
1587 LIST_FILE_YEAR, FileTag->year,
1588 LIST_FILE_DISCNO, disc,
1589 LIST_FILE_TRACK, track,
1590 LIST_FILE_GENRE, FileTag->genre,
1591 LIST_FILE_COMMENT, FileTag->comment,
1592 LIST_FILE_COMPOSER, FileTag->composer,
1593 LIST_FILE_ORIG_ARTIST, FileTag->orig_artist,
1594 LIST_FILE_COPYRIGHT, FileTag->copyright,
1595 LIST_FILE_URL, FileTag->url,
1596 LIST_FILE_ENCODED_BY, FileTag->encoded_by,
1597 -1);
1598 g_free(current_basename_utf8);
1599 g_free(track);
1600 g_free (disc);
1601
1602 /* Change appearance (line to red) if filename changed. */
1603 Browser_List_Set_Row_Appearance (self, &selectedIter);
1604
1605 variant = g_action_group_get_action_state (G_ACTION_GROUP (MainWindow),
1606 "file-artist-view");
1607
1608 /* When displaying Artist + Album lists => refresh also rows color. */
1609 if (strcmp (g_variant_get_string (variant, NULL), "artist") == 0)
1610 {
1611 gchar *current_artist = ((File_Tag *)ETFile->FileTag->data)->artist;
1612 gchar *current_album = ((File_Tag *)ETFile->FileTag->data)->album;
1613
1614 valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->artist_model),
1615 &selectedIter);
1616
1617 while (valid)
1618 {
1619 gtk_tree_model_get (GTK_TREE_MODEL (priv->artist_model),
1620 &selectedIter, ARTIST_NAME, &artist, -1);
1621
1622 if ((!current_artist && !artist)
1623 || (current_artist && artist
1624 && g_utf8_collate (current_artist, artist) == 0))
1625 {
1626 /* Set color of the row. */
1627 Browser_Artist_List_Set_Row_Appearance (self,
1628 &selectedIter);
1629 g_free (artist);
1630 break;
1631 }
1632
1633 g_free (artist);
1634
1635 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->artist_model),
1636 &selectedIter);
1637 }
1638
1639 //
1640 // FIX ME : see also if we must add a new line / or change list of the ETFile
1641 //
1642 valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->album_model),
1643 &selectedIter);
1644
1645 while (valid)
1646 {
1647 gtk_tree_model_get (GTK_TREE_MODEL (priv->album_model),
1648 &selectedIter, ALBUM_NAME, &album, -1);
1649
1650 if ((!current_album && !album)
1651 || (current_album && album
1652 && g_utf8_collate (current_album, album) == 0))
1653 {
1654 /* Set color of the row. */
1655 Browser_Album_List_Set_Row_Appearance (self, &selectedIter);
1656 g_free (album);
1657 break;
1658 }
1659
1660 g_free (album);
1661
1662 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->album_model),
1663 &selectedIter);
1664 }
1665
1666 //
1667 // FIX ME : see also if we must add a new line / or change list of the ETFile
1668 //
1669 }
1670
1671 g_variant_unref (variant);
1672 }
1673
1674
1675 /*
1676 * Set the appearance of the row
1677 * - change background according LIST_FILE_OTHERDIR
1678 * - change foreground according file status (saved or not)
1679 */
1680 static void
Browser_List_Set_Row_Appearance(EtBrowser * self,GtkTreeIter * iter)1681 Browser_List_Set_Row_Appearance (EtBrowser *self, GtkTreeIter *iter)
1682 {
1683 EtBrowserPrivate *priv;
1684 ET_File *rowETFile = NULL;
1685 gboolean otherdir = FALSE;
1686 const GdkRGBA LIGHT_BLUE = { 0.866, 0.933, 1.0, 1.0 };
1687 const GdkRGBA *background;
1688 //gchar *temp = NULL;
1689
1690 priv = et_browser_get_instance_private (self);
1691
1692 if (iter == NULL)
1693 return;
1694
1695 // Get the ETFile reference
1696 gtk_tree_model_get(GTK_TREE_MODEL(priv->file_model), iter,
1697 LIST_FILE_POINTER, &rowETFile,
1698 LIST_FILE_OTHERDIR, &otherdir,
1699 //LIST_FILE_NAME, &temp,
1700 -1);
1701
1702 // Must change background color?
1703 if (otherdir)
1704 background = &LIGHT_BLUE;
1705 else
1706 background = NULL;
1707
1708 // Set text to bold/red if 'filename' or 'tag' changed
1709 if (!et_file_check_saved (rowETFile))
1710 {
1711 if (g_settings_get_boolean (MainSettings, "file-changed-bold"))
1712 {
1713 gtk_list_store_set(priv->file_model, iter,
1714 LIST_FONT_WEIGHT, PANGO_WEIGHT_BOLD,
1715 LIST_ROW_BACKGROUND, background,
1716 LIST_ROW_FOREGROUND, NULL, -1);
1717 } else
1718 {
1719 gtk_list_store_set(priv->file_model, iter,
1720 LIST_FONT_WEIGHT, PANGO_WEIGHT_NORMAL,
1721 LIST_ROW_BACKGROUND, background,
1722 LIST_ROW_FOREGROUND, &RED, -1);
1723 }
1724 } else
1725 {
1726 gtk_list_store_set(priv->file_model, iter,
1727 LIST_FONT_WEIGHT, PANGO_WEIGHT_NORMAL,
1728 LIST_ROW_BACKGROUND, background,
1729 LIST_ROW_FOREGROUND, NULL ,-1);
1730 }
1731
1732 // Update text fields
1733 // Don't do it here
1734 /*if (rowETFile)
1735 {
1736 File_Tag *FileTag = ((File_Tag *)((ET_File *)rowETFile)->FileTag->data);
1737
1738 gtk_list_store_set(priv->file_model, iter,
1739 LIST_FILE_TITLE, FileTag->title,
1740 LIST_FILE_ARTIST, FileTag->artist,
1741 LIST_FILE_ALBUM_ARTIST, FileTag->album_artist,
1742 LIST_FILE_ALBUM, FileTag->album,
1743 LIST_FILE_YEAR, FileTag->year,
1744 LIST_FILE_TRACK, FileTag->track,
1745 LIST_FILE_GENRE, FileTag->genre,
1746 LIST_FILE_COMMENT, FileTag->comment,
1747 LIST_FILE_COMPOSER, FileTag->composer,
1748 LIST_FILE_ORIG_ARTIST, FileTag->orig_artist,
1749 LIST_FILE_COPYRIGHT, FileTag->copyright,
1750 LIST_FILE_URL, FileTag->url,
1751 LIST_FILE_ENCODED_BY, FileTag->encoded_by,
1752 -1);
1753 }*/
1754
1755 // Frees allocated item from gtk_tree_model_get...
1756 //g_free(temp);
1757 }
1758
1759
1760 /*
1761 * Remove a file from the list, by ETFile
1762 */
1763 void
et_browser_remove_file(EtBrowser * self,const ET_File * searchETFile)1764 et_browser_remove_file (EtBrowser *self,
1765 const ET_File *searchETFile)
1766 {
1767 EtBrowserPrivate *priv;
1768 gint row;
1769 GtkTreePath *currentPath = NULL;
1770 GtkTreeIter currentIter;
1771 ET_File *currentETFile;
1772 gboolean valid;
1773
1774 if (searchETFile == NULL)
1775 return;
1776
1777 priv = et_browser_get_instance_private (self);
1778
1779 // Go through the file list until it is found
1780 for (row=0; row < gtk_tree_model_iter_n_children(GTK_TREE_MODEL(priv->file_model), NULL); row++)
1781 {
1782 if (row == 0)
1783 currentPath = gtk_tree_path_new_first();
1784 else
1785 gtk_tree_path_next(currentPath);
1786
1787 valid = gtk_tree_model_get_iter(GTK_TREE_MODEL(priv->file_model), ¤tIter, currentPath);
1788 if (valid)
1789 {
1790 gtk_tree_model_get(GTK_TREE_MODEL(priv->file_model), ¤tIter,
1791 LIST_FILE_POINTER, ¤tETFile, -1);
1792
1793 if (currentETFile == searchETFile)
1794 {
1795 gtk_list_store_remove(priv->file_model, ¤tIter);
1796 break;
1797 }
1798 }
1799 }
1800
1801 gtk_tree_path_free (currentPath);
1802 }
1803
1804 /*
1805 * Get ETFile pointer of a file from a Tree Iter
1806 */
1807 ET_File *
et_browser_get_et_file_from_path(EtBrowser * self,GtkTreePath * path)1808 et_browser_get_et_file_from_path (EtBrowser *self, GtkTreePath *path)
1809 {
1810 EtBrowserPrivate *priv;
1811 GtkTreeIter iter;
1812
1813 g_return_val_if_fail (ET_BROWSER (self), NULL);
1814
1815 priv = et_browser_get_instance_private (self);
1816
1817 if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->file_model), &iter,
1818 path))
1819 {
1820 return NULL;
1821 }
1822
1823 return et_browser_get_et_file_from_iter (self, &iter);
1824 }
1825
1826 /*
1827 * Get ETFile pointer of a file from a Tree Iter
1828 */
1829 ET_File *
et_browser_get_et_file_from_iter(EtBrowser * self,GtkTreeIter * iter)1830 et_browser_get_et_file_from_iter (EtBrowser *self, GtkTreeIter *iter)
1831 {
1832 EtBrowserPrivate *priv;
1833 ET_File *etfile;
1834
1835 g_return_val_if_fail (ET_BROWSER (self), NULL);
1836
1837 priv = et_browser_get_instance_private (self);
1838
1839 gtk_tree_model_get (GTK_TREE_MODEL (priv->file_model), iter,
1840 LIST_FILE_POINTER, &etfile, -1);
1841 return etfile;
1842 }
1843
1844
1845 /*
1846 * Select the specified file in the list, by its ETFile
1847 */
1848 void
et_browser_select_file_by_et_file(EtBrowser * self,const ET_File * file,gboolean select_it)1849 et_browser_select_file_by_et_file (EtBrowser *self,
1850 const ET_File *file,
1851 gboolean select_it)
1852 {
1853 GtkTreePath *currentPath = NULL;
1854
1855 currentPath = et_browser_select_file_by_et_file2 (self, file, select_it,
1856 NULL);
1857
1858 if (currentPath)
1859 {
1860 gtk_tree_path_free (currentPath);
1861 }
1862 }
1863 /*
1864 * Select the specified file in the list, by its ETFile
1865 * - startPath : if set : starting path to try increase speed
1866 * - returns allocated "currentPath" to free
1867 */
1868 GtkTreePath *
et_browser_select_file_by_et_file2(EtBrowser * self,const ET_File * searchETFile,gboolean select_it,GtkTreePath * startPath)1869 et_browser_select_file_by_et_file2 (EtBrowser *self,
1870 const ET_File *searchETFile,
1871 gboolean select_it,
1872 GtkTreePath *startPath)
1873 {
1874 EtBrowserPrivate *priv;
1875 gint row;
1876 GtkTreePath *currentPath = NULL;
1877 GtkTreeIter currentIter;
1878 ET_File *currentETFile;
1879 gboolean valid;
1880
1881 g_return_val_if_fail (searchETFile != NULL, NULL);
1882
1883 priv = et_browser_get_instance_private (self);
1884
1885 // If the path is used, we try the next item (to increase speed), as it is correct in many cases...
1886 if (startPath)
1887 {
1888 // Try the next path
1889 gtk_tree_path_next(startPath);
1890 valid = gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->file_model),
1891 ¤tIter, startPath);
1892 if (valid)
1893 {
1894 gtk_tree_model_get(GTK_TREE_MODEL(priv->file_model), ¤tIter,
1895 LIST_FILE_POINTER, ¤tETFile, -1);
1896 // It is the good file?
1897 if (currentETFile == searchETFile)
1898 {
1899 Browser_List_Select_File_By_Iter (self, ¤tIter,
1900 select_it);
1901 return startPath;
1902 }
1903 }
1904 }
1905
1906 // Else, we try the whole list...
1907 // Go through the file list until it is found
1908 currentPath = gtk_tree_path_new_first();
1909 for (row=0; row < gtk_tree_model_iter_n_children(GTK_TREE_MODEL(priv->file_model), NULL); row++)
1910 {
1911 valid = gtk_tree_model_get_iter(GTK_TREE_MODEL(priv->file_model), ¤tIter, currentPath);
1912 if (valid)
1913 {
1914 gtk_tree_model_get(GTK_TREE_MODEL(priv->file_model), ¤tIter,
1915 LIST_FILE_POINTER, ¤tETFile, -1);
1916
1917 if (currentETFile == searchETFile)
1918 {
1919 Browser_List_Select_File_By_Iter (self, ¤tIter,
1920 select_it);
1921 return currentPath;
1922 //break;
1923 }
1924 }
1925 gtk_tree_path_next(currentPath);
1926 }
1927 gtk_tree_path_free(currentPath);
1928
1929 return NULL;
1930 }
1931
1932
1933 /*
1934 * Select the specified file in the list, by an iter
1935 */
1936 static void
Browser_List_Select_File_By_Iter(EtBrowser * self,GtkTreeIter * rowIter,gboolean select_it)1937 Browser_List_Select_File_By_Iter (EtBrowser *self,
1938 GtkTreeIter *rowIter,
1939 gboolean select_it)
1940 {
1941 EtBrowserPrivate *priv;
1942
1943 priv = et_browser_get_instance_private (self);
1944
1945 if (select_it)
1946 {
1947 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->file_view));
1948
1949 if (selection)
1950 {
1951 g_signal_handler_block (selection, priv->file_selected_handler);
1952 gtk_tree_selection_select_iter(selection, rowIter);
1953 g_signal_handler_unblock (selection, priv->file_selected_handler);
1954 }
1955 }
1956 et_browser_set_row_visible (self, rowIter);
1957 }
1958
1959 /*
1960 * Select the specified file in the list, by a string representation of an iter
1961 * e.g. output of gtk_tree_model_get_string_from_iter()
1962 */
1963 void
et_browser_select_file_by_iter_string(EtBrowser * self,const gchar * stringIter,gboolean select_it)1964 et_browser_select_file_by_iter_string (EtBrowser *self,
1965 const gchar* stringIter,
1966 gboolean select_it)
1967 {
1968 EtBrowserPrivate *priv;
1969 GtkTreeIter iter;
1970
1971 priv = et_browser_get_instance_private (self);
1972
1973 g_return_if_fail (priv->file_model != NULL || priv->file_view != NULL);
1974
1975 if (gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(priv->file_model), &iter, stringIter))
1976 {
1977 if (select_it)
1978 {
1979 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->file_view));
1980
1981 // FIX ME : Why signal was blocked if selected? Don't remember...
1982 if (selection)
1983 {
1984 //g_signal_handlers_block_by_func(G_OBJECT(selection),G_CALLBACK(Browser_List_Row_Selected),NULL);
1985 gtk_tree_selection_select_iter(selection, &iter);
1986 //g_signal_handlers_unblock_by_func(G_OBJECT(selection),G_CALLBACK(Browser_List_Row_Selected),NULL);
1987 }
1988 }
1989 et_browser_set_row_visible (self, &iter);
1990 }
1991 }
1992
1993 /*
1994 * Select the specified file in the list, by fuzzy string matching based on
1995 * the Damerau-Levenshtein Metric (patch from Santtu Lakkala - 23/08/2004)
1996 */
1997 ET_File *
et_browser_select_file_by_dlm(EtBrowser * self,const gchar * string,gboolean select_it)1998 et_browser_select_file_by_dlm (EtBrowser *self,
1999 const gchar* string,
2000 gboolean select_it)
2001 {
2002 EtBrowserPrivate *priv;
2003 GtkTreeIter iter;
2004 GtkTreeIter iter2;
2005 GtkTreeSelection *selection;
2006 ET_File *current_etfile = NULL, *retval = NULL;
2007 gchar *current_filename = NULL, *current_title = NULL;
2008 int max = 0, this;
2009
2010 priv = et_browser_get_instance_private (self);
2011
2012 g_return_val_if_fail (priv->file_model != NULL || priv->file_view != NULL, NULL);
2013
2014 if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->file_model),
2015 &iter))
2016 {
2017 do
2018 {
2019 gtk_tree_model_get(GTK_TREE_MODEL(priv->file_model), &iter,
2020 LIST_FILE_NAME, ¤t_filename,
2021 LIST_FILE_POINTER, ¤t_etfile, -1);
2022 current_title = ((File_Tag *)current_etfile->FileTag->data)->title;
2023
2024 if ((this = dlm((current_title ? current_title : current_filename), string)) > max) // See "dlm.c"
2025 {
2026 max = this;
2027 iter2 = iter;
2028 retval = current_etfile;
2029 }
2030
2031 g_free (current_filename);
2032 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(priv->file_model), &iter));
2033
2034 if (select_it)
2035 {
2036 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->file_view));
2037 if (selection)
2038 {
2039 g_signal_handler_block (selection,
2040 priv->file_selected_handler);
2041 gtk_tree_selection_select_iter(selection, &iter2);
2042 g_signal_handler_unblock (selection,
2043 priv->file_selected_handler);
2044 }
2045 }
2046 et_browser_set_row_visible (self, &iter2);
2047 }
2048 return retval;
2049 }
2050
2051 /*
2052 * Clear all entries on the file list
2053 */
2054 void
et_browser_clear(EtBrowser * self)2055 et_browser_clear (EtBrowser *self)
2056 {
2057 g_return_if_fail (ET_BROWSER (self));
2058
2059 et_browser_clear_file_model (self);
2060 et_browser_clear_artist_model (self);
2061 et_browser_clear_album_model (self);
2062 }
2063
2064 /*
2065 * Refresh the list sorting (call me after sort-mode has changed)
2066 */
2067 void
et_browser_refresh_sort(EtBrowser * self)2068 et_browser_refresh_sort (EtBrowser *self)
2069 {
2070 EtBrowserPrivate *priv;
2071
2072 g_return_if_fail (ET_BROWSER (self));
2073
2074 priv = et_browser_get_instance_private (self);
2075
2076 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (priv->file_model), 0,
2077 Browser_List_Sort_Func, NULL, NULL);
2078 }
2079
2080 /*
2081 * Intelligently sort the file list based on the current sorting method
2082 * see also 'ET_Sort_File_List'
2083 */
2084 static gint
Browser_List_Sort_Func(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer data)2085 Browser_List_Sort_Func (GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
2086 gpointer data)
2087 {
2088 ET_File *ETFile1;
2089 ET_File *ETFile2;
2090 gint result = 0;
2091
2092 gtk_tree_model_get(model, a, LIST_FILE_POINTER, &ETFile1, -1);
2093 gtk_tree_model_get(model, b, LIST_FILE_POINTER, &ETFile2, -1);
2094
2095 switch (g_settings_get_enum (MainSettings, "sort-mode"))
2096 {
2097 case ET_SORT_MODE_ASCENDING_FILENAME:
2098 result = ET_Comp_Func_Sort_File_By_Ascending_Filename(ETFile1, ETFile2);
2099 break;
2100 case ET_SORT_MODE_DESCENDING_FILENAME:
2101 result = ET_Comp_Func_Sort_File_By_Descending_Filename(ETFile1, ETFile2);
2102 break;
2103 case ET_SORT_MODE_ASCENDING_TITLE:
2104 result = ET_Comp_Func_Sort_File_By_Ascending_Title(ETFile1, ETFile2);
2105 break;
2106 case ET_SORT_MODE_DESCENDING_TITLE:
2107 result = ET_Comp_Func_Sort_File_By_Descending_Title(ETFile1, ETFile2);
2108 break;
2109 case ET_SORT_MODE_ASCENDING_ARTIST:
2110 result = ET_Comp_Func_Sort_File_By_Ascending_Artist(ETFile1, ETFile2);
2111 break;
2112 case ET_SORT_MODE_DESCENDING_ARTIST:
2113 result = ET_Comp_Func_Sort_File_By_Descending_Artist(ETFile1, ETFile2);
2114 break;
2115 case ET_SORT_MODE_ASCENDING_ALBUM_ARTIST:
2116 result = ET_Comp_Func_Sort_File_By_Ascending_Album_Artist(ETFile1, ETFile2);
2117 break;
2118 case ET_SORT_MODE_DESCENDING_ALBUM_ARTIST:
2119 result = ET_Comp_Func_Sort_File_By_Descending_Album_Artist(ETFile1, ETFile2);
2120 break;
2121 case ET_SORT_MODE_ASCENDING_ALBUM:
2122 result = ET_Comp_Func_Sort_File_By_Ascending_Album(ETFile1, ETFile2);
2123 break;
2124 case ET_SORT_MODE_DESCENDING_ALBUM:
2125 result = ET_Comp_Func_Sort_File_By_Descending_Album(ETFile1, ETFile2);
2126 break;
2127 case ET_SORT_MODE_ASCENDING_YEAR:
2128 result = ET_Comp_Func_Sort_File_By_Ascending_Year(ETFile1, ETFile2);
2129 break;
2130 case ET_SORT_MODE_DESCENDING_YEAR:
2131 result = ET_Comp_Func_Sort_File_By_Descending_Year(ETFile1, ETFile2);
2132 break;
2133 case ET_SORT_MODE_ASCENDING_DISC_NUMBER:
2134 result = et_comp_func_sort_file_by_ascending_disc_number (ETFile1,
2135 ETFile2);
2136 break;
2137 case ET_SORT_MODE_DESCENDING_DISC_NUMBER:
2138 result = et_comp_func_sort_file_by_descending_disc_number (ETFile1,
2139 ETFile2);
2140 break;
2141 case ET_SORT_MODE_ASCENDING_TRACK_NUMBER:
2142 result = ET_Comp_Func_Sort_File_By_Ascending_Track_Number (ETFile1, ETFile2);
2143 break;
2144 case ET_SORT_MODE_DESCENDING_TRACK_NUMBER:
2145 result = ET_Comp_Func_Sort_File_By_Descending_Track_Number (ETFile1, ETFile2);
2146 break;
2147 case ET_SORT_MODE_ASCENDING_GENRE:
2148 result = ET_Comp_Func_Sort_File_By_Ascending_Genre(ETFile1, ETFile2);
2149 break;
2150 case ET_SORT_MODE_DESCENDING_GENRE:
2151 result = ET_Comp_Func_Sort_File_By_Descending_Genre(ETFile1, ETFile2);
2152 break;
2153 case ET_SORT_MODE_ASCENDING_COMMENT:
2154 result = ET_Comp_Func_Sort_File_By_Ascending_Comment(ETFile1, ETFile2);
2155 break;
2156 case ET_SORT_MODE_DESCENDING_COMMENT:
2157 result = ET_Comp_Func_Sort_File_By_Descending_Comment(ETFile1, ETFile2);
2158 break;
2159 case ET_SORT_MODE_ASCENDING_COMPOSER:
2160 result = ET_Comp_Func_Sort_File_By_Ascending_Composer(ETFile1, ETFile2);
2161 break;
2162 case ET_SORT_MODE_DESCENDING_COMPOSER:
2163 result = ET_Comp_Func_Sort_File_By_Descending_Composer(ETFile1, ETFile2);
2164 break;
2165 case ET_SORT_MODE_ASCENDING_ORIG_ARTIST:
2166 result = ET_Comp_Func_Sort_File_By_Ascending_Orig_Artist(ETFile1, ETFile2);
2167 break;
2168 case ET_SORT_MODE_DESCENDING_ORIG_ARTIST:
2169 result = ET_Comp_Func_Sort_File_By_Descending_Orig_Artist(ETFile1, ETFile2);
2170 break;
2171 case ET_SORT_MODE_ASCENDING_COPYRIGHT:
2172 result = ET_Comp_Func_Sort_File_By_Ascending_Copyright(ETFile1, ETFile2);
2173 break;
2174 case ET_SORT_MODE_DESCENDING_COPYRIGHT:
2175 result = ET_Comp_Func_Sort_File_By_Descending_Copyright(ETFile1, ETFile2);
2176 break;
2177 case ET_SORT_MODE_ASCENDING_URL:
2178 result = ET_Comp_Func_Sort_File_By_Ascending_Url(ETFile1, ETFile2);
2179 break;
2180 case ET_SORT_MODE_DESCENDING_URL:
2181 result = ET_Comp_Func_Sort_File_By_Descending_Url(ETFile1, ETFile2);
2182 break;
2183 case ET_SORT_MODE_ASCENDING_ENCODED_BY:
2184 result = ET_Comp_Func_Sort_File_By_Ascending_Encoded_By(ETFile1, ETFile2);
2185 break;
2186 case ET_SORT_MODE_DESCENDING_ENCODED_BY:
2187 result = ET_Comp_Func_Sort_File_By_Descending_Encoded_By(ETFile1, ETFile2);
2188 break;
2189 case ET_SORT_MODE_ASCENDING_CREATION_DATE:
2190 result = ET_Comp_Func_Sort_File_By_Ascending_Creation_Date (ETFile1,
2191 ETFile2);
2192 break;
2193 case ET_SORT_MODE_DESCENDING_CREATION_DATE:
2194 result = ET_Comp_Func_Sort_File_By_Descending_Creation_Date (ETFile1,
2195 ETFile2);
2196 break;
2197 case ET_SORT_MODE_ASCENDING_FILE_TYPE:
2198 result = ET_Comp_Func_Sort_File_By_Ascending_File_Type(ETFile1, ETFile2);
2199 break;
2200 case ET_SORT_MODE_DESCENDING_FILE_TYPE:
2201 result = ET_Comp_Func_Sort_File_By_Descending_File_Type(ETFile1, ETFile2);
2202 break;
2203 case ET_SORT_MODE_ASCENDING_FILE_SIZE:
2204 result = ET_Comp_Func_Sort_File_By_Ascending_File_Size(ETFile1, ETFile2);
2205 break;
2206 case ET_SORT_MODE_DESCENDING_FILE_SIZE:
2207 result = ET_Comp_Func_Sort_File_By_Descending_File_Size(ETFile1, ETFile2);
2208 break;
2209 case ET_SORT_MODE_ASCENDING_FILE_DURATION:
2210 result = ET_Comp_Func_Sort_File_By_Ascending_File_Duration(ETFile1, ETFile2);
2211 break;
2212 case ET_SORT_MODE_DESCENDING_FILE_DURATION:
2213 result = ET_Comp_Func_Sort_File_By_Descending_File_Duration(ETFile1, ETFile2);
2214 break;
2215 case ET_SORT_MODE_ASCENDING_FILE_BITRATE:
2216 result = ET_Comp_Func_Sort_File_By_Ascending_File_Bitrate(ETFile1, ETFile2);
2217 break;
2218 case ET_SORT_MODE_DESCENDING_FILE_BITRATE:
2219 result = ET_Comp_Func_Sort_File_By_Descending_File_Bitrate(ETFile1, ETFile2);
2220 break;
2221 case ET_SORT_MODE_ASCENDING_FILE_SAMPLERATE:
2222 result = ET_Comp_Func_Sort_File_By_Ascending_File_Samplerate(ETFile1, ETFile2);
2223 break;
2224 case ET_SORT_MODE_DESCENDING_FILE_SAMPLERATE:
2225 result = ET_Comp_Func_Sort_File_By_Descending_File_Samplerate(ETFile1, ETFile2);
2226 break;
2227 default:
2228 g_assert_not_reached ();
2229 break;
2230 }
2231
2232 return result;
2233 }
2234
2235 /*
2236 * Select all files on the file list
2237 */
2238 void
et_browser_select_all(EtBrowser * self)2239 et_browser_select_all (EtBrowser *self)
2240 {
2241 EtBrowserPrivate *priv;
2242 GtkTreeSelection *selection;
2243
2244 g_return_if_fail (ET_BROWSER (self));
2245
2246 priv = et_browser_get_instance_private (self);
2247 selection = et_browser_get_selection (self);
2248
2249 if (selection)
2250 {
2251 /* Must block the select signal to avoid the selecting, one by one, of
2252 * all files in the main files list. */
2253 g_signal_handler_block (selection, priv->file_selected_handler);
2254 gtk_tree_selection_select_all(selection);
2255 g_signal_handler_unblock (selection, priv->file_selected_handler);
2256 }
2257 }
2258
2259 /*
2260 * Unselect all files on the file list
2261 */
2262 void
et_browser_unselect_all(EtBrowser * self)2263 et_browser_unselect_all (EtBrowser *self)
2264 {
2265 GtkTreeSelection *selection;
2266
2267 selection = et_browser_get_selection (self);
2268
2269 if (selection)
2270 {
2271 gtk_tree_selection_unselect_all (selection);
2272 }
2273 }
2274
2275 /*
2276 * Invert the selection of the file list
2277 */
2278 void
et_browser_invert_selection(EtBrowser * self)2279 et_browser_invert_selection (EtBrowser *self)
2280 {
2281 EtBrowserPrivate *priv;
2282 GtkTreeIter iter;
2283 GtkTreeSelection *selection;
2284 gboolean valid;
2285
2286 priv = et_browser_get_instance_private (self);
2287
2288 g_return_if_fail (priv->file_model != NULL || priv->file_view != NULL);
2289
2290 selection = et_browser_get_selection (self);
2291 if (selection)
2292 {
2293 /* Must block the select signal to avoid selecting all files (one by
2294 * one) in the main files list. */
2295 g_signal_handler_block (selection, priv->file_selected_handler);
2296 valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(priv->file_model), &iter);
2297 while (valid)
2298 {
2299 if (gtk_tree_selection_iter_is_selected(selection, &iter))
2300 {
2301 gtk_tree_selection_unselect_iter(selection, &iter);
2302 } else
2303 {
2304 gtk_tree_selection_select_iter(selection, &iter);
2305 }
2306 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(priv->file_model), &iter);
2307 }
2308 g_signal_handler_unblock (selection, priv->file_selected_handler);
2309 }
2310 }
2311
2312 void
et_browser_clear_artist_model(EtBrowser * self)2313 et_browser_clear_artist_model (EtBrowser *self)
2314 {
2315 EtBrowserPrivate *priv;
2316 GtkTreeSelection *selection;
2317
2318 /* Empty Model, Disable Browser_Artist_List_Row_Selected() during clear
2319 * because it may be called and may crash.
2320 */
2321
2322 priv = et_browser_get_instance_private (self);
2323
2324 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->artist_view));
2325
2326 g_signal_handler_block (selection, priv->artist_selected_handler);
2327
2328 gtk_list_store_clear (priv->artist_model);
2329
2330 g_signal_handler_unblock (selection, priv->artist_selected_handler);
2331 }
2332
2333 static void
Browser_Artist_List_Load_Files(EtBrowser * self,ET_File * etfile_to_select)2334 Browser_Artist_List_Load_Files (EtBrowser *self, ET_File *etfile_to_select)
2335 {
2336 EtBrowserPrivate *priv;
2337 GList *AlbumList;
2338 GList *etfilelist;
2339 ET_File *etfile;
2340 GList *l;
2341 GList *m;
2342 GtkTreeIter iter;
2343 GtkTreeSelection *selection;
2344 gchar *artistname, *artist_to_select = NULL;
2345
2346 priv = et_browser_get_instance_private (self);
2347
2348 g_return_if_fail (priv->artist_view != NULL);
2349
2350 if (etfile_to_select)
2351 artist_to_select = ((File_Tag *)etfile_to_select->FileTag->data)->artist;
2352
2353 et_browser_clear_artist_model (self);
2354 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->artist_view));
2355
2356 for (l = ETCore->ETArtistAlbumFileList; l != NULL; l = g_list_next (l))
2357 {
2358 gint nbr_files = 0;
2359 GdkPixbuf* pixbuf;
2360
2361 // Insert a line for each artist
2362 AlbumList = (GList *)l->data;
2363 etfilelist = (GList *)AlbumList->data;
2364 etfile = (ET_File *)etfilelist->data;
2365 artistname = ((File_Tag *)etfile->FileTag->data)->artist;
2366
2367 // Third column text : number of files
2368 for (m = g_list_first (AlbumList); m != NULL; m = g_list_next (m))
2369 {
2370 nbr_files += g_list_length (g_list_first ((GList *)m->data));
2371 }
2372
2373 /* Add the new row. */
2374 pixbuf = gdk_pixbuf_new_from_resource ("/org/gnome/EasyTAG/images/artist.png",
2375 NULL);
2376 gtk_list_store_insert_with_values (priv->artist_model, &iter, G_MAXINT,
2377 ARTIST_PIXBUF, pixbuf,
2378 ARTIST_NAME, artistname,
2379 ARTIST_NUM_ALBUMS,
2380 g_list_length (g_list_first (AlbumList)),
2381 ARTIST_NUM_FILES, nbr_files,
2382 ARTIST_ALBUM_LIST_POINTER,
2383 AlbumList, -1);
2384
2385 g_object_unref (pixbuf);
2386
2387 // Todo: Use something better than string comparison
2388 if ( (!artistname && !artist_to_select)
2389 || (artistname && artist_to_select && strcmp(artistname,artist_to_select) == 0) )
2390 {
2391 GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(priv->artist_model), &iter);
2392
2393 g_signal_handler_block (selection, priv->artist_selected_handler);
2394 gtk_tree_selection_select_iter(selection, &iter);
2395 g_signal_handler_unblock (selection, priv->artist_selected_handler);
2396
2397 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(priv->artist_view), path, NULL, FALSE, 0, 0);
2398 gtk_tree_path_free(path);
2399
2400 Browser_Album_List_Load_Files (self, AlbumList, etfile_to_select);
2401
2402 // Now that we've found the artist, no need to continue searching
2403 artist_to_select = NULL;
2404 }
2405
2406 // Set color of the row
2407 Browser_Artist_List_Set_Row_Appearance (self, &iter);
2408 }
2409
2410 // Select the first line if we weren't asked to select anything
2411 if (!etfile_to_select && gtk_tree_model_get_iter_first(GTK_TREE_MODEL(priv->artist_model), &iter))
2412 {
2413 gtk_tree_model_get(GTK_TREE_MODEL(priv->artist_model), &iter,
2414 ARTIST_ALBUM_LIST_POINTER, &AlbumList,
2415 -1);
2416 et_application_window_update_et_file_from_ui (ET_APPLICATION_WINDOW (MainWindow));
2417 Browser_Album_List_Load_Files (self, AlbumList,NULL);
2418 }
2419 }
2420
2421
2422 /*
2423 * Callback to select-row event
2424 */
2425 static void
Browser_Artist_List_Row_Selected(EtBrowser * self,GtkTreeSelection * selection)2426 Browser_Artist_List_Row_Selected (EtBrowser *self, GtkTreeSelection* selection)
2427 {
2428 EtBrowserPrivate *priv;
2429 GList *AlbumList;
2430 GtkTreeIter iter;
2431
2432 priv = et_browser_get_instance_private (self);
2433
2434 // Display the relevant albums
2435 if(!gtk_tree_selection_get_selected(selection, NULL, &iter))
2436 return; // We might be called with no row selected
2437
2438 et_application_window_update_et_file_from_ui (ET_APPLICATION_WINDOW (MainWindow));
2439
2440 gtk_tree_model_get (GTK_TREE_MODEL (priv->artist_model), &iter,
2441 ARTIST_ALBUM_LIST_POINTER, &AlbumList, -1);
2442 Browser_Album_List_Load_Files (self, AlbumList, NULL);
2443 }
2444
2445 /*
2446 * Set the color of the row of priv->artist_view
2447 */
2448 static void
Browser_Artist_List_Set_Row_Appearance(EtBrowser * self,GtkTreeIter * iter)2449 Browser_Artist_List_Set_Row_Appearance (EtBrowser *self, GtkTreeIter *iter)
2450 {
2451 EtBrowserPrivate *priv;
2452 GList *l;
2453 GList *m;
2454 gboolean not_all_saved = FALSE;
2455
2456 priv = et_browser_get_instance_private (self);
2457
2458 // Change the style (red/bold) of the row if one of the files was changed
2459 for (gtk_tree_model_get (GTK_TREE_MODEL (priv->artist_model), iter,
2460 ARTIST_ALBUM_LIST_POINTER, &l, -1);
2461 l != NULL; l = g_list_next (l))
2462 {
2463 for (m = (GList *)l->data; m != NULL; m = g_list_next (m))
2464 {
2465 if (!et_file_check_saved ((ET_File *)m->data))
2466 {
2467 if (g_settings_get_boolean (MainSettings, "file-changed-bold"))
2468 {
2469 // Set the font-style to "bold"
2470 gtk_list_store_set(priv->artist_model, iter,
2471 ARTIST_FONT_WEIGHT, PANGO_WEIGHT_BOLD, -1);
2472 } else
2473 {
2474 // Set the background-color to "red"
2475 gtk_list_store_set(priv->artist_model, iter,
2476 ARTIST_FONT_WEIGHT, PANGO_WEIGHT_NORMAL,
2477 ARTIST_ROW_FOREGROUND, &RED, -1);
2478 }
2479 not_all_saved = TRUE;
2480 break;
2481 }
2482 }
2483 }
2484
2485 // Reset style if all files saved
2486 if (not_all_saved == FALSE)
2487 {
2488 gtk_list_store_set(priv->artist_model, iter,
2489 ARTIST_FONT_WEIGHT, PANGO_WEIGHT_NORMAL,
2490 ARTIST_ROW_FOREGROUND, NULL, -1);
2491 }
2492 }
2493
2494 void
et_browser_clear_album_model(EtBrowser * self)2495 et_browser_clear_album_model (EtBrowser *self)
2496 {
2497 EtBrowserPrivate *priv;
2498 GtkTreeSelection *selection;
2499 gboolean valid;
2500 GtkTreeIter iter;
2501
2502 g_return_if_fail (ET_BROWSER (self));
2503
2504 priv = et_browser_get_instance_private (self);
2505
2506 /* Free the attached list in the "all albums" row. */
2507 valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (priv->album_model),
2508 &iter);
2509
2510 while (valid)
2511 {
2512 GList *l;
2513 gboolean all_albums_row = FALSE;
2514
2515 gtk_tree_model_get (GTK_TREE_MODEL (priv->album_model), &iter,
2516 ALBUM_ETFILE_LIST_POINTER, &l,
2517 ALBUM_ALL_ALBUMS_ROW, &all_albums_row, -1);
2518
2519 if (all_albums_row && l)
2520 {
2521 g_list_free (l);
2522 break;
2523 }
2524
2525 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (priv->album_model),
2526 &iter);
2527 }
2528
2529 /* Empty model, disable Browser_Album_List_Row_Selected () during clear
2530 * because it is called and crashed. */
2531
2532 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->album_view));
2533
2534 g_signal_handler_block (selection, priv->album_selected_handler);
2535
2536 gtk_list_store_clear (priv->album_model);
2537
2538 g_signal_handler_unblock (selection, priv->album_selected_handler);
2539 }
2540
2541 /*
2542 * Load the list of Albums for each Artist
2543 */
2544 static void
Browser_Album_List_Load_Files(EtBrowser * self,GList * albumlist,ET_File * etfile_to_select)2545 Browser_Album_List_Load_Files (EtBrowser *self,
2546 GList *albumlist,
2547 ET_File *etfile_to_select)
2548 {
2549 EtBrowserPrivate *priv;
2550 GList *l;
2551 GList *etfilelist = NULL;
2552 ET_File *etfile;
2553 GtkTreeIter iter;
2554 GtkTreeSelection *selection;
2555 gchar *albumname, *album_to_select = NULL;
2556
2557 priv = et_browser_get_instance_private (self);
2558
2559 g_return_if_fail (priv->album_view != NULL);
2560
2561 if (etfile_to_select)
2562 album_to_select = ((File_Tag *)etfile_to_select->FileTag->data)->album;
2563
2564 et_browser_clear_album_model (self);
2565 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->album_view));
2566
2567 // Create a first row to select all albums of the artist
2568 for (l = albumlist; l != NULL; l = g_list_next (l))
2569 {
2570 GList *etfilelist_tmp;
2571
2572 etfilelist_tmp = (GList *)l->data;
2573 // We must make a copy to not "alter" the initial list by appending another list
2574 etfilelist_tmp = g_list_copy(etfilelist_tmp);
2575 etfilelist = g_list_concat(etfilelist, etfilelist_tmp);
2576 }
2577
2578 gtk_list_store_insert_with_values (priv->album_model, &iter, G_MAXINT,
2579 ALBUM_NAME, _("All albums"),
2580 ALBUM_NUM_FILES,
2581 g_list_length (g_list_first (etfilelist)),
2582 ALBUM_ETFILE_LIST_POINTER, etfilelist,
2583 ALBUM_ALL_ALBUMS_ROW, TRUE,
2584 -1);
2585
2586 gtk_list_store_insert_with_values (priv->album_model, &iter, G_MAXINT,
2587 ALBUM_ALL_ALBUMS_ROW, FALSE,
2588 ALBUM_ALL_ALBUMS_SEPARATOR_ROW, TRUE,
2589 -1);
2590
2591 // Create a line for each album of the artist
2592 for (l = albumlist; l != NULL; l = g_list_next (l))
2593 {
2594 GIcon *icon;
2595
2596 // Insert a line for each album
2597 etfilelist = (GList *)l->data;
2598 etfile = (ET_File *)etfilelist->data;
2599 albumname = ((File_Tag *)etfile->FileTag->data)->album;
2600
2601 /* TODO: Make the icon use the symbolic variant. */
2602 icon = g_themed_icon_new_with_default_fallbacks ("media-optical-cd-audio");
2603
2604 /* Add the new row. */
2605 gtk_list_store_insert_with_values (priv->album_model, &iter, G_MAXINT,
2606 ALBUM_GICON, icon,
2607 ALBUM_NAME, albumname,
2608 ALBUM_NUM_FILES,
2609 g_list_length (g_list_first (etfilelist)),
2610 ALBUM_ETFILE_LIST_POINTER,
2611 etfilelist, -1);
2612
2613 g_object_unref (icon);
2614
2615 if ( (!albumname && !album_to_select)
2616 || (albumname && album_to_select && strcmp(albumname,album_to_select) == 0) )
2617 {
2618 GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(priv->album_model), &iter);
2619
2620 g_signal_handler_block (selection, priv->album_selected_handler);
2621 gtk_tree_selection_select_iter(selection, &iter);
2622 g_signal_handler_unblock (selection, priv->album_selected_handler);
2623
2624 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(priv->album_view), path, NULL, FALSE, 0, 0);
2625 gtk_tree_path_free(path);
2626
2627 et_displayed_file_list_set (etfilelist);
2628 et_browser_load_file_list (self, etfilelist, etfile_to_select);
2629
2630 // Now that we've found the album, no need to continue searching
2631 album_to_select = NULL;
2632 }
2633
2634 // Set color of the row
2635 Browser_Album_List_Set_Row_Appearance (self, &iter);
2636 }
2637
2638 // Select the first line if we werent asked to select anything
2639 if (!etfile_to_select && gtk_tree_model_get_iter_first(GTK_TREE_MODEL(priv->album_model), &iter))
2640 {
2641 gtk_tree_model_get(GTK_TREE_MODEL(priv->album_model), &iter,
2642 ALBUM_ETFILE_LIST_POINTER, &etfilelist,
2643 -1);
2644 et_application_window_update_et_file_from_ui (ET_APPLICATION_WINDOW (MainWindow));
2645
2646 /* Set the attached list as "Displayed List". */
2647 et_displayed_file_list_set (etfilelist);
2648 et_browser_load_file_list (self, etfilelist, NULL);
2649
2650 /* Displays the first item. */
2651 et_application_window_select_file_by_et_file (ET_APPLICATION_WINDOW (MainWindow),
2652 (ET_File *)etfilelist->data);
2653 }
2654 }
2655
2656 /*
2657 * Callback to select-row event
2658 */
2659 static void
Browser_Album_List_Row_Selected(EtBrowser * self,GtkTreeSelection * selection)2660 Browser_Album_List_Row_Selected (EtBrowser *self, GtkTreeSelection *selection)
2661 {
2662 EtBrowserPrivate *priv;
2663 GList *etfilelist;
2664 GtkTreeIter iter;
2665
2666 priv = et_browser_get_instance_private (self);
2667
2668 // We might be called with no rows selected
2669 if (!gtk_tree_selection_get_selected(selection, NULL, &iter))
2670 return;
2671
2672 gtk_tree_model_get (GTK_TREE_MODEL (priv->album_model), &iter,
2673 ALBUM_ETFILE_LIST_POINTER, &etfilelist, -1);
2674
2675 et_application_window_update_et_file_from_ui (ET_APPLICATION_WINDOW (MainWindow));
2676
2677 /* Set the attached list as "Displayed List". */
2678 et_displayed_file_list_set (etfilelist);
2679
2680 et_browser_load_file_list (self, etfilelist, NULL);
2681
2682 /* Displays the first item. */
2683 et_application_window_select_file_by_et_file (ET_APPLICATION_WINDOW (MainWindow),
2684 (ET_File *)etfilelist->data);
2685 }
2686
2687 /*
2688 * Set the color of the row of priv->album_view
2689 */
2690 static void
Browser_Album_List_Set_Row_Appearance(EtBrowser * self,GtkTreeIter * iter)2691 Browser_Album_List_Set_Row_Appearance (EtBrowser *self, GtkTreeIter *iter)
2692 {
2693 EtBrowserPrivate *priv;
2694 GList *l;
2695 gboolean not_all_saved = FALSE;
2696
2697 priv = et_browser_get_instance_private (self);
2698
2699 // Change the style (red/bold) of the row if one of the files was changed
2700 for (gtk_tree_model_get (GTK_TREE_MODEL (priv->album_model), iter,
2701 ALBUM_ETFILE_LIST_POINTER, &l, -1);
2702 l != NULL; l = g_list_next (l))
2703 {
2704 if (!et_file_check_saved ((ET_File *)l->data))
2705 {
2706 if (g_settings_get_boolean (MainSettings, "file-changed-bold"))
2707 {
2708 // Set the font-style to "bold"
2709 gtk_list_store_set(priv->album_model, iter,
2710 ALBUM_FONT_WEIGHT, PANGO_WEIGHT_BOLD, -1);
2711 } else
2712 {
2713 // Set the background-color to "red"
2714 gtk_list_store_set(priv->album_model, iter,
2715 ALBUM_FONT_WEIGHT, PANGO_WEIGHT_NORMAL,
2716 ALBUM_ROW_FOREGROUND, &RED, -1);
2717 }
2718 not_all_saved = TRUE;
2719 break;
2720 }
2721 }
2722
2723 // Reset style if all files saved
2724 if (not_all_saved == FALSE)
2725 {
2726 gtk_list_store_set(priv->album_model, iter,
2727 ALBUM_FONT_WEIGHT, PANGO_WEIGHT_NORMAL,
2728 ALBUM_ROW_FOREGROUND, NULL, -1);
2729 }
2730 }
2731
2732 void
et_browser_set_display_mode(EtBrowser * self,EtBrowserMode mode)2733 et_browser_set_display_mode (EtBrowser *self,
2734 EtBrowserMode mode)
2735 {
2736 EtBrowserPrivate *priv;
2737 ET_File *etfile = ETCore->ETFileDisplayed; // ETFile to display again after changing browser view
2738
2739 g_return_if_fail (ET_BROWSER (self));
2740
2741 priv = et_browser_get_instance_private (self);
2742
2743 et_application_window_update_et_file_from_ui (ET_APPLICATION_WINDOW (MainWindow));
2744
2745 switch (mode)
2746 {
2747 case ET_BROWSER_MODE_FILE:
2748 /* Set the whole list as "Displayed list". */
2749 et_displayed_file_list_set (ETCore->ETFileList);
2750
2751 /* Display Tree Browser. */
2752 gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->directory_album_artist_notebook),
2753 0);
2754 et_browser_load_file_list (self, ETCore->ETFileDisplayedList,
2755 etfile);
2756
2757 /* Displays the first file if nothing specified. */
2758 if (!etfile)
2759 {
2760 GList *etfilelist = ET_Displayed_File_List_First ();
2761 if (etfilelist)
2762 {
2763 etfile = (ET_File *)etfilelist->data;
2764 }
2765
2766 et_application_window_select_file_by_et_file (ET_APPLICATION_WINDOW (MainWindow),
2767 etfile);
2768 }
2769 break;
2770 case ET_BROWSER_MODE_ARTIST:
2771 /* Display Artist + Album lists. */
2772 gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->directory_album_artist_notebook),
2773 1);
2774 if (ETCore->ETArtistAlbumFileList)
2775 {
2776 et_artist_album_file_list_free (ETCore->ETArtistAlbumFileList);
2777 }
2778
2779 ETCore->ETArtistAlbumFileList = et_artist_album_list_new_from_file_list (ETCore->ETFileList);
2780 Browser_Artist_List_Load_Files (self, etfile);
2781 break;
2782 default:
2783 g_assert_not_reached ();
2784 }
2785 //ET_Display_File_Data_To_UI(etfile); // Causes a crash
2786 }
2787
2788 /*
2789 * Disable (FALSE) / Enable (TRUE) all user widgets in the browser area (Tree + List + Entry)
2790 */
2791 void
et_browser_set_sensitive(EtBrowser * self,gboolean sensitive)2792 et_browser_set_sensitive (EtBrowser *self, gboolean sensitive)
2793 {
2794 EtBrowserPrivate *priv;
2795
2796 priv = et_browser_get_instance_private (self);
2797
2798 gtk_widget_set_sensitive (GTK_WIDGET (priv->entry_combo), sensitive);
2799 gtk_widget_set_sensitive (GTK_WIDGET (priv->directory_view), sensitive);
2800 gtk_widget_set_sensitive (GTK_WIDGET (priv->file_view), sensitive);
2801 gtk_widget_set_sensitive (GTK_WIDGET (priv->artist_view), sensitive);
2802 gtk_widget_set_sensitive (GTK_WIDGET (priv->album_view), sensitive);
2803 gtk_widget_set_sensitive (GTK_WIDGET (priv->open_button), sensitive);
2804 gtk_widget_set_sensitive (GTK_WIDGET (priv->files_label), sensitive);
2805 }
2806
2807 static void
do_popup_menu(EtBrowser * self,GdkEventButton * event,GtkTreeView * view,GtkWidget * menu)2808 do_popup_menu (EtBrowser *self,
2809 GdkEventButton *event,
2810 GtkTreeView *view,
2811 GtkWidget *menu)
2812 {
2813 gint button;
2814 gint event_time;
2815
2816 if (event)
2817 {
2818 button = event->button;
2819 event_time = event->time;
2820 }
2821 else
2822 {
2823 button = 0;
2824 event_time = gtk_get_current_event_time ();
2825 }
2826
2827 /* TODO: Add popup positioning function. */
2828 gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL, button,
2829 event_time);
2830 }
2831
2832 static void
select_row_for_button_press_event(GtkTreeView * treeview,GdkEventButton * event)2833 select_row_for_button_press_event (GtkTreeView *treeview,
2834 GdkEventButton *event)
2835 {
2836 if (event->window == gtk_tree_view_get_bin_window (treeview))
2837 {
2838 GtkTreePath *tree_path;
2839
2840 if (gtk_tree_view_get_path_at_pos (treeview, event->x,
2841 event->y, &tree_path, NULL,
2842 NULL,NULL))
2843 {
2844 gtk_tree_selection_select_path (gtk_tree_view_get_selection (treeview),
2845 tree_path);
2846 gtk_tree_path_free (tree_path);
2847 }
2848 }
2849 }
2850
2851 static gboolean
on_album_tree_popup_menu(GtkWidget * treeview,EtBrowser * self)2852 on_album_tree_popup_menu (GtkWidget *treeview,
2853 EtBrowser *self)
2854 {
2855 EtBrowserPrivate *priv;
2856
2857 priv = et_browser_get_instance_private (self);
2858
2859 do_popup_menu (self, NULL, GTK_TREE_VIEW (treeview), priv->album_menu);
2860
2861 return GDK_EVENT_STOP;
2862 }
2863
2864 static gboolean
on_artist_tree_popup_menu(GtkWidget * treeview,EtBrowser * self)2865 on_artist_tree_popup_menu (GtkWidget *treeview,
2866 EtBrowser *self)
2867 {
2868 EtBrowserPrivate *priv;
2869
2870 priv = et_browser_get_instance_private (self);
2871
2872 do_popup_menu (self, NULL, GTK_TREE_VIEW (treeview), priv->artist_menu);
2873
2874 return GDK_EVENT_STOP;
2875 }
2876
2877 static gboolean
on_directory_tree_popup_menu(GtkWidget * treeview,EtBrowser * self)2878 on_directory_tree_popup_menu (GtkWidget *treeview,
2879 EtBrowser *self)
2880 {
2881 EtBrowserPrivate *priv;
2882
2883 priv = et_browser_get_instance_private (self);
2884
2885 do_popup_menu (self, NULL, GTK_TREE_VIEW (treeview), priv->directory_view_menu);
2886
2887 return GDK_EVENT_STOP;
2888 }
2889
2890 static gboolean
on_file_tree_popup_menu(GtkWidget * treeview,EtBrowser * self)2891 on_file_tree_popup_menu (GtkWidget *treeview,
2892 EtBrowser *self)
2893 {
2894 EtBrowserPrivate *priv;
2895
2896 priv = et_browser_get_instance_private (self);
2897
2898 do_popup_menu (self, NULL, GTK_TREE_VIEW (treeview), priv->file_menu);
2899
2900 return GDK_EVENT_STOP;
2901 }
2902
2903 static gboolean
on_album_tree_button_press_event(GtkWidget * widget,GdkEventButton * event,EtBrowser * self)2904 on_album_tree_button_press_event (GtkWidget *widget,
2905 GdkEventButton *event,
2906 EtBrowser *self)
2907 {
2908 if (gdk_event_triggers_context_menu ((GdkEvent *)event))
2909 {
2910 EtBrowserPrivate *priv;
2911
2912 priv = et_browser_get_instance_private (self);
2913
2914 if (GTK_IS_TREE_VIEW (widget))
2915 {
2916 select_row_for_button_press_event (GTK_TREE_VIEW (widget), event);
2917 }
2918
2919 do_popup_menu (self, event, GTK_TREE_VIEW (priv->album_view),
2920 priv->album_menu);
2921
2922 return GDK_EVENT_STOP;
2923 }
2924
2925 return GDK_EVENT_PROPAGATE;
2926 }
2927
2928 static gboolean
on_artist_tree_button_press_event(GtkWidget * widget,GdkEventButton * event,EtBrowser * self)2929 on_artist_tree_button_press_event (GtkWidget *widget,
2930 GdkEventButton *event,
2931 EtBrowser *self)
2932 {
2933 if (gdk_event_triggers_context_menu ((GdkEvent *)event))
2934 {
2935 EtBrowserPrivate *priv;
2936
2937 priv = et_browser_get_instance_private (self);
2938
2939 if (GTK_IS_TREE_VIEW (widget))
2940 {
2941 select_row_for_button_press_event (GTK_TREE_VIEW (widget), event);
2942 }
2943
2944 do_popup_menu (self, event, GTK_TREE_VIEW (priv->artist_view),
2945 priv->artist_menu);
2946
2947 return GDK_EVENT_STOP;
2948 }
2949
2950 return GDK_EVENT_PROPAGATE;
2951 }
2952
2953 static gboolean
on_directory_tree_button_press_event(GtkWidget * widget,GdkEventButton * event,EtBrowser * self)2954 on_directory_tree_button_press_event (GtkWidget *widget,
2955 GdkEventButton *event,
2956 EtBrowser *self)
2957 {
2958 if (gdk_event_triggers_context_menu ((GdkEvent *)event))
2959 {
2960 EtBrowserPrivate *priv;
2961
2962 priv = et_browser_get_instance_private (self);
2963
2964 if (GTK_IS_TREE_VIEW (widget))
2965 {
2966 select_row_for_button_press_event (GTK_TREE_VIEW (widget), event);
2967 }
2968
2969 do_popup_menu (self, event, GTK_TREE_VIEW (priv->directory_view),
2970 priv->directory_view_menu);
2971
2972 return GDK_EVENT_STOP;
2973 }
2974
2975 return GDK_EVENT_PROPAGATE;
2976 }
2977
2978 /*
2979 * Browser_Popup_Menu_Handler : displays the corresponding menu
2980 */
2981 static gboolean
on_file_tree_button_press_event(GtkWidget * widget,GdkEventButton * event,EtBrowser * self)2982 on_file_tree_button_press_event (GtkWidget *widget,
2983 GdkEventButton *event,
2984 EtBrowser *self)
2985 {
2986 if (gdk_event_triggers_context_menu ((GdkEvent *)event))
2987 {
2988 EtBrowserPrivate *priv;
2989
2990 priv = et_browser_get_instance_private (self);
2991
2992 if (GTK_IS_TREE_VIEW (widget))
2993 {
2994 select_row_for_button_press_event (GTK_TREE_VIEW (widget), event);
2995 }
2996
2997 do_popup_menu (self, event, GTK_TREE_VIEW (priv->file_view),
2998 priv->file_menu);
2999
3000 return GDK_EVENT_STOP;
3001 }
3002 else if (event->type == GDK_2BUTTON_PRESS
3003 && event->button == GDK_BUTTON_PRIMARY)
3004 {
3005 /* Double left mouse click. Select files of the same directory (useful
3006 * when browsing sub-directories). */
3007 GdkWindow *bin_window;
3008 GList *l;
3009 gchar *path_ref = NULL;
3010 gchar *patch_check = NULL;
3011 GtkTreePath *currentPath = NULL;
3012
3013 if (!ETCore->ETFileDisplayed)
3014 {
3015 return GDK_EVENT_PROPAGATE;
3016 }
3017
3018 bin_window = gtk_tree_view_get_bin_window (GTK_TREE_VIEW (widget));
3019
3020 if (bin_window != event->window)
3021 {
3022 /* If the double-click is not on a tree view row, for example when
3023 * resizing a header column, ignore it. */
3024 return GDK_EVENT_PROPAGATE;
3025 }
3026
3027 /* File taken as reference. */
3028 path_ref = g_path_get_dirname (((File_Name *)ETCore->ETFileDisplayed->FileNameCur->data)->value);
3029
3030 /* Search and select files of the same directory. */
3031 for (l = g_list_first (ETCore->ETFileDisplayedList); l != NULL;
3032 l = g_list_next (l))
3033 {
3034 /* Path of the file to check if it is in the same directory. */
3035 patch_check = g_path_get_dirname (((File_Name *)((ET_File *)l->data)->FileNameCur->data)->value);
3036
3037 if (path_ref && patch_check && strcmp (path_ref, patch_check) == 0)
3038 {
3039 /* Use of 'currentPath' to try to increase speed. Indeed, in
3040 * many cases, the next file to select, is the next in the
3041 * list. */
3042 currentPath = et_browser_select_file_by_et_file2 (self,
3043 (ET_File *)l->data,
3044 TRUE,
3045 currentPath);
3046 }
3047
3048 g_free (patch_check);
3049 }
3050
3051 g_free (path_ref);
3052
3053 if (currentPath)
3054 {
3055 gtk_tree_path_free (currentPath);
3056 }
3057
3058 return GDK_EVENT_STOP;
3059 }
3060 else if (event->type == GDK_3BUTTON_PRESS
3061 && event->button == GDK_BUTTON_PRIMARY)
3062 {
3063 /* Triple left mouse click, select all files of the list. */
3064 g_action_group_activate_action (G_ACTION_GROUP (MainWindow),
3065 "select-all", NULL);
3066 return GDK_EVENT_STOP;
3067 }
3068
3069 return GDK_EVENT_PROPAGATE;
3070 }
3071
3072 /*
3073 * Destroy the whole tree up to the root node
3074 */
3075 static void
Browser_Tree_Initialize(EtBrowser * self)3076 Browser_Tree_Initialize (EtBrowser *self)
3077 {
3078 EtBrowserPrivate *priv;
3079 #ifdef G_OS_WIN32
3080 GVolumeMonitor *monitor;
3081 GList *mounts;
3082 GList *l;
3083 #endif
3084 GtkTreeIter parent_iter;
3085 GtkTreeIter dummy_iter;
3086 GIcon *drive_icon;
3087
3088 priv = et_browser_get_instance_private (self);
3089
3090 g_return_if_fail (priv->directory_model != NULL);
3091
3092 gtk_tree_store_clear (priv->directory_model);
3093
3094 #ifdef G_OS_WIN32
3095 /* TODO: Connect to the monitor changed signals. */
3096 monitor = g_volume_monitor_get ();
3097 mounts = g_volume_monitor_get_mounts (monitor);
3098
3099 for (l = mounts; l != NULL; l = g_list_next (l))
3100 {
3101 GMount *mount;
3102 gchar *name;
3103 GFile *root;
3104 gchar *path;
3105
3106 mount = l->data;
3107 drive_icon = g_mount_get_icon (mount);
3108 name = g_mount_get_name (mount);
3109 root = g_mount_get_root (mount);
3110 path = g_file_get_path (root);
3111
3112 gtk_tree_store_insert_with_values (priv->directory_model,
3113 &parent_iter, NULL, G_MAXINT,
3114 TREE_COLUMN_DIR_NAME,
3115 name,
3116 TREE_COLUMN_FULL_PATH,
3117 path,
3118 TREE_COLUMN_HAS_SUBDIR, TRUE,
3119 TREE_COLUMN_SCANNED, FALSE,
3120 TREE_COLUMN_ICON, drive_icon,
3121 -1);
3122 /* Insert dummy node. */
3123 gtk_tree_store_append (priv->directory_model, &dummy_iter,
3124 &parent_iter);
3125
3126 g_free (path);
3127 g_free (name);
3128 g_object_unref (root);
3129 g_object_unref (drive_icon);
3130 }
3131
3132 g_list_free_full (mounts, g_object_unref);
3133 g_object_unref (monitor);
3134 #else /* !G_OS_WIN32 */
3135 drive_icon = get_gicon_for_path (G_DIR_SEPARATOR_S, ET_PATH_STATE_CLOSED);
3136 gtk_tree_store_insert_with_values (priv->directory_model, &parent_iter, NULL,
3137 G_MAXINT, TREE_COLUMN_DIR_NAME,
3138 G_DIR_SEPARATOR_S,
3139 TREE_COLUMN_FULL_PATH,
3140 G_DIR_SEPARATOR_S,
3141 TREE_COLUMN_HAS_SUBDIR, TRUE,
3142 TREE_COLUMN_SCANNED, FALSE,
3143 TREE_COLUMN_ICON, drive_icon, -1);
3144 /* Insert dummy node. */
3145 gtk_tree_store_append (priv->directory_model, &dummy_iter, &parent_iter);
3146
3147 g_object_unref (drive_icon);
3148 #endif /* !G_OS_WIN32 */
3149 }
3150
3151 /*
3152 * et_browser_reload: Refresh the tree browser by destroying it and rebuilding it.
3153 * Opens tree nodes corresponding to the current path.
3154 */
3155 void
et_browser_reload(EtBrowser * self)3156 et_browser_reload (EtBrowser *self)
3157 {
3158 EtBrowserPrivate *priv;
3159 gchar *current_path = NULL;
3160 GtkTreeSelection *selection;
3161
3162 priv = et_browser_get_instance_private (self);
3163
3164 /* Memorize the current path to load it again at the end */
3165 current_path = Browser_Tree_Get_Path_Of_Selected_Node (self);
3166
3167 /* Select again the memorized path without loading files */
3168 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->directory_view));
3169
3170 if (selection)
3171 {
3172 GFile *file;
3173
3174 g_signal_handlers_block_by_func (selection,
3175 G_CALLBACK (Browser_Tree_Node_Selected),
3176 self);
3177 Browser_Tree_Initialize (self);
3178 file = g_file_new_for_path (current_path);
3179 et_browser_select_dir (self, file);
3180 g_object_unref (file);
3181 g_signal_handlers_unblock_by_func (selection,
3182 G_CALLBACK (Browser_Tree_Node_Selected),
3183 self);
3184 }
3185 g_free(current_path);
3186
3187 et_application_window_update_actions (ET_APPLICATION_WINDOW (MainWindow));
3188 }
3189
3190 /*
3191 * Renames a directory
3192 * last_path:
3193 * new_path:
3194 * Parameters are non-utf8!
3195 */
3196 static void
Browser_Tree_Rename_Directory(EtBrowser * self,const gchar * last_path,const gchar * new_path)3197 Browser_Tree_Rename_Directory (EtBrowser *self,
3198 const gchar *last_path,
3199 const gchar *new_path)
3200 {
3201 EtBrowserPrivate *priv;
3202 gchar **textsplit;
3203 gint i;
3204 GtkTreeIter iter;
3205 GtkTreePath *childpath;
3206 GtkTreePath *parentpath;
3207 gchar *new_basename_utf8;
3208 gchar *path;
3209 GFile *file;
3210
3211 if (!last_path || !new_path)
3212 return;
3213
3214 priv = et_browser_get_instance_private (self);
3215
3216 /*
3217 * Find the existing tree entry
3218 */
3219 textsplit = g_strsplit(last_path, G_DIR_SEPARATOR_S, 0);
3220
3221 #ifdef G_OS_WIN32
3222 if (!et_browser_win32_get_drive_root (self, textsplit[0], &iter,
3223 &parentpath))
3224 {
3225 return;
3226 }
3227 #else /* !G_OS_WIN32 */
3228 parentpath = gtk_tree_path_new_first();
3229 #endif /* !G_OS_WIN32 */
3230
3231 for (i = 1; textsplit[i] != NULL; i++)
3232 {
3233 gboolean valid = gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->directory_model),
3234 &iter, parentpath);
3235 if (valid)
3236 {
3237 childpath = Find_Child_Node (self, &iter, textsplit[i]);
3238 }
3239 else
3240 {
3241 childpath = NULL;
3242 }
3243
3244 if (childpath == NULL)
3245 {
3246 // ERROR! Could not find it!
3247 gchar *text_utf8 = g_filename_display_name (textsplit[i]);
3248 g_critical ("Error: Searching for %s, could not find node %s in tree.",
3249 last_path, text_utf8);
3250 g_strfreev(textsplit);
3251 g_free(text_utf8);
3252 return;
3253 }
3254 gtk_tree_path_free(parentpath);
3255 parentpath = childpath;
3256 }
3257
3258 gtk_tree_model_get_iter(GTK_TREE_MODEL(priv->directory_model), &iter, parentpath);
3259 gtk_tree_path_free(parentpath);
3260
3261 /* Rename the on-screen node */
3262 new_basename_utf8 = g_filename_display_basename (new_path);
3263 gtk_tree_store_set(priv->directory_model, &iter,
3264 TREE_COLUMN_DIR_NAME, new_basename_utf8,
3265 TREE_COLUMN_FULL_PATH, new_path,
3266 -1);
3267
3268 /* Update fullpath of child nodes */
3269 Browser_Tree_Handle_Rename (self, &iter, last_path, new_path);
3270
3271 /* Update the variable of the current path */
3272 path = Browser_Tree_Get_Path_Of_Selected_Node (self);
3273 file = g_file_new_for_path (path);
3274 et_browser_set_current_path (self, file);
3275 g_object_unref (file);
3276 g_free(path);
3277
3278 g_strfreev(textsplit);
3279 g_free(new_basename_utf8);
3280 }
3281
3282 /*
3283 * Browser_Tree_Handle_Rename:
3284 * @self: an #EtBrowser
3285 * @parentnode: the parent node in a tree model containing directory paths
3286 * @old_path: (type filename): the old path, in GLib filename encoding
3287 * @new_path: (type filename): the new path, in GLib filename encoding
3288 *
3289 * Recursive function to update paths of all child nodes.
3290 */
3291 static void
Browser_Tree_Handle_Rename(EtBrowser * self,GtkTreeIter * parentnode,const gchar * old_path,const gchar * new_path)3292 Browser_Tree_Handle_Rename (EtBrowser *self,
3293 GtkTreeIter *parentnode,
3294 const gchar *old_path,
3295 const gchar *new_path)
3296 {
3297 EtBrowserPrivate *priv;
3298 GtkTreeIter iter;
3299
3300 priv = et_browser_get_instance_private (self);
3301
3302 /* If there are no children then nothing needs to be done! */
3303 if (!gtk_tree_model_iter_children (GTK_TREE_MODEL (priv->directory_model),
3304 &iter, parentnode))
3305 {
3306 return;
3307 }
3308
3309 do
3310 {
3311 gchar *path;
3312 gsize path_shift;
3313 gchar *path_new;
3314
3315 gtk_tree_model_get(GTK_TREE_MODEL(priv->directory_model), &iter,
3316 TREE_COLUMN_FULL_PATH, &path, -1);
3317 if(path == NULL)
3318 continue;
3319
3320 /* Graft the new path onto the old path. */
3321 path_shift = strlen (old_path);
3322 path_new = g_strconcat (new_path, path + path_shift, NULL);
3323
3324 gtk_tree_store_set(priv->directory_model, &iter,
3325 TREE_COLUMN_FULL_PATH, path_new, -1);
3326
3327 g_free(path_new);
3328 g_free(path);
3329
3330 /* Recurse if necessary. */
3331 if (gtk_tree_model_iter_has_child (GTK_TREE_MODEL (priv->directory_model),
3332 &iter))
3333 {
3334 Browser_Tree_Handle_Rename (self, &iter, old_path, new_path);
3335 }
3336
3337 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(priv->directory_model), &iter));
3338
3339 }
3340
3341 /*
3342 * Find the child node of "parentnode" that has text of "childtext
3343 * Returns NULL on failure
3344 */
3345 static GtkTreePath *
Find_Child_Node(EtBrowser * self,GtkTreeIter * parentnode,gchar * childtext)3346 Find_Child_Node (EtBrowser *self, GtkTreeIter *parentnode, gchar *childtext)
3347 {
3348 EtBrowserPrivate *priv;
3349 gint row;
3350 GtkTreeIter iter;
3351 gchar *text;
3352 gchar *temp;
3353
3354 priv = et_browser_get_instance_private (self);
3355
3356 for (row=0; row < gtk_tree_model_iter_n_children(GTK_TREE_MODEL(priv->directory_model), parentnode); row++)
3357 {
3358 if (row == 0)
3359 {
3360 if (gtk_tree_model_iter_children(GTK_TREE_MODEL(priv->directory_model), &iter, parentnode) == FALSE) return NULL;
3361 } else
3362 {
3363 if (gtk_tree_model_iter_next(GTK_TREE_MODEL(priv->directory_model), &iter) == FALSE)
3364 return NULL;
3365 }
3366 gtk_tree_model_get(GTK_TREE_MODEL(priv->directory_model), &iter,
3367 TREE_COLUMN_FULL_PATH, &temp, -1);
3368 text = g_path_get_basename(temp);
3369 g_free(temp);
3370 if(strcmp(childtext,text) == 0)
3371 {
3372 g_free(text);
3373 return gtk_tree_model_get_path(GTK_TREE_MODEL(priv->directory_model), &iter);
3374 }
3375 g_free(text);
3376
3377 }
3378
3379 return NULL;
3380 }
3381
3382 /*
3383 * check_for_subdir:
3384 * @path: (type filename): the path to test
3385 *
3386 * Check if @path has any subdirectories.
3387 *
3388 * Returns: %TRUE if subdirectories exist, %FALSE otherwise
3389 */
3390 static gboolean
check_for_subdir(const gchar * path)3391 check_for_subdir (const gchar *path)
3392 {
3393 GFile *dir;
3394 GFileEnumerator *enumerator;
3395
3396 dir = g_file_new_for_path (path);
3397 enumerator = g_file_enumerate_children (dir,
3398 G_FILE_ATTRIBUTE_STANDARD_TYPE ","
3399 G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN,
3400 G_FILE_QUERY_INFO_NONE,
3401 NULL, NULL);
3402 g_object_unref (dir);
3403
3404 if (enumerator)
3405 {
3406 GFileInfo *childinfo;
3407
3408 while ((childinfo = g_file_enumerator_next_file (enumerator,
3409 NULL, NULL)))
3410 {
3411 if ((g_file_info_get_file_type (childinfo) ==
3412 G_FILE_TYPE_DIRECTORY) &&
3413 (g_settings_get_boolean (MainSettings, "browse-show-hidden")
3414 || !g_file_info_get_is_hidden (childinfo)))
3415 {
3416 g_object_unref (childinfo);
3417 g_file_enumerator_close (enumerator, NULL, NULL);
3418 g_object_unref (enumerator);
3419 return TRUE;
3420 }
3421
3422 g_object_unref (childinfo);
3423 }
3424
3425 g_file_enumerator_close (enumerator, NULL, NULL);
3426 g_object_unref (enumerator);
3427 }
3428
3429 return FALSE;
3430 }
3431
3432 /*
3433 * get_gicon_for_path:
3434 * @path: (type filename): path to create icon for
3435 * @path_state: whether the icon should be shown open or closed
3436 *
3437 * Check the permissions for the supplied @path (authorized?, readonly?,
3438 * unreadable?) and return an appropriate icon.
3439 *
3440 * Returns: an icon corresponding to the @path
3441 */
3442 static GIcon *
get_gicon_for_path(const gchar * path,EtPathState path_state)3443 get_gicon_for_path (const gchar *path, EtPathState path_state)
3444 {
3445 GIcon *folder_icon;
3446 GIcon *emblem_icon;
3447 GIcon *emblemed_icon;
3448 GEmblem *emblem;
3449 GFile *file;
3450 GFileInfo *info;
3451 GError *error = NULL;
3452
3453 switch (path_state)
3454 {
3455 case ET_PATH_STATE_OPEN:
3456 folder_icon = g_themed_icon_new ("folder-open");
3457 break;
3458 case ET_PATH_STATE_CLOSED:
3459 folder_icon = g_themed_icon_new ("folder");
3460 break;
3461 default:
3462 g_assert_not_reached ();
3463 }
3464
3465 file = g_file_new_for_path (path);
3466 info = g_file_query_info (file, G_FILE_ATTRIBUTE_ACCESS_CAN_READ ","
3467 G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE,
3468 G_FILE_QUERY_INFO_NONE, NULL, &error);
3469
3470 if (info == NULL)
3471 {
3472 g_warning ("Error while querying path information: %s",
3473 error->message);
3474 g_clear_error (&error);
3475 info = g_file_info_new ();
3476 g_file_info_set_attribute_boolean (info,
3477 G_FILE_ATTRIBUTE_ACCESS_CAN_READ,
3478 FALSE);
3479 }
3480
3481 if (!g_file_info_get_attribute_boolean (info,
3482 G_FILE_ATTRIBUTE_ACCESS_CAN_READ))
3483 {
3484 emblem_icon = g_themed_icon_new ("emblem-unreadable");
3485 emblem = g_emblem_new_with_origin (emblem_icon,
3486 G_EMBLEM_ORIGIN_LIVEMETADATA);
3487 emblemed_icon = g_emblemed_icon_new (folder_icon, emblem);
3488 g_object_unref (folder_icon);
3489 g_object_unref (emblem_icon);
3490 g_object_unref (emblem);
3491
3492 folder_icon = emblemed_icon;
3493 }
3494 else if (!g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE))
3495 {
3496 emblem_icon = g_themed_icon_new ("emblem-readonly");
3497 emblem = g_emblem_new_with_origin (emblem_icon,
3498 G_EMBLEM_ORIGIN_LIVEMETADATA);
3499 emblemed_icon = g_emblemed_icon_new (folder_icon, emblem);
3500 g_object_unref (folder_icon);
3501 g_object_unref (emblem_icon);
3502 g_object_unref (emblem);
3503
3504 folder_icon = emblemed_icon;
3505 }
3506
3507 g_object_unref (file);
3508 g_object_unref (info);
3509
3510 return folder_icon;
3511 }
3512
3513 /*
3514 * Open up a node on the browser tree
3515 * Scanning and showing all subdirectories
3516 */
3517 static void
expand_cb(EtBrowser * self,GtkTreeIter * iter,GtkTreePath * gtreePath,GtkTreeView * tree)3518 expand_cb (EtBrowser *self, GtkTreeIter *iter, GtkTreePath *gtreePath, GtkTreeView *tree)
3519 {
3520 EtBrowserPrivate *priv;
3521 GFile *dir;
3522 GFileEnumerator *enumerator;
3523 gchar *fullpath_file;
3524 gchar *parentPath;
3525 gboolean treeScanned;
3526 gboolean has_subdir = FALSE;
3527 GtkTreeIter currentIter;
3528 GtkTreeIter subNodeIter;
3529 GIcon *icon;
3530
3531 priv = et_browser_get_instance_private (self);
3532
3533 g_return_if_fail (priv->directory_model != NULL);
3534
3535 gtk_tree_model_get(GTK_TREE_MODEL(priv->directory_model), iter,
3536 TREE_COLUMN_FULL_PATH, &parentPath,
3537 TREE_COLUMN_SCANNED, &treeScanned, -1);
3538
3539 if (treeScanned)
3540 return;
3541
3542 dir = g_file_new_for_path (parentPath);
3543 enumerator = g_file_enumerate_children (dir,
3544 G_FILE_ATTRIBUTE_STANDARD_TYPE ","
3545 G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME ","
3546 G_FILE_ATTRIBUTE_STANDARD_NAME ","
3547 G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN,
3548 G_FILE_QUERY_INFO_NONE,
3549 NULL, NULL);
3550
3551 if (enumerator)
3552 {
3553 GFileInfo *childinfo;
3554
3555 while ((childinfo = g_file_enumerator_next_file (enumerator,
3556 NULL, NULL))
3557 != NULL)
3558 {
3559 GFile *child;
3560 gboolean isdir;
3561
3562 child = g_file_enumerator_get_child (enumerator, childinfo);
3563 fullpath_file = g_file_get_path (child);
3564 isdir = g_file_info_get_file_type (childinfo) == G_FILE_TYPE_DIRECTORY;
3565
3566 if (isdir &&
3567 (g_settings_get_boolean (MainSettings, "browse-show-hidden")
3568 || !g_file_info_get_is_hidden (childinfo)))
3569 {
3570 const gchar *dirname_utf8;
3571 dirname_utf8 = g_file_info_get_display_name (childinfo);
3572
3573 has_subdir = check_for_subdir (fullpath_file);
3574
3575 /* Select pixmap according permissions for the directory. */
3576 icon = get_gicon_for_path (fullpath_file,
3577 ET_PATH_STATE_CLOSED);
3578
3579 gtk_tree_store_insert_with_values (priv->directory_model,
3580 ¤tIter, iter,
3581 G_MAXINT,
3582 TREE_COLUMN_DIR_NAME,
3583 dirname_utf8,
3584 TREE_COLUMN_FULL_PATH,
3585 fullpath_file,
3586 TREE_COLUMN_HAS_SUBDIR,
3587 !has_subdir,
3588 TREE_COLUMN_SCANNED, FALSE,
3589 TREE_COLUMN_ICON, icon, -1);
3590
3591 if (has_subdir)
3592 {
3593 /* Insert a dummy node. */
3594 gtk_tree_store_append(priv->directory_model, &subNodeIter, ¤tIter);
3595 }
3596
3597 g_object_unref (icon);
3598 }
3599
3600 g_free (fullpath_file);
3601 g_object_unref (childinfo);
3602 g_object_unref (child);
3603 }
3604
3605 g_file_enumerator_close (enumerator, NULL, NULL);
3606 g_object_unref (enumerator);
3607
3608 /* Remove dummy node. */
3609 gtk_tree_model_iter_children (GTK_TREE_MODEL (priv->directory_model),
3610 &subNodeIter, iter);
3611 gtk_tree_store_remove (priv->directory_model, &subNodeIter);
3612 }
3613
3614 g_object_unref (dir);
3615 icon = get_gicon_for_path (parentPath, ET_PATH_STATE_OPEN);
3616
3617 #ifdef G_OS_WIN32
3618 // set open folder pixmap except on drive (depth == 0)
3619 if (gtk_tree_path_get_depth(gtreePath) > 1)
3620 {
3621 // update the icon of the node to opened folder :-)
3622 gtk_tree_store_set(priv->directory_model, iter,
3623 TREE_COLUMN_SCANNED, TRUE,
3624 TREE_COLUMN_ICON, icon,
3625 -1);
3626 }
3627 #else /* !G_OS_WIN32 */
3628 // update the icon of the node to opened folder :-)
3629 gtk_tree_store_set(priv->directory_model, iter,
3630 TREE_COLUMN_SCANNED, TRUE,
3631 TREE_COLUMN_ICON, icon,
3632 -1);
3633 #endif /* !G_OS_WIN32 */
3634
3635 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(priv->directory_model),
3636 TREE_COLUMN_DIR_NAME, GTK_SORT_ASCENDING);
3637
3638 g_object_unref (icon);
3639 g_free(parentPath);
3640 }
3641
3642 static void
collapse_cb(EtBrowser * self,GtkTreeIter * iter,GtkTreePath * treePath,GtkTreeView * tree)3643 collapse_cb (EtBrowser *self, GtkTreeIter *iter, GtkTreePath *treePath, GtkTreeView *tree)
3644 {
3645 EtBrowserPrivate *priv;
3646 GtkTreeIter subNodeIter;
3647 gchar *path;
3648 GIcon *icon;
3649 GFile *file;
3650 GFileInfo *fileinfo;
3651 GError *error = NULL;
3652
3653 priv = et_browser_get_instance_private (self);
3654
3655 g_return_if_fail (priv->directory_model != NULL);
3656
3657 gtk_tree_model_get (GTK_TREE_MODEL (priv->directory_model), iter,
3658 TREE_COLUMN_FULL_PATH, &path, -1);
3659
3660 /* If the directory is not readable, do not delete its children. */
3661 file = g_file_new_for_path (path);
3662 g_free (path);
3663 fileinfo = g_file_query_info (file, G_FILE_ATTRIBUTE_ACCESS_CAN_READ,
3664 G_FILE_QUERY_INFO_NONE, NULL, &error);
3665 g_object_unref (file);
3666
3667 if (fileinfo)
3668 {
3669 if (!g_file_info_get_attribute_boolean (fileinfo,
3670 G_FILE_ATTRIBUTE_ACCESS_CAN_READ))
3671 {
3672 g_object_unref (fileinfo);
3673 return;
3674 }
3675
3676 g_object_unref (fileinfo);
3677 }
3678
3679 gtk_tree_model_iter_children(GTK_TREE_MODEL(priv->directory_model),
3680 &subNodeIter, iter);
3681 while (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(priv->directory_model), iter))
3682 {
3683 gtk_tree_model_iter_children(GTK_TREE_MODEL(priv->directory_model), &subNodeIter, iter);
3684 gtk_tree_store_remove(priv->directory_model, &subNodeIter);
3685 }
3686
3687 gtk_tree_model_get (GTK_TREE_MODEL (priv->directory_model), iter,
3688 TREE_COLUMN_FULL_PATH, &path, -1);
3689 icon = get_gicon_for_path (path, ET_PATH_STATE_OPEN);
3690 g_free (path);
3691 #ifdef G_OS_WIN32
3692 // set closed folder pixmap except on drive (depth == 0)
3693 if(gtk_tree_path_get_depth(treePath) > 1)
3694 {
3695 // update the icon of the node to closed folder :-)
3696 gtk_tree_store_set(priv->directory_model, iter,
3697 TREE_COLUMN_SCANNED, FALSE,
3698 TREE_COLUMN_ICON, icon, -1);
3699 }
3700 #else /* !G_OS_WIN32 */
3701 // update the icon of the node to closed folder :-)
3702 gtk_tree_store_set(priv->directory_model, iter,
3703 TREE_COLUMN_SCANNED, FALSE,
3704 TREE_COLUMN_ICON, icon, -1);
3705 #endif /* !G_OS_WIN32 */
3706
3707 /* Insert dummy node only if directory exists. */
3708 if (error)
3709 {
3710 /* Remove the parent (missing) directory from the tree. */
3711 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
3712 {
3713 gtk_tree_store_remove (priv->directory_model, iter);
3714 }
3715
3716 g_error_free (error);
3717 }
3718 else
3719 {
3720 gtk_tree_store_append (priv->directory_model, &subNodeIter, iter);
3721 }
3722
3723 g_object_unref (icon);
3724 }
3725
3726 static void
on_sort_mode_changed(EtBrowser * self,gchar * key,GSettings * settings)3727 on_sort_mode_changed (EtBrowser *self, gchar *key, GSettings *settings)
3728 {
3729 EtBrowserPrivate *priv;
3730 EtSortMode sort_mode;
3731 GtkTreeViewColumn *column;
3732
3733 priv = et_browser_get_instance_private (self);
3734
3735 sort_mode = g_settings_get_enum (settings, key);
3736 column = et_browser_get_column_for_column_id (self, sort_mode / 2);
3737
3738 /* If the column to sort is different than the old sorted column. */
3739 if (sort_mode / 2 != priv->file_sort_mode / 2)
3740 {
3741 GtkTreeViewColumn *old_column;
3742
3743 old_column = et_browser_get_column_for_column_id (self,
3744 priv->file_sort_mode / 2);
3745
3746 /* Reset the sort order of the old sort column. */
3747 if (gtk_tree_view_column_get_sort_order (old_column)
3748 == GTK_SORT_DESCENDING)
3749 {
3750 gtk_tree_view_column_set_sort_order (old_column,
3751 GTK_SORT_ASCENDING);
3752 }
3753
3754 gtk_tree_view_column_set_sort_indicator (old_column, FALSE);
3755 }
3756
3757 /* New sort mode is for a column with a visible counterpart. */
3758 if (sort_mode / 2 < ET_SORT_MODE_ASCENDING_CREATION_DATE)
3759 {
3760 gtk_tree_view_column_set_sort_indicator (column, TRUE);
3761 }
3762
3763 /* Even is GTK_SORT_ASCENDING, odd is GTK_SORT_DESCENDING. */
3764 gtk_tree_view_column_set_sort_order (column, sort_mode % 2);
3765
3766 /* Store the new sort mode. */
3767 priv->file_sort_mode = sort_mode;
3768
3769 et_browser_refresh_sort (self);
3770 }
3771
3772 /*
3773 * Open the file selection window and saves the selected file path into entry
3774 */
3775 static void
open_file_selection_dialog(GtkWidget * entry,const gchar * title,GtkFileChooserAction action)3776 open_file_selection_dialog (GtkWidget *entry,
3777 const gchar *title,
3778 GtkFileChooserAction action)
3779 {
3780 const gchar *tmp;
3781 gchar *filename, *filename_utf8;
3782 GtkWidget *dialog;
3783 GtkWindow *parent_window = NULL;
3784 gint response;
3785
3786 parent_window = (GtkWindow*) gtk_widget_get_toplevel (entry);
3787 if (!gtk_widget_is_toplevel (GTK_WIDGET (parent_window)))
3788 {
3789 g_warning ("%s", "Could not get parent window");
3790 return;
3791 }
3792
3793 dialog = gtk_file_chooser_dialog_new (title, parent_window, action,
3794 _("_Cancel"), GTK_RESPONSE_CANCEL,
3795 _("_Open"), GTK_RESPONSE_ACCEPT,
3796 NULL);
3797
3798 /* Set initial directory. */
3799 tmp = gtk_entry_get_text (GTK_ENTRY (entry));
3800
3801 if (tmp && *tmp)
3802 {
3803 if (!gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (dialog), tmp))
3804 {
3805 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog),
3806 tmp);
3807 }
3808 }
3809
3810 response = gtk_dialog_run (GTK_DIALOG (dialog));
3811
3812 if (response == GTK_RESPONSE_ACCEPT)
3813 {
3814 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
3815 filename_utf8 = g_filename_display_name (filename);
3816 gtk_entry_set_text (GTK_ENTRY (entry), filename_utf8);
3817 g_free (filename);
3818 g_free (filename_utf8);
3819 /* Useful for the button on the main window. */
3820 gtk_widget_grab_focus (GTK_WIDGET (entry));
3821 g_signal_emit_by_name (entry, "activate");
3822 }
3823
3824 gtk_widget_destroy (dialog);
3825 }
3826
3827 /* File selection window */
3828 static void
File_Selection_Window_For_File(GtkWidget * entry)3829 File_Selection_Window_For_File (GtkWidget *entry)
3830 {
3831 open_file_selection_dialog (entry, _("Select File"),
3832 GTK_FILE_CHOOSER_ACTION_OPEN);
3833 }
3834
3835 static void
File_Selection_Window_For_Directory(GtkWidget * entry)3836 File_Selection_Window_For_Directory (GtkWidget *entry)
3837 {
3838 open_file_selection_dialog (entry, _("Select Directory"),
3839 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
3840 }
3841
3842 static gboolean
album_list_separator_func(GtkTreeModel * model,GtkTreeIter * iter,gpointer user_data)3843 album_list_separator_func (GtkTreeModel *model,
3844 GtkTreeIter *iter,
3845 gpointer user_data)
3846 {
3847 gboolean separator_row;
3848
3849 gtk_tree_model_get (model, iter, ALBUM_ALL_ALBUMS_SEPARATOR_ROW,
3850 &separator_row, -1);
3851
3852 return separator_row;
3853 }
3854
3855 /*
3856 * Create item of the browser (Entry + Tree + List).
3857 */
3858 static void
create_browser(EtBrowser * self)3859 create_browser (EtBrowser *self)
3860 {
3861 EtBrowserPrivate *priv;
3862 gsize i;
3863 GtkBuilder *builder;
3864 GMenuModel *menu_model;
3865 GFile *file;
3866
3867 priv = et_browser_get_instance_private (self);
3868
3869 /* History list */
3870 Load_Path_Entry_List (priv->entry_model, MISC_COMBO_TEXT);
3871
3872 g_signal_connect_swapped (gtk_bin_get_child (GTK_BIN (priv->entry_combo)),
3873 "activate", G_CALLBACK (Browser_Entry_Activated),
3874 self);
3875 /* The button to select a directory to browse. */
3876 g_signal_connect_swapped (priv->open_button, "clicked",
3877 G_CALLBACK (File_Selection_Window_For_Directory),
3878 gtk_bin_get_child (GTK_BIN (priv->entry_combo)));
3879
3880 /* The tree view */
3881 Browser_Tree_Initialize (self);
3882
3883 /* Create popup menu on browser tree view. */
3884 builder = gtk_builder_new_from_resource ("/org/gnome/EasyTAG/menus.ui");
3885
3886 menu_model = G_MENU_MODEL (gtk_builder_get_object (builder,
3887 "directory-menu"));
3888 priv->directory_view_menu = gtk_menu_new_from_model (menu_model);
3889 gtk_menu_attach_to_widget (GTK_MENU (priv->directory_view_menu), priv->directory_view, NULL);
3890
3891 /* The ScrollWindows with the Artist and Album Lists. */
3892 priv->artist_selected_handler = g_signal_connect_swapped (gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->artist_view)),
3893 "changed",
3894 G_CALLBACK (Browser_Artist_List_Row_Selected),
3895 self);
3896
3897 /* Create popup menu on browser artist list. */
3898 menu_model = G_MENU_MODEL (gtk_builder_get_object (builder,
3899 "directory-artist-menu"));
3900 priv->artist_menu = gtk_menu_new_from_model (menu_model);
3901 gtk_menu_attach_to_widget (GTK_MENU (priv->artist_menu), priv->artist_view,
3902 NULL);
3903
3904 gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (priv->album_view),
3905 album_list_separator_func, NULL,
3906 NULL);
3907
3908 priv->album_selected_handler = g_signal_connect_swapped (gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->album_view)),
3909 "changed",
3910 G_CALLBACK (Browser_Album_List_Row_Selected),
3911 self);
3912
3913 /* Create Popup Menu on browser album list. */
3914 menu_model = G_MENU_MODEL (gtk_builder_get_object (builder,
3915 "directory-album-menu"));
3916 priv->album_menu = gtk_menu_new_from_model (menu_model);
3917 gtk_menu_attach_to_widget (GTK_MENU (priv->album_menu), priv->album_view,
3918 NULL);
3919
3920 /* The file list */
3921 /* Add columns to tree view. See ET_FILE_LIST_COLUMN. */
3922 for (i = 0; i <= LIST_FILE_ENCODED_BY; i++)
3923 {
3924 const guint ascending_sort = 2 * i;
3925 GtkTreeViewColumn *column = gtk_tree_view_get_column (GTK_TREE_VIEW (priv->file_view),
3926 i);
3927
3928 g_object_set_data (G_OBJECT (column), "browser", self);
3929 g_signal_connect (column, "clicked",
3930 G_CALLBACK (et_browser_on_column_clicked),
3931 GINT_TO_POINTER (ascending_sort));
3932 }
3933
3934 g_signal_connect_swapped (MainSettings, "changed::sort-mode",
3935 G_CALLBACK (on_sort_mode_changed), self);
3936 // To sort list
3937 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (priv->file_model), 0,
3938 Browser_List_Sort_Func, NULL, NULL);
3939 et_browser_refresh_sort (self);
3940 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (priv->file_model),
3941 0, GTK_SORT_ASCENDING);
3942
3943 priv->file_selected_handler = g_signal_connect_swapped (gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->file_view)),
3944 "changed",
3945 G_CALLBACK (Browser_List_Row_Selected),
3946 self);
3947
3948 /* Create popup menu on file list. */
3949 menu_model = G_MENU_MODEL (gtk_builder_get_object (builder, "file-menu"));
3950 priv->file_menu = gtk_menu_new_from_model (menu_model);
3951 gtk_menu_attach_to_widget (GTK_MENU (priv->file_menu), priv->file_view,
3952 NULL);
3953
3954 g_object_unref (builder);
3955
3956 /* The list store for run program combos. */
3957 priv->run_program_model = gtk_list_store_new(MISC_COMBO_COUNT, G_TYPE_STRING);
3958
3959 /* TODO: Give the browser area a sensible default size. */
3960
3961 /* Set home variable as current path */
3962 file = g_file_new_for_path (g_get_home_dir ());
3963 et_browser_set_current_path (self, file);
3964 g_object_unref (file);
3965 }
3966
3967 /*
3968 * et_browser_on_column_clicked:
3969 * @column: the tree view column to sort
3970 * @data: the (required) #ET_Sorting_Type, converted to a pointer with
3971 * #GINT_TO_POINTER
3972 *
3973 * Set the sort mode and display appropriate sort indicator when
3974 * column is clicked.
3975 */
3976 static void
et_browser_on_column_clicked(GtkTreeViewColumn * column,gpointer data)3977 et_browser_on_column_clicked (GtkTreeViewColumn *column, gpointer data)
3978 {
3979 /* Flip to a descing sort mode if the row is already sorted ascending. */
3980 if (gtk_tree_view_column_get_sort_order (column) == GTK_SORT_ASCENDING)
3981 {
3982 g_settings_set_enum (MainSettings, "sort-mode",
3983 GPOINTER_TO_INT (data) + 1);
3984 }
3985 else
3986 {
3987 g_settings_set_enum (MainSettings, "sort-mode",
3988 GPOINTER_TO_INT (data));
3989 }
3990 }
3991
3992 /*******************************
3993 * Scanner To Rename Directory *
3994 *******************************/
3995 static void
rename_directory_generate_preview(EtBrowser * self)3996 rename_directory_generate_preview (EtBrowser *self)
3997 {
3998 EtBrowserPrivate *priv;
3999 gchar *preview_text = NULL;
4000 gchar *mask = NULL;
4001
4002 priv = et_browser_get_instance_private (self);
4003
4004 if (!ETCore->ETFileDisplayed
4005 || !priv->rename_directory_dialog || !priv->rename_directory_mask_entry || !priv->rename_directory_preview_label)
4006 return;
4007
4008 mask = g_settings_get_string (MainSettings,
4009 "rename-directory-default-mask");
4010
4011 if (!mask)
4012 return;
4013
4014 preview_text = et_scan_generate_new_filename_from_mask (ETCore->ETFileDisplayed,
4015 mask, FALSE);
4016
4017 if (GTK_IS_LABEL(priv->rename_directory_preview_label))
4018 {
4019 if (preview_text)
4020 {
4021 //gtk_label_set_text(GTK_LABEL(priv->rename_file_preview_label),preview_text);
4022 gchar *tmp_string = g_markup_printf_escaped("%s",preview_text); // To avoid problem with strings containing characters like '&'
4023 gchar *str = g_strdup_printf("<i>%s</i>",tmp_string);
4024 gtk_label_set_markup(GTK_LABEL(priv->rename_directory_preview_label),str);
4025 g_free(tmp_string);
4026 g_free(str);
4027 } else
4028 {
4029 gtk_label_set_text(GTK_LABEL(priv->rename_directory_preview_label),"");
4030 }
4031
4032 // Force the window to be redrawed else the preview label may be not placed correctly
4033 gtk_widget_queue_resize(priv->rename_directory_dialog);
4034 }
4035
4036 g_free(mask);
4037 g_free(preview_text);
4038 }
4039
4040 /*
4041 * The window to Rename a directory into the browser.
4042 */
4043 void
et_browser_show_rename_directory_dialog(EtBrowser * self)4044 et_browser_show_rename_directory_dialog (EtBrowser *self)
4045 {
4046 EtBrowserPrivate *priv;
4047 GtkBuilder *builder;
4048 GtkWidget *label;
4049 GtkWidget *button;
4050 GFile *parent;
4051 gchar *parent_path;
4052 gchar *basename;
4053 gchar *display_basename;
4054 gchar *string;
4055
4056 priv = et_browser_get_instance_private (self);
4057
4058 if (priv->rename_directory_dialog != NULL)
4059 {
4060 gtk_window_present(GTK_WINDOW(priv->rename_directory_dialog));
4061 return;
4062 }
4063
4064 /* We get the full path but we musn't display the parent directories */
4065 parent = g_file_get_parent (priv->current_path);
4066
4067 if (!parent)
4068 {
4069 return;
4070 }
4071
4072 parent_path = g_file_get_path (parent);
4073 g_object_unref (parent);
4074
4075 if (!parent_path)
4076 {
4077 return;
4078 }
4079
4080 basename = g_file_get_basename (priv->current_path);
4081
4082 if (!basename)
4083 {
4084 return;
4085 }
4086
4087 display_basename = g_filename_display_name (basename);
4088
4089 builder = gtk_builder_new_from_resource ("/org/gnome/EasyTAG/browser_dialogs.ui");
4090
4091 priv->rename_directory_dialog = GTK_WIDGET (gtk_builder_get_object (builder,
4092 "rename_directory_dialog"));
4093
4094 gtk_window_set_transient_for (GTK_WINDOW (priv->rename_directory_dialog),
4095 GTK_WINDOW (MainWindow));
4096 gtk_dialog_set_default_response (GTK_DIALOG (priv->rename_directory_dialog),
4097 GTK_RESPONSE_APPLY);
4098
4099 /* We attach useful data to the combobox */
4100 g_object_set_data_full (G_OBJECT (priv->rename_directory_dialog),
4101 "Parent_Directory", parent_path, g_free);
4102 g_object_set_data_full (G_OBJECT (priv->rename_directory_dialog),
4103 "Current_Directory", basename, g_free);
4104 g_signal_connect (priv->rename_directory_dialog, "response",
4105 G_CALLBACK (et_rename_directory_on_response), self);
4106
4107 string = g_strdup_printf (_("Rename the directory ‘%s’ to:"),
4108 display_basename);
4109 label = GTK_WIDGET (gtk_builder_get_object (builder, "rename_label"));
4110 gtk_label_set_label (GTK_LABEL (label), string);
4111 g_free (string);
4112 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
4113
4114 /* The entry to rename the directory. */
4115 priv->rename_directory_entry = GTK_WIDGET (gtk_builder_get_object (builder,
4116 "rename_entry"));
4117 /* Set the directory into the combobox */
4118 gtk_entry_set_text (GTK_ENTRY (priv->rename_directory_entry),
4119 display_basename);
4120
4121 /* Rename directory : check box + entry + Status icon */
4122 priv->rename_directory_mask_toggle = GTK_WIDGET (gtk_builder_get_object (builder,
4123 "rename_mask_check"));
4124 g_settings_bind (MainSettings, "rename-directory-with-mask",
4125 priv->rename_directory_mask_toggle, "active",
4126 G_SETTINGS_BIND_DEFAULT);
4127 g_signal_connect_swapped (priv->rename_directory_mask_toggle, "toggled",
4128 G_CALLBACK (Rename_Directory_With_Mask_Toggled),
4129 self);
4130
4131 /* The entry to enter the mask to apply. */
4132 priv->rename_directory_mask_entry = GTK_WIDGET (gtk_builder_get_object (builder,
4133 "rename_mask_entry"));
4134 gtk_widget_set_size_request(priv->rename_directory_mask_entry, 80, -1);
4135
4136 /* Signal to generate preview (preview of the new directory). */
4137 g_signal_connect_swapped (priv->rename_directory_mask_entry,
4138 "changed",
4139 G_CALLBACK (rename_directory_generate_preview),
4140 self);
4141
4142 g_settings_bind (MainSettings, "rename-directory-default-mask",
4143 priv->rename_directory_mask_entry, "text",
4144 G_SETTINGS_BIND_DEFAULT);
4145
4146 /* Mask status icon. Signal connection to check if mask is correct to the
4147 * mask entry. */
4148 g_signal_connect (priv->rename_directory_mask_entry, "changed",
4149 G_CALLBACK (entry_check_rename_file_mask), NULL);
4150
4151 /* Preview label. */
4152 priv->rename_directory_preview_label = GTK_WIDGET (gtk_builder_get_object (builder,
4153 "rename_preview_label"));
4154 /* Button to save: to rename directory */
4155 button = gtk_dialog_get_widget_for_response (GTK_DIALOG (priv->rename_directory_dialog),
4156 GTK_RESPONSE_APPLY);
4157 g_signal_connect_swapped (priv->rename_directory_entry,
4158 "changed",
4159 G_CALLBACK (empty_entry_disable_widget),
4160 G_OBJECT (button));
4161
4162 g_object_unref (builder);
4163
4164 gtk_widget_show_all (priv->rename_directory_dialog);
4165
4166 /* To initialize the 'Use mask' check button state. */
4167 g_signal_emit_by_name (G_OBJECT (priv->rename_directory_mask_toggle),
4168 "toggled");
4169
4170 /* To initialize PreviewLabel + MaskStatusIconBox. */
4171 g_signal_emit_by_name (priv->rename_directory_mask_entry, "changed");
4172
4173 g_free (display_basename);
4174 }
4175
4176 static void
Destroy_Rename_Directory_Window(EtBrowser * self)4177 Destroy_Rename_Directory_Window (EtBrowser *self)
4178 {
4179 EtBrowserPrivate *priv;
4180
4181 priv = et_browser_get_instance_private (self);
4182
4183 if (priv->rename_directory_dialog)
4184 {
4185 gtk_widget_destroy(priv->rename_directory_dialog);
4186 priv->rename_directory_preview_label = NULL;
4187 priv->rename_directory_dialog = NULL;
4188 }
4189 }
4190
4191 static void
Rename_Directory(EtBrowser * self)4192 Rename_Directory (EtBrowser *self)
4193 {
4194 EtBrowserPrivate *priv;
4195 gchar *directory_parent;
4196 gchar *directory_last_name;
4197 gchar *directory_new_name;
4198 gchar *directory_new_name_file;
4199 gchar *last_path;
4200 gchar *last_path_utf8;
4201 gchar *new_path;
4202 gchar *new_path_utf8;
4203 gchar *tmp_path;
4204 gchar *tmp_path_utf8;
4205 gint fd_tmp;
4206
4207 priv = et_browser_get_instance_private (self);
4208
4209 g_return_if_fail (priv->rename_directory_dialog != NULL);
4210
4211 directory_parent = g_object_get_data(G_OBJECT(priv->rename_directory_dialog),"Parent_Directory");
4212 directory_last_name = g_object_get_data(G_OBJECT(priv->rename_directory_dialog),"Current_Directory");
4213
4214 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->rename_directory_mask_toggle)))
4215 {
4216 /* Renamed from mask. */
4217 gchar *mask;
4218
4219 mask = g_settings_get_string (MainSettings,
4220 "rename-directory-default-mask");
4221 directory_new_name = et_scan_generate_new_directory_name_from_mask (ETCore->ETFileDisplayed,
4222 mask,
4223 FALSE);
4224 g_free (mask);
4225
4226 }
4227 else
4228 {
4229 /* Renamed 'manually'. */
4230 directory_new_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (priv->rename_directory_entry)));
4231 }
4232
4233 /* Check if a name for the directory have been supplied */
4234 if (et_str_empty (directory_new_name))
4235 {
4236 GtkWidget *msgdialog;
4237
4238 msgdialog = gtk_message_dialog_new(GTK_WINDOW(MainWindow),
4239 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4240 GTK_MESSAGE_ERROR,
4241 GTK_BUTTONS_CLOSE,
4242 "%s",
4243 _("You must type a directory name"));
4244 gtk_window_set_title(GTK_WINDOW(msgdialog),_("Directory Name Error"));
4245
4246 gtk_dialog_run(GTK_DIALOG(msgdialog));
4247 gtk_widget_destroy(msgdialog);
4248 g_free(directory_new_name);
4249 return;
4250 }
4251
4252 /* Check that we can write the new directory name */
4253 directory_new_name_file = filename_from_display(directory_new_name);
4254 if (!directory_new_name_file)
4255 {
4256 GtkWidget *msgdialog;
4257
4258 msgdialog = gtk_message_dialog_new(GTK_WINDOW(MainWindow),
4259 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4260 GTK_MESSAGE_ERROR,
4261 GTK_BUTTONS_CLOSE,
4262 _("Could not convert ‘%s’ into filename encoding"),
4263 directory_new_name);
4264 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (msgdialog),
4265 _("Please use another name."));
4266 gtk_window_set_title(GTK_WINDOW(msgdialog),_("Directory Name Error"));
4267
4268 gtk_dialog_run(GTK_DIALOG(msgdialog));
4269 gtk_widget_destroy(msgdialog);
4270 g_free(directory_new_name_file);
4271 }
4272
4273 g_free (directory_new_name);
4274
4275 /* If the directory name haven't been changed, we do nothing! */
4276 if (directory_last_name && directory_new_name_file
4277 && strcmp(directory_last_name,directory_new_name_file)==0)
4278 {
4279 Destroy_Rename_Directory_Window (self);
4280 g_free(directory_new_name_file);
4281 return;
4282 }
4283
4284 /* Build the current and new absolute paths */
4285 last_path = g_build_filename (directory_parent, directory_last_name, NULL);
4286 last_path_utf8 = g_filename_display_name (last_path);
4287 new_path = g_build_filename (directory_parent, directory_new_name_file,
4288 NULL);
4289 new_path_utf8 = g_filename_display_name (new_path);
4290
4291 /* TODO: Replace with g_file_move(). */
4292 /* Check if the new directory name doesn't already exists, and detect if
4293 * it's only a case change (needed for vfat) */
4294 if (g_file_test (new_path, G_FILE_TEST_IS_DIR))
4295 {
4296 GtkWidget *msgdialog;
4297 //gint response;
4298
4299 if (strcasecmp(last_path,new_path) != 0)
4300 {
4301 // TODO
4302 // // The same directory already exists. So we ask if we want to move the files
4303 // msg = g_strdup_printf(_("The directory already exists!\n(%s)\nDo you want "
4304 // "to move the files?"),new_path_utf8);
4305 // msgbox = msg_box_new(_("Confirm"),
4306 // GTK_WINDOW(MainWindow),
4307 // NULL,
4308 // GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4309 // msg,
4310 // GTK_STOCK_DIALOG_QUESTION,
4311 // GTK_STOCK_NO, GTK_RESPONSE_NO,
4312 // GTK_STOCK_YES, GTK_RESPONSE_YES,
4313 // NULL);
4314 // g_free(msg);
4315 // response = gtk_dialog_run(GTK_DIALOG(msgbox));
4316 // gtk_widget_destroy(msgbox);
4317 //
4318 // switch (response)
4319 // {
4320 // case GTK_STOCK_YES:
4321 // // Here we must rename all files with the new location, and remove the directory
4322 //
4323 // Rename_File ()
4324 //
4325 // break;
4326 // case BUTTON_NO:
4327 // break;
4328 // }
4329
4330 msgdialog = gtk_message_dialog_new(GTK_WINDOW(MainWindow),
4331 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4332 GTK_MESSAGE_ERROR,
4333 GTK_BUTTONS_CLOSE,
4334 "%s",
4335 "Cannot rename file");
4336 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (msgdialog),
4337 _("The directory name ‘%s’ already exists."),new_path_utf8);
4338 gtk_window_set_title(GTK_WINDOW(msgdialog),_("Rename File Error"));
4339
4340 gtk_dialog_run(GTK_DIALOG(msgdialog));
4341 gtk_widget_destroy(msgdialog);
4342
4343 g_free(directory_new_name_file);
4344 g_free(last_path);
4345 g_free(last_path_utf8);
4346 g_free(new_path);
4347 g_free(new_path_utf8);
4348
4349 return;
4350 }
4351 }
4352
4353 /* Temporary path (useful when changing only string case) */
4354 tmp_path = g_strdup_printf("%s.XXXXXX",last_path);
4355 tmp_path_utf8 = g_filename_display_name (tmp_path);
4356
4357 if ((fd_tmp = g_mkstemp (tmp_path)) >= 0)
4358 {
4359 /* TODO: handle error. */
4360 g_close (fd_tmp, NULL);
4361 g_unlink (tmp_path);
4362 }
4363
4364 /* Rename the directory from 'last name' to 'tmp name' */
4365 if (g_rename (last_path, tmp_path) != 0)
4366 {
4367 GtkWidget *msgdialog;
4368
4369 msgdialog = gtk_message_dialog_new(GTK_WINDOW(MainWindow),
4370 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4371 GTK_MESSAGE_ERROR,
4372 GTK_BUTTONS_CLOSE,
4373 "Cannot rename directory '%s' to '%s'",
4374 last_path_utf8,
4375 tmp_path_utf8);
4376 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msgdialog),"%s",g_strerror(errno));
4377 gtk_window_set_title(GTK_WINDOW(msgdialog),_("Rename Directory Error"));
4378
4379 gtk_dialog_run(GTK_DIALOG(msgdialog));
4380 gtk_widget_destroy(msgdialog);
4381
4382 g_free(directory_new_name_file);
4383 g_free(last_path);
4384 g_free(last_path_utf8);
4385 g_free(new_path);
4386 g_free(new_path_utf8);
4387 g_free(tmp_path);
4388 g_free(tmp_path_utf8);
4389
4390 return;
4391 }
4392
4393 /* Rename the directory from 'tmp name' to 'new name' (final name) */
4394 if (g_rename (tmp_path, new_path) != 0)
4395 {
4396 GtkWidget *msgdialog;
4397
4398 msgdialog = gtk_message_dialog_new(GTK_WINDOW(MainWindow),
4399 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
4400 GTK_MESSAGE_ERROR,
4401 GTK_BUTTONS_CLOSE,
4402 "Cannot rename directory '%s' to '%s",
4403 tmp_path_utf8,
4404 new_path_utf8);
4405 gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(msgdialog),"%s",g_strerror(errno));
4406 gtk_window_set_title(GTK_WINDOW(msgdialog),_("Rename Directory Error"));
4407
4408 gtk_dialog_run(GTK_DIALOG(msgdialog));
4409 gtk_widget_destroy(msgdialog);
4410
4411 g_free(directory_new_name_file);
4412 g_free(last_path);
4413 g_free(last_path_utf8);
4414 g_free(new_path);
4415 g_free(new_path_utf8);
4416 g_free(tmp_path);
4417 g_free(tmp_path_utf8);
4418
4419 return;
4420 }
4421
4422 et_file_list_update_directory_name (ETCore->ETFileList, last_path,
4423 new_path);
4424 Browser_Tree_Rename_Directory (self, last_path, new_path);
4425
4426 // To update file path in the browser entry
4427 if (ETCore->ETFileDisplayedList)
4428 {
4429 et_application_window_display_et_file (ET_APPLICATION_WINDOW (MainWindow),
4430 ETCore->ETFileDisplayed);
4431 }else
4432 {
4433 gchar *tmp = g_file_get_parse_name (et_browser_get_current_path (self));
4434 et_browser_entry_set_text (self, tmp);
4435 g_free (tmp);
4436 }
4437
4438 Destroy_Rename_Directory_Window (self);
4439 g_free(last_path);
4440 g_free(last_path_utf8);
4441 g_free(new_path);
4442 g_free(new_path_utf8);
4443 g_free(tmp_path);
4444 g_free(tmp_path_utf8);
4445 g_free(directory_new_name_file);
4446 et_application_window_status_bar_message (ET_APPLICATION_WINDOW (MainWindow),
4447 _("Directory renamed"), TRUE);
4448 }
4449
4450 static void
Rename_Directory_With_Mask_Toggled(EtBrowser * self)4451 Rename_Directory_With_Mask_Toggled (EtBrowser *self)
4452 {
4453 EtBrowserPrivate *priv;
4454
4455 priv = et_browser_get_instance_private (self);
4456
4457 gtk_widget_set_sensitive (priv->rename_directory_entry,
4458 !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->rename_directory_mask_toggle)));
4459 gtk_widget_set_sensitive (priv->rename_directory_mask_entry,
4460 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->rename_directory_mask_toggle)));
4461 gtk_widget_set_sensitive (priv->rename_directory_preview_label,
4462 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->rename_directory_mask_toggle)));
4463 }
4464
4465
4466 /*
4467 * Window where is typed the name of the program to run, which
4468 * receives the current directory as parameter.
4469 */
4470 void
et_browser_show_open_directory_with_dialog(EtBrowser * self)4471 et_browser_show_open_directory_with_dialog (EtBrowser *self)
4472 {
4473 EtBrowserPrivate *priv;
4474 GtkBuilder *builder;
4475 GtkWidget *button;
4476 gchar *current_directory = NULL;
4477
4478 g_return_if_fail (ET_BROWSER (self));
4479
4480 priv = et_browser_get_instance_private (self);
4481
4482 if (priv->open_directory_with_dialog != NULL)
4483 {
4484 gtk_window_present(GTK_WINDOW(priv->open_directory_with_dialog));
4485 return;
4486 }
4487
4488 /* Current directory. */
4489 if (!priv->current_path)
4490 {
4491 return;
4492 }
4493
4494 current_directory = g_file_get_path (priv->current_path);
4495
4496 builder = gtk_builder_new_from_resource ("/org/gnome/EasyTAG/browser_dialogs.ui");
4497
4498 priv->open_directory_with_dialog = GTK_WIDGET (gtk_builder_get_object (builder,
4499 "open_directory_dialog"));
4500
4501 gtk_window_set_transient_for (GTK_WINDOW (priv->open_directory_with_dialog),
4502 GTK_WINDOW (MainWindow));
4503 gtk_dialog_set_default_response (GTK_DIALOG (priv->open_directory_with_dialog),
4504 GTK_RESPONSE_OK);
4505 g_signal_connect (priv->open_directory_with_dialog, "response",
4506 G_CALLBACK (et_run_program_tree_on_response), self);
4507
4508 /* The combobox to enter the program to run */
4509 priv->open_directory_with_combobox = GTK_WIDGET (gtk_builder_get_object (builder,
4510 "open_directory_combo"));
4511 gtk_combo_box_set_model (GTK_COMBO_BOX (priv->open_directory_with_combobox),
4512 GTK_TREE_MODEL (priv->run_program_model));
4513
4514 /* History list */
4515 gtk_list_store_clear (priv->run_program_model);
4516 Load_Run_Program_With_Directory_List (priv->run_program_model,
4517 MISC_COMBO_TEXT);
4518 g_signal_connect_swapped (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->open_directory_with_combobox))),
4519 "activate",
4520 G_CALLBACK (Run_Program_With_Directory),
4521 self);
4522
4523 /* The button to Browse */
4524 button = GTK_WIDGET (gtk_builder_get_object (builder,
4525 "open_directory_button"));
4526 g_signal_connect_swapped (button, "clicked",
4527 G_CALLBACK (File_Selection_Window_For_File),
4528 G_OBJECT (gtk_bin_get_child (GTK_BIN (priv->open_directory_with_combobox))));
4529
4530 /* We attach useful data to the combobox (into Run_Program_With_Directory) */
4531 g_object_set_data_full (G_OBJECT (priv->open_directory_with_combobox),
4532 "Current_Directory", current_directory, g_free);
4533
4534 /* Button to execute */
4535 button = gtk_dialog_get_widget_for_response (GTK_DIALOG (priv->open_directory_with_dialog),
4536 GTK_RESPONSE_OK);
4537 g_signal_connect_swapped (button, "clicked",
4538 G_CALLBACK (Run_Program_With_Directory),
4539 self);
4540 g_signal_connect_swapped (gtk_bin_get_child (GTK_BIN (priv->open_directory_with_combobox)),
4541 "changed",
4542 G_CALLBACK (empty_entry_disable_widget),
4543 G_OBJECT (button));
4544 g_signal_emit_by_name (G_OBJECT (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->open_directory_with_combobox)))),
4545 "changed", NULL);
4546
4547 gtk_widget_show_all (priv->open_directory_with_dialog);
4548 }
4549
4550 static void
Destroy_Run_Program_Tree_Window(EtBrowser * self)4551 Destroy_Run_Program_Tree_Window (EtBrowser *self)
4552 {
4553 EtBrowserPrivate *priv;
4554
4555 priv = et_browser_get_instance_private (self);
4556
4557 if (priv->open_directory_with_dialog)
4558 {
4559 gtk_widget_hide (priv->open_directory_with_dialog);
4560 }
4561 }
4562
4563 void
Run_Program_With_Directory(EtBrowser * self)4564 Run_Program_With_Directory (EtBrowser *self)
4565 {
4566 EtBrowserPrivate *priv;
4567 gchar *program_name;
4568 gchar *current_directory;
4569 GList *args_list = NULL;
4570 gboolean program_ran;
4571 GError *error = NULL;
4572
4573 priv = et_browser_get_instance_private (self);
4574
4575 program_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->open_directory_with_combobox)))));
4576 current_directory = g_object_get_data (G_OBJECT (priv->open_directory_with_combobox),
4577 "Current_Directory");
4578
4579 // List of parameters (here only one! : the current directory)
4580 args_list = g_list_append(args_list,current_directory);
4581
4582 program_ran = et_run_program (program_name, args_list, &error);
4583 g_list_free(args_list);
4584
4585 if (program_ran)
4586 {
4587 gchar *msg;
4588
4589 // Append newest choice to the drop down list
4590 Add_String_To_Combo_List(priv->run_program_model, program_name);
4591
4592 // Save list attached to the combobox
4593 Save_Run_Program_With_Directory_List(priv->run_program_model, MISC_COMBO_TEXT);
4594
4595 Destroy_Run_Program_Tree_Window (self);
4596
4597 msg = g_strdup_printf (_("Executed command ‘%s’"), program_name);
4598 et_application_window_status_bar_message (ET_APPLICATION_WINDOW (MainWindow),
4599 msg, TRUE);
4600
4601 g_free (msg);
4602 }
4603 else
4604 {
4605 Log_Print (LOG_ERROR, _("Failed to launch program ‘%s’"),
4606 error->message);
4607 g_clear_error (&error);
4608 }
4609
4610 g_free(program_name);
4611 }
4612
4613 static void
Run_Program_With_Selected_Files(EtBrowser * self)4614 Run_Program_With_Selected_Files (EtBrowser *self)
4615 {
4616 EtBrowserPrivate *priv;
4617 gchar *program_name;
4618 GList *selected_paths;
4619 GList *l;
4620 GList *args_list = NULL;
4621 GtkTreeIter iter;
4622 gboolean program_ran;
4623 GError *error = NULL;
4624
4625 priv = et_browser_get_instance_private (self);
4626
4627 if (!GTK_IS_COMBO_BOX (priv->open_files_with_combobox) || !ETCore->ETFileDisplayedList)
4628 return;
4629
4630 // Programe name to run
4631 program_name = g_strdup (gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->open_files_with_combobox)))));
4632
4633 // List of files to pass as parameters
4634 selected_paths = gtk_tree_selection_get_selected_rows(gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->file_view)), NULL);
4635
4636 for (l = selected_paths; l != NULL; l = g_list_next (l))
4637 {
4638 if (gtk_tree_model_get_iter (GTK_TREE_MODEL (priv->file_model), &iter,
4639 (GtkTreePath *)l->data))
4640 {
4641 const ET_File *ETFile;
4642
4643 gtk_tree_model_get (GTK_TREE_MODEL (priv->file_model), &iter,
4644 LIST_FILE_POINTER, &ETFile, -1);
4645
4646 args_list = g_list_prepend (args_list,
4647 ((File_Name *)ETFile->FileNameCur->data)->value);
4648 //args_list = g_list_append(args_list,((File_Name *)ETFile->FileNameCur->data)->value_utf8);
4649 }
4650 }
4651
4652 args_list = g_list_reverse (args_list);
4653 program_ran = et_run_program (program_name, args_list, &error);
4654
4655 g_list_free_full (selected_paths, (GDestroyNotify)gtk_tree_path_free);
4656 g_list_free(args_list);
4657
4658 if (program_ran)
4659 {
4660 gchar *msg;
4661
4662 // Append newest choice to the drop down list
4663 //gtk_list_store_prepend(GTK_LIST_STORE(priv->run_program_model), &iter);
4664 //gtk_list_store_set(priv->run_program_model, &iter, MISC_COMBO_TEXT, program_name, -1);
4665 Add_String_To_Combo_List(GTK_LIST_STORE(priv->run_program_model), program_name);
4666
4667 // Save list attached to the combobox
4668 Save_Run_Program_With_File_List(priv->run_program_model, MISC_COMBO_TEXT);
4669
4670 Destroy_Run_Program_List_Window (self);
4671
4672 msg = g_strdup_printf (_("Executed command ‘%s’"), program_name);
4673 et_application_window_status_bar_message (ET_APPLICATION_WINDOW (MainWindow),
4674 msg, TRUE);
4675
4676 g_free (msg);
4677 }
4678 else
4679 {
4680 Log_Print (LOG_ERROR, _("Failed to launch program ‘%s’"),
4681 error->message);
4682 g_clear_error (&error);
4683 }
4684
4685 g_free(program_name);
4686 }
4687
4688 /*
4689 * Window where is typed the name of the program to run, which
4690 * receives the current file as parameter.
4691 */
4692 void
et_browser_show_open_files_with_dialog(EtBrowser * self)4693 et_browser_show_open_files_with_dialog (EtBrowser *self)
4694 {
4695 EtBrowserPrivate *priv;
4696 GtkBuilder *builder;
4697 GtkWidget *button;
4698
4699 g_return_if_fail (ET_BROWSER (self));
4700
4701 priv = et_browser_get_instance_private (self);
4702
4703 if (priv->open_files_with_dialog != NULL)
4704 {
4705 gtk_window_present(GTK_WINDOW(priv->open_files_with_dialog));
4706 return;
4707 }
4708
4709 builder = gtk_builder_new_from_resource ("/org/gnome/EasyTAG/browser_dialogs.ui");
4710
4711 priv->open_files_with_dialog = GTK_WIDGET (gtk_builder_get_object (builder,
4712 "open_files_dialog"));
4713 gtk_dialog_set_default_response (GTK_DIALOG (priv->open_files_with_dialog),
4714 GTK_RESPONSE_OK);
4715 gtk_window_set_transient_for (GTK_WINDOW (priv->open_files_with_dialog),
4716 GTK_WINDOW (MainWindow));
4717 g_signal_connect ((priv->open_files_with_dialog), "response",
4718 G_CALLBACK (et_run_program_list_on_response), self);
4719
4720 /* The combobox to enter the program to run */
4721 priv->open_files_with_combobox = GTK_WIDGET (gtk_builder_get_object (builder,
4722 "open_files_combo"));
4723 gtk_combo_box_set_model (GTK_COMBO_BOX (priv->open_files_with_combobox),
4724 GTK_TREE_MODEL (priv->run_program_model));
4725 gtk_widget_set_size_request (GTK_WIDGET (priv->open_files_with_combobox),
4726 250, -1);
4727
4728 /* History list */
4729 gtk_list_store_clear (priv->run_program_model);
4730 Load_Run_Program_With_File_List (priv->run_program_model, MISC_COMBO_TEXT);
4731 g_signal_connect_swapped (gtk_bin_get_child (GTK_BIN (priv->open_files_with_combobox)),
4732 "activate",
4733 G_CALLBACK (Run_Program_With_Selected_Files),
4734 self);
4735
4736 /* The button to Browse */
4737 button = GTK_WIDGET (gtk_builder_get_object (builder,
4738 "open_files_button"));
4739 g_signal_connect_swapped (button, "clicked",
4740 G_CALLBACK (File_Selection_Window_For_File),
4741 G_OBJECT (gtk_bin_get_child (GTK_BIN (priv->open_files_with_combobox))));
4742
4743 g_object_unref (builder);
4744
4745 /* Button to execute */
4746 button = gtk_dialog_get_widget_for_response (GTK_DIALOG (priv->open_files_with_dialog),
4747 GTK_RESPONSE_OK);
4748 g_signal_connect_swapped (button, "clicked",
4749 G_CALLBACK (Run_Program_With_Selected_Files),
4750 self);
4751 g_signal_connect_swapped (gtk_bin_get_child (GTK_BIN (priv->open_files_with_combobox)),
4752 "changed",
4753 G_CALLBACK (empty_entry_disable_widget),
4754 G_OBJECT (button));
4755 g_signal_emit_by_name (gtk_bin_get_child (GTK_BIN (priv->open_files_with_combobox)),
4756 "changed", NULL);
4757
4758 gtk_widget_show_all (priv->open_files_with_dialog);
4759 }
4760
4761 static void
Destroy_Run_Program_List_Window(EtBrowser * self)4762 Destroy_Run_Program_List_Window (EtBrowser *self)
4763 {
4764 EtBrowserPrivate *priv;
4765
4766 priv = et_browser_get_instance_private (self);
4767
4768 if (priv->open_files_with_dialog)
4769 {
4770 gtk_widget_hide (priv->open_files_with_dialog);
4771 }
4772 }
4773
4774 /*
4775 * empty_entry_disable_widget:
4776 * @widget: a widget to set sensitive if @entry contains text
4777 * @entry: the entry for which to test the text
4778 *
4779 * Make @widget insensitive if @entry contains no text, or sensitive otherwise.
4780 */
4781 static void
empty_entry_disable_widget(GtkWidget * widget,GtkEntry * entry)4782 empty_entry_disable_widget (GtkWidget *widget, GtkEntry *entry)
4783 {
4784 const gchar *text;
4785
4786 g_return_if_fail (widget != NULL && entry != NULL);
4787
4788 text = gtk_entry_get_text (GTK_ENTRY (entry));
4789
4790 gtk_widget_set_sensitive (widget, text && *text);
4791 }
4792
4793 /*
4794 * et_rename_directory_on_response:
4795 * @dialog: the dialog which emitted the response signal
4796 * @response_id: the response ID
4797 * @user_data: user data set when the signal was connected
4798 *
4799 * Signal handler for the rename directory dialog.
4800 */
4801 static void
et_rename_directory_on_response(GtkDialog * dialog,gint response_id,gpointer user_data)4802 et_rename_directory_on_response (GtkDialog *dialog, gint response_id,
4803 gpointer user_data)
4804 {
4805 EtBrowser *self;
4806
4807 self = ET_BROWSER (user_data);
4808
4809 switch (response_id)
4810 {
4811 case GTK_RESPONSE_APPLY:
4812 Rename_Directory (self);
4813 break;
4814 case GTK_RESPONSE_CANCEL:
4815 case GTK_RESPONSE_DELETE_EVENT:
4816 Destroy_Rename_Directory_Window (self);
4817 break;
4818 default:
4819 g_assert_not_reached ();
4820 }
4821 }
4822
4823 /*
4824 * et_run_program_tree_on_response:
4825 * @dialog: the dialog which emitted the response signal
4826 * @response_id: the response ID
4827 * @user_data: user data set when the signal was connected
4828 *
4829 * Signal handler for the run program on directory tree dialog.
4830 */
4831 static void
et_run_program_tree_on_response(GtkDialog * dialog,gint response_id,gpointer user_data)4832 et_run_program_tree_on_response (GtkDialog *dialog, gint response_id,
4833 gpointer user_data)
4834 {
4835 EtBrowser *self;
4836
4837 self = ET_BROWSER (user_data);
4838
4839 switch (response_id)
4840 {
4841 case GTK_RESPONSE_OK:
4842 /* FIXME: Ignored for now. */
4843 break;
4844 case GTK_RESPONSE_CANCEL:
4845 case GTK_RESPONSE_DELETE_EVENT:
4846 Destroy_Run_Program_Tree_Window (self);
4847 break;
4848 default:
4849 g_assert_not_reached ();
4850 }
4851 }
4852 /*
4853 * et_run_program_list_on_response:
4854 * @dialog: the dialog which emitted the response signal
4855 * @response_id: the response ID
4856 * @user_data: user data set when the signal was connected
4857 *
4858 * Signal handler for the run program on selected file dialog.
4859 */
4860 static void
et_run_program_list_on_response(GtkDialog * dialog,gint response_id,gpointer user_data)4861 et_run_program_list_on_response (GtkDialog *dialog, gint response_id,
4862 gpointer user_data)
4863 {
4864 EtBrowser *self;
4865
4866 self = ET_BROWSER (user_data);
4867
4868 switch (response_id)
4869 {
4870 case GTK_RESPONSE_OK:
4871 /* FIXME: Ignored for now. */
4872 break;
4873 case GTK_RESPONSE_CANCEL:
4874 case GTK_RESPONSE_DELETE_EVENT:
4875 Destroy_Run_Program_List_Window (self);
4876 break;
4877 default:
4878 g_assert_not_reached ();
4879 }
4880 }
4881
4882 /*
4883 * get_sort_order_for_column_id:
4884 * @column_id: the column ID for which to set the sort order
4885 *
4886 * Gets the sort order for the given column ID from the browser list treeview
4887 * column.
4888 *
4889 * Returns: the sort order for @column_id
4890 */
4891 GtkSortType
et_browser_get_sort_order_for_column_id(EtBrowser * self,gint column_id)4892 et_browser_get_sort_order_for_column_id (EtBrowser *self, gint column_id)
4893 {
4894 GtkTreeViewColumn *column;
4895
4896 column = et_browser_get_column_for_column_id (self, column_id);
4897 return gtk_tree_view_column_get_sort_order (column);
4898 }
4899
4900 /*
4901 * get_column_for_column_id:
4902 * @column_id: the column ID of the #GtkTreeViewColumn to fetch
4903 *
4904 * Gets the browser list treeview column for the given column ID.
4905 *
4906 * Returns: (transfer none): the tree view column corresponding to @column_id
4907 */
4908 GtkTreeViewColumn *
et_browser_get_column_for_column_id(EtBrowser * self,gint column_id)4909 et_browser_get_column_for_column_id (EtBrowser *self, gint column_id)
4910 {
4911 EtBrowserPrivate *priv;
4912
4913 priv = et_browser_get_instance_private (self);
4914
4915 return gtk_tree_view_get_column (GTK_TREE_VIEW (priv->file_view),
4916 column_id);
4917 }
4918
4919 static void
et_browser_destroy(GtkWidget * widget)4920 et_browser_destroy (GtkWidget *widget)
4921 {
4922 EtBrowserPrivate *priv;
4923
4924 priv = et_browser_get_instance_private (ET_BROWSER (widget));
4925
4926 /* Save combobox history list before exit. */
4927 if (priv->entry_model)
4928 {
4929 Save_Path_Entry_List (priv->entry_model, MISC_COMBO_TEXT);
4930 priv->entry_model = NULL;
4931 /* The model is disposed when the combo box is disposed. */
4932 }
4933
4934 GTK_WIDGET_CLASS (et_browser_parent_class)->destroy (widget);
4935 }
4936
4937 static void
et_browser_finalize(GObject * object)4938 et_browser_finalize (GObject *object)
4939 {
4940 EtBrowserPrivate *priv;
4941
4942 priv = et_browser_get_instance_private (ET_BROWSER (object));
4943
4944 g_clear_object (&priv->current_path);
4945 g_clear_object (&priv->run_program_model);
4946
4947 G_OBJECT_CLASS (et_browser_parent_class)->finalize (object);
4948 }
4949
4950 static void
et_browser_init(EtBrowser * self)4951 et_browser_init (EtBrowser *self)
4952 {
4953 gtk_widget_init_template (GTK_WIDGET (self));
4954 create_browser (self);
4955 }
4956
4957 static
et_browser_class_init(EtBrowserClass * klass)4958 void et_browser_class_init (EtBrowserClass *klass)
4959 {
4960 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
4961
4962 G_OBJECT_CLASS (klass)->finalize = et_browser_finalize;
4963 widget_class->destroy = et_browser_destroy;
4964
4965 gtk_widget_class_set_template_from_resource (widget_class,
4966 "/org/gnome/EasyTAG/browser.ui");
4967 gtk_widget_class_bind_template_child_private (widget_class, EtBrowser,
4968 files_label);
4969 gtk_widget_class_bind_template_child_private (widget_class, EtBrowser,
4970 open_button);
4971 gtk_widget_class_bind_template_child_private (widget_class, EtBrowser,
4972 entry_model);
4973 gtk_widget_class_bind_template_child_private (widget_class, EtBrowser,
4974 entry_combo);
4975 gtk_widget_class_bind_template_child_private (widget_class, EtBrowser,
4976 directory_album_artist_notebook);
4977 gtk_widget_class_bind_template_child_private (widget_class, EtBrowser,
4978 file_model);
4979 gtk_widget_class_bind_template_child_private (widget_class, EtBrowser,
4980 file_view);
4981 gtk_widget_class_bind_template_child_private (widget_class, EtBrowser,
4982 album_model);
4983 gtk_widget_class_bind_template_child_private (widget_class, EtBrowser,
4984 album_view);
4985 gtk_widget_class_bind_template_child_private (widget_class, EtBrowser,
4986 artist_model);
4987 gtk_widget_class_bind_template_child_private (widget_class, EtBrowser,
4988 artist_view);
4989 gtk_widget_class_bind_template_child_private (widget_class, EtBrowser,
4990 directory_model);
4991 gtk_widget_class_bind_template_child_private (widget_class, EtBrowser,
4992 directory_view);
4993 gtk_widget_class_bind_template_callback (widget_class, collapse_cb);
4994 gtk_widget_class_bind_template_callback (widget_class, expand_cb);
4995 gtk_widget_class_bind_template_callback (widget_class,
4996 on_album_tree_button_press_event);
4997 gtk_widget_class_bind_template_callback (widget_class,
4998 on_artist_tree_button_press_event);
4999 gtk_widget_class_bind_template_callback (widget_class,
5000 on_directory_tree_button_press_event);
5001 gtk_widget_class_bind_template_callback (widget_class,
5002 on_file_tree_button_press_event);
5003 gtk_widget_class_bind_template_callback (widget_class,
5004 on_album_tree_popup_menu);
5005 gtk_widget_class_bind_template_callback (widget_class,
5006 on_artist_tree_popup_menu);
5007 gtk_widget_class_bind_template_callback (widget_class,
5008 on_directory_tree_popup_menu);
5009 gtk_widget_class_bind_template_callback (widget_class,
5010 on_file_tree_popup_menu);
5011 gtk_widget_class_bind_template_callback (widget_class,
5012 Browser_Entry_Activated);
5013 gtk_widget_class_bind_template_callback (widget_class,
5014 Browser_List_Key_Press);
5015 gtk_widget_class_bind_template_callback (widget_class,
5016 Browser_Tree_Key_Press);
5017 gtk_widget_class_bind_template_callback (widget_class,
5018 Browser_Tree_Node_Selected);
5019 }
5020
5021 /*
5022 * et_browser_new:
5023 *
5024 * Create a new EtBrowser instance.
5025 *
5026 * Returns: a new #EtBrowser
5027 */
5028 EtBrowser *
et_browser_new(void)5029 et_browser_new (void)
5030 {
5031 return g_object_new (ET_TYPE_BROWSER, NULL);
5032 }
5033