1 /* EasyTAG - tag editor for audio files
2 * Copyright (C) 2014-2016 David King <amigadave@amigadave.com>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the Free
6 * Software Foundation; either version 2 of the License, or (at your option)
7 * any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 51
16 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include "config.h"
20
21 #include "file_list.h"
22
23 #include <gtk/gtk.h>
24 #include <glib/gi18n.h>
25 #include <locale.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <sys/stat.h>
29 #include <unistd.h>
30
31 #include "application_window.h"
32 #include "charset.h"
33 #include "easytag.h"
34 #include "log.h"
35 #include "misc.h"
36 #include "mpeg_header.h"
37 #include "monkeyaudio_header.h"
38 #include "musepack_header.h"
39 #include "picture.h"
40 #include "ape_tag.h"
41 #ifdef ENABLE_MP3
42 #include "id3_tag.h"
43 #endif
44 #ifdef ENABLE_OGG
45 #include "ogg_header.h"
46 #include "ogg_tag.h"
47 #endif
48 #ifdef ENABLE_FLAC
49 #include "flac_header.h"
50 #include "flac_tag.h"
51 #endif
52 #ifdef ENABLE_MP4
53 #include "mp4_header.h"
54 #include "mp4_tag.h"
55 #endif
56 #ifdef ENABLE_WAVPACK
57 #include "wavpack_header.h"
58 #include "wavpack_tag.h"
59 #endif
60 #ifdef ENABLE_OPUS
61 #include "opus_header.h"
62 #include "opus_tag.h"
63 #endif
64
65 /*
66 * et_file_list_free:
67 * @file_list: (element-type ET_File) (allow-none): a list of files
68 *
69 * Frees the full list of files.
70 */
71 void
et_file_list_free(GList * file_list)72 et_file_list_free (GList *file_list)
73 {
74 g_return_if_fail (file_list != NULL);
75
76 g_list_free_full (file_list, (GDestroyNotify)ET_Free_File_List_Item);
77 }
78
79 static void
et_history_file_free(ET_History_File * file)80 et_history_file_free (ET_History_File *file)
81 {
82 g_slice_free (ET_History_File, file);
83 }
84
85 /*
86 * History list contains only pointers, so no data to free except the history structure.
87 */
88 void
et_history_file_list_free(GList * file_list)89 et_history_file_list_free (GList *file_list)
90 {
91 g_return_if_fail (file_list != NULL);
92
93 /* et_history_list_add() sets the list to the final element, so explicitly
94 * go back to the start. */
95 g_list_free_full (g_list_first (file_list),
96 (GDestroyNotify)et_history_file_free);
97 }
98
99 /*
100 * "Display" list contains only pointers, so NOTHING to free
101 */
102 void
et_displayed_file_list_free(GList * file_list)103 et_displayed_file_list_free (GList *file_list)
104 {
105 }
106
107 /*
108 * ArtistAlbum list contains 3 levels of lists
109 */
110 void
et_artist_album_file_list_free(GList * file_list)111 et_artist_album_file_list_free (GList *file_list)
112 {
113 GList *l;
114
115 g_return_if_fail (file_list != NULL);
116
117 /* Pointers are stored inside the artist/album list-stores, so free them
118 * first. */
119 et_application_window_browser_clear_artist_model (ET_APPLICATION_WINDOW (MainWindow));
120 et_application_window_browser_clear_album_model (ET_APPLICATION_WINDOW (MainWindow));
121
122 for (l = file_list; l != NULL; l = g_list_next (l))
123 {
124 GList *m;
125
126 for (m = (GList *)l->data; m != NULL; m = g_list_next (m))
127 {
128 GList *n = (GList *)m->data;
129 if (n)
130 g_list_free (n);
131 }
132
133 if (l->data) /* Free AlbumList list. */
134 g_list_free ((GList *)l->data);
135 }
136
137 g_list_free (file_list);
138 }
139
140 /* Key for each item of ETFileList */
141 static guint
ET_File_Key_New(void)142 ET_File_Key_New (void)
143 {
144 static guint ETFileKey = 0;
145 return ++ETFileKey;
146 }
147
148 /*
149 * et_core_read_file_info:
150 * @file: a file from which to read information
151 * @ETFileInfo: (out caller-allocates): a file information structure
152 * @error: a #GError to provide information on erros, or %NULL to ignore
153 *
154 * Fille @ETFileInfo with information about the file. Currently, this only
155 * fills the file size.
156 *
157 * Returns: %TRUE on success, %FALSE otherwise
158 */
159 static gboolean
et_core_read_file_info(GFile * file,ET_File_Info * ETFileInfo,GError ** error)160 et_core_read_file_info (GFile *file,
161 ET_File_Info *ETFileInfo,
162 GError **error)
163 {
164 GFileInfo *info;
165
166 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
167 g_return_val_if_fail (file != NULL && ETFileInfo != NULL, FALSE);
168
169 info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_SIZE,
170 G_FILE_QUERY_INFO_NONE, NULL, error);
171
172 if (!info)
173 {
174 g_assert (error == NULL || *error != NULL);
175 return FALSE;
176 }
177
178 ETFileInfo->version = 0;
179 ETFileInfo->bitrate = 0;
180 ETFileInfo->samplerate = 0;
181 ETFileInfo->mode = 0;
182 ETFileInfo->size = g_file_info_get_size (info);
183 ETFileInfo->duration = 0;
184
185 g_assert (error == NULL || *error == NULL);
186 g_object_unref (info);
187
188 return TRUE;
189 }
190
191 /*
192 * et_file_list_add:
193 * Add a file to the "main" list. And get all information of the file.
194 * The filename passed in should be in raw format, only convert it to UTF8 when
195 * displaying it.
196 */
197 GList *
et_file_list_add(GList * file_list,GFile * file)198 et_file_list_add (GList *file_list,
199 GFile *file)
200 {
201 GList *result;
202 const ET_File_Description *description;
203 ET_File *ETFile;
204 File_Name *FileName;
205 File_Tag *FileTag;
206 ET_File_Info *ETFileInfo;
207 gchar *ETFileExtension;
208 guint ETFileKey;
209 guint undo_key;
210 GFileInfo *fileinfo;
211 gchar *filename;
212 gchar *display_path;
213 GError *error = NULL;
214 gboolean success;
215
216 g_return_val_if_fail (file != NULL, file_list);
217
218 /* Primary Key for this file */
219 ETFileKey = ET_File_Key_New();
220
221 /* Get description of the file */
222 filename = g_file_get_path (file);
223 display_path = g_filename_display_name (filename);
224 description = ET_Get_File_Description (filename);
225
226 /* Get real extension of the file (keeping the case) */
227 ETFileExtension = g_strdup(ET_Get_File_Extension(filename));
228
229 /* Fill the File_Name structure for FileNameList */
230 FileName = et_file_name_new ();
231 FileName->saved = TRUE; /* The file hasn't been changed, so it's saved */
232 ET_Set_Filename_File_Name_Item (FileName, display_path, filename);
233
234 /* Fill the File_Tag structure for FileTagList */
235 FileTag = et_file_tag_new ();
236 FileTag->saved = TRUE; /* The file hasn't been changed, so it's saved */
237
238 switch (description->TagType)
239 {
240 #ifdef ENABLE_MP3
241 case ID3_TAG:
242 if (!id3tag_read_file_tag (file, FileTag, &error))
243 {
244 Log_Print (LOG_ERROR,
245 _("Error reading ID3 tag from file ‘%s’: %s"),
246 display_path, error->message);
247 g_clear_error (&error);
248 }
249 break;
250 #endif
251 #ifdef ENABLE_OGG
252 case OGG_TAG:
253 if (!ogg_tag_read_file_tag (file, FileTag, &error))
254 {
255 Log_Print (LOG_ERROR,
256 _("Error reading tag from Ogg file ‘%s’: %s"),
257 display_path, error->message);
258 g_clear_error (&error);
259 }
260 break;
261 #endif
262 #ifdef ENABLE_FLAC
263 case FLAC_TAG:
264 if (!flac_tag_read_file_tag (file, FileTag, &error))
265 {
266 Log_Print (LOG_ERROR,
267 _("Error reading tag from FLAC file ‘%s’: %s"),
268 display_path, error->message);
269 g_clear_error (&error);
270 }
271 break;
272 #endif
273 case APE_TAG:
274 if (!ape_tag_read_file_tag (file, FileTag, &error))
275 {
276 Log_Print (LOG_ERROR,
277 _("Error reading APE tag from file ‘%s’: %s"),
278 display_path, error->message);
279 g_clear_error (&error);
280 }
281 break;
282 #ifdef ENABLE_MP4
283 case MP4_TAG:
284 if (!mp4tag_read_file_tag (file, FileTag, &error))
285 {
286 Log_Print (LOG_ERROR,
287 _("Error reading tag from MP4 file ‘%s’: %s"),
288 display_path, error->message);
289 g_clear_error (&error);
290 }
291 break;
292 #endif
293 #ifdef ENABLE_WAVPACK
294 case WAVPACK_TAG:
295 if (!wavpack_tag_read_file_tag (file, FileTag, &error))
296 {
297 Log_Print (LOG_ERROR,
298 _("Error reading tag from WavPack file ‘%s’: %s"),
299 display_path, error->message);
300 g_clear_error (&error);
301 }
302 break;
303 #endif
304 #ifdef ENABLE_OPUS
305 case OPUS_TAG:
306 if (!et_opus_tag_read_file_tag (file, FileTag, &error))
307 {
308 Log_Print (LOG_ERROR,
309 _("Error reading tag from Opus file ‘%s’: %s"),
310 display_path, error->message);
311 g_clear_error (&error);
312 }
313 break;
314 #endif
315 #ifndef ENABLE_MP3
316 case ID3_TAG:
317 #endif
318 #ifndef ENABLE_OGG
319 case OGG_TAG:
320 #endif
321 #ifndef ENABLE_FLAC
322 case FLAC_TAG:
323 #endif
324 #ifndef ENABLE_MP4
325 case MP4_TAG:
326 #endif
327 #ifndef ENABLE_WAVPACK
328 case WAVPACK_TAG:
329 #endif
330 #ifndef ENABLE_OPUS
331 case OPUS_TAG:
332 #endif
333 case UNKNOWN_TAG:
334 default:
335 /* FIXME: Translatable string. */
336 Log_Print (LOG_ERROR,
337 "FileTag: Undefined tag type (%d) for file %s",
338 (gint)description->TagType, display_path);
339 break;
340 }
341
342 if (FileTag->year && g_utf8_strlen (FileTag->year, -1) > 4)
343 {
344 Log_Print (LOG_WARNING,
345 _("The year value ‘%s’ seems to be invalid in file ‘%s’. The information will be lost when saving"),
346 FileTag->year, display_path);
347 }
348
349 /* Fill the ET_File_Info structure */
350 ETFileInfo = et_file_info_new ();
351
352 switch (description->FileType)
353 {
354 #if defined ENABLE_MP3 && defined ENABLE_ID3LIB
355 case MP3_FILE:
356 case MP2_FILE:
357 success = et_mpeg_header_read_file_info (file, ETFileInfo, &error);
358 break;
359 #endif
360 #ifdef ENABLE_OGG
361 case OGG_FILE:
362 success = et_ogg_header_read_file_info (file, ETFileInfo, &error);
363 break;
364 #endif
365 #ifdef ENABLE_SPEEX
366 case SPEEX_FILE:
367 success = et_speex_header_read_file_info (file, ETFileInfo,
368 &error);
369 break;
370 #endif
371 #ifdef ENABLE_FLAC
372 case FLAC_FILE:
373 success = et_flac_header_read_file_info (file, ETFileInfo, &error);
374 break;
375 #endif
376 case MPC_FILE:
377 success = et_mpc_header_read_file_info (file, ETFileInfo, &error);
378 break;
379 case MAC_FILE:
380 success = et_mac_header_read_file_info (file, ETFileInfo, &error);
381 break;
382 #ifdef ENABLE_WAVPACK
383 case WAVPACK_FILE:
384 success = et_wavpack_header_read_file_info (file, ETFileInfo,
385 &error);
386 break;
387 #endif
388 #ifdef ENABLE_MP4
389 case MP4_FILE:
390 success = et_mp4_header_read_file_info (file, ETFileInfo, &error);
391 break;
392 #endif
393 #ifdef ENABLE_OPUS
394 case OPUS_FILE:
395 success = et_opus_read_file_info (file, ETFileInfo, &error);
396 break;
397 #endif
398 case OFR_FILE:
399 #if !defined ENABLE_MP3 && !defined ENABLE_ID3LIB
400 case MP3_FILE:
401 case MP2_FILE:
402 #endif
403 #ifndef ENABLE_OGG
404 case OGG_FILE:
405 #endif
406 #ifndef ENABLE_SPEEX
407 case SPEEX_FILE:
408 #endif
409 #ifndef ENABLE_FLAC
410 case FLAC_FILE:
411 #endif
412 #ifndef ENABLE_MP4
413 case MP4_FILE:
414 #endif
415 #ifndef ENABLE_WAVPACK
416 case WAVPACK_FILE:
417 #endif
418 #ifndef ENABLE_OPUS
419 case OPUS_FILE:
420 #endif
421 case UNKNOWN_FILE:
422 default:
423 /* FIXME: Translatable string. */
424 Log_Print (LOG_ERROR,
425 "ETFileInfo: Undefined file type (%d) for file %s",
426 (gint)description->FileType, display_path);
427 /* To get at least the file size. */
428 success = et_core_read_file_info (file, ETFileInfo, &error);
429 break;
430 }
431
432 if (!success)
433 {
434 Log_Print (LOG_ERROR,
435 _("Error while querying information for file ‘%s’: %s"),
436 display_path, error->message);
437 g_error_free (error);
438 }
439
440 /* Store the modification time of the file to check if the file was changed
441 * before saving */
442 fileinfo = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED,
443 G_FILE_QUERY_INFO_NONE, NULL, NULL);
444
445 /* Attach all data defined above to this ETFile item */
446 ETFile = ET_File_Item_New();
447
448 if (fileinfo)
449 {
450 ETFile->FileModificationTime = g_file_info_get_attribute_uint64 (fileinfo,
451 G_FILE_ATTRIBUTE_TIME_MODIFIED);
452 g_object_unref (fileinfo);
453 }
454 else
455 {
456 ETFile->FileModificationTime = 0;
457 }
458
459 ETFile->IndexKey = 0; // Will be renumered after...
460 ETFile->ETFileKey = ETFileKey;
461 ETFile->ETFileDescription = description;
462 ETFile->ETFileExtension = ETFileExtension;
463 ETFile->FileNameList = g_list_append(NULL,FileName);
464 ETFile->FileNameCur = ETFile->FileNameList;
465 ETFile->FileNameNew = ETFile->FileNameList;
466 ETFile->FileTagList = g_list_append(NULL,FileTag);
467 ETFile->FileTag = ETFile->FileTagList;
468 ETFile->ETFileInfo = ETFileInfo;
469
470 /* Add the item to the "main list" */
471 result = g_list_append (file_list, ETFile);
472
473
474 /*
475 * Process the filename and tag to generate undo if needed...
476 * The undo key must be the same for FileName and FileTag => changed in the same time
477 */
478 undo_key = et_undo_key_new ();
479
480 FileName = et_file_name_new ();
481 FileName->key = undo_key;
482 ET_Save_File_Name_Internal(ETFile,FileName);
483
484 FileTag = et_file_tag_new ();
485 FileTag->key = undo_key;
486 ET_Save_File_Tag_Internal(ETFile,FileTag);
487
488 /*
489 * Generate undo for the file and the main undo list.
490 * If no changes detected, FileName and FileTag item are deleted.
491 */
492 ET_Manage_Changes_Of_File_Data(ETFile,FileName,FileTag);
493
494 /*
495 * Display a message if the file was changed at start
496 */
497 FileTag = (File_Tag *)ETFile->FileTag->data;
498 FileName = (File_Name *)ETFile->FileNameNew->data;
499 if ( (FileName && FileName->saved==FALSE) || (FileTag && FileTag->saved==FALSE) )
500 {
501 Log_Print (LOG_INFO, _("Automatic corrections applied for file ‘%s’"),
502 display_path);
503 }
504
505 /* Add the item to the ArtistAlbum list (placed here to take advantage of previous changes) */
506 //ET_Add_File_To_Artist_Album_File_List(ETFile);
507
508 //ET_Debug_Print_File_List(ETCore->ETFileList,__FILE__,__LINE__,__FUNCTION__);
509
510 g_free (filename);
511 g_free (display_path);
512
513 return result;
514 }
515
516 /*
517 * Comparison function for sorting by ascending artist in the ArtistAlbumList.
518 */
519 static gint
ET_Comp_Func_Sort_Artist_Item_By_Ascending_Artist(const GList * AlbumList1,const GList * AlbumList2)520 ET_Comp_Func_Sort_Artist_Item_By_Ascending_Artist (const GList *AlbumList1,
521 const GList *AlbumList2)
522 {
523 const GList *etfilelist1 = NULL;
524 const GList *etfilelist2 = NULL;
525 const ET_File *etfile1 = NULL;
526 const ET_File *etfile2 = NULL;
527 const gchar *etfile1_artist;
528 const gchar *etfile2_artist;
529
530 if (!AlbumList1 || !(etfilelist1 = (GList *)AlbumList1->data)
531 || !(etfile1 = (ET_File *)etfilelist1->data))
532 {
533 return -1;
534 }
535
536 if (!AlbumList2 || !(etfilelist2 = (GList *)AlbumList2->data)
537 || !(etfile2 = (ET_File *)etfilelist2->data))
538 {
539 return 1;
540 }
541
542 etfile1_artist = ((File_Tag *)etfile1->FileTag->data)->artist;
543 etfile2_artist = ((File_Tag *)etfile2->FileTag->data)->artist;
544
545 if (g_settings_get_boolean (MainSettings, "sort-case-sensitive"))
546 {
547 return et_normalized_strcmp0 (etfile1_artist, etfile2_artist);
548 }
549 else
550 {
551 return et_normalized_strcasecmp0 (etfile1_artist, etfile2_artist);
552 }
553 }
554
555 /*
556 * Comparison function for sorting by ascending album in the ArtistAlbumList.
557 */
558 static gint
ET_Comp_Func_Sort_Album_Item_By_Ascending_Album(const GList * etfilelist1,const GList * etfilelist2)559 ET_Comp_Func_Sort_Album_Item_By_Ascending_Album (const GList *etfilelist1,
560 const GList *etfilelist2)
561 {
562 const ET_File *etfile1;
563 const ET_File *etfile2;
564 const gchar *etfile1_album;
565 const gchar *etfile2_album;
566
567 if (!etfilelist1 || !(etfile1 = (ET_File *)etfilelist1->data))
568 {
569 return -1;
570 }
571
572 if (!etfilelist2 || !(etfile2 = (ET_File *)etfilelist2->data))
573 {
574 return 1;
575 }
576
577 etfile1_album = ((File_Tag *)etfile1->FileTag->data)->album;
578 etfile2_album = ((File_Tag *)etfile2->FileTag->data)->album;
579
580 if (g_settings_get_boolean (MainSettings, "sort-case-sensitive"))
581 {
582 return et_normalized_strcmp0 (etfile1_album, etfile2_album);
583 }
584 else
585 {
586 return et_normalized_strcasecmp0 (etfile1_album, etfile2_album);
587 }
588 }
589
590 /*
591 * Comparison function for sorting etfile in the ArtistAlbumList.
592 * FIX ME : should use the default sorting!
593 */
594 static gint
ET_Comp_Func_Sort_Etfile_Item_By_Ascending_Filename(const ET_File * ETFile1,const ET_File * ETFile2)595 ET_Comp_Func_Sort_Etfile_Item_By_Ascending_Filename (const ET_File *ETFile1,
596 const ET_File *ETFile2)
597 {
598
599 if (!ETFile1) return -1;
600 if (!ETFile2) return 1;
601
602 return ET_Comp_Func_Sort_File_By_Ascending_Filename(ETFile1,ETFile2);
603 }
604
605 /*
606 * The ETArtistAlbumFileList contains 3 levels of lists to sort the ETFile by artist then by album :
607 * - "ETArtistAlbumFileList" list is a list of "ArtistList" items,
608 * - "ArtistList" list is a list of "AlbumList" items,
609 * - "AlbumList" list is a list of ETFile items.
610 * Note : use the function ET_Debug_Print_Artist_Album_List(...) to understand how it works, it needed...
611 */
612 static GList *
et_artist_album_list_add_file(GList * file_list,ET_File * ETFile)613 et_artist_album_list_add_file (GList *file_list,
614 ET_File *ETFile)
615 {
616 const gchar *ETFile_Artist;
617 const gchar *ETFile_Album;
618 const gchar *etfile_artist;
619 const gchar *etfile_album;
620 GList *ArtistList;
621 GList *AlbumList = NULL;
622 GList *etfilelist = NULL;
623 ET_File *etfile = NULL;
624
625 g_return_val_if_fail (ETFile != NULL, NULL);
626
627 /* Album value of the ETFile passed in parameter. */
628 ETFile_Album = ((File_Tag *)ETFile->FileTag->data)->album;
629 /* Artist value of the ETFile passed in parameter. */
630 ETFile_Artist = ((File_Tag *)ETFile->FileTag->data)->artist;
631
632 for (ArtistList = file_list; ArtistList != NULL;
633 ArtistList = g_list_next (ArtistList))
634 {
635 AlbumList = (GList *)ArtistList->data; /* Take the first item */
636 /* Take the first item, and the first etfile item. */
637 if (AlbumList && (etfilelist = (GList *)AlbumList->data)
638 && (etfile = (ET_File *)etfilelist->data)
639 && ((File_Tag *)etfile->FileTag->data) != NULL)
640 {
641 etfile_artist = ((File_Tag *)etfile->FileTag->data)->artist;
642 }
643 else
644 {
645 etfile_artist = NULL;
646 }
647
648 if ((etfile_artist && ETFile_Artist && strcmp (etfile_artist,
649 ETFile_Artist) == 0)
650 || (!etfile_artist && !ETFile_Artist)) /* The "artist" values correspond? */
651 {
652 /* The "ArtistList" item was found! */
653 while (AlbumList)
654 {
655 if ((etfilelist = (GList *)AlbumList->data)
656 && (etfile = (ET_File *)etfilelist->data)
657 && ((File_Tag *)etfile->FileTag->data) != NULL)
658 {
659 etfile_album = ((File_Tag *)etfile->FileTag->data)->album;
660 }
661 else
662 {
663 etfile_album = NULL;
664 }
665
666 if ((etfile_album && ETFile_Album && strcmp (etfile_album,
667 ETFile_Album) == 0)
668 || (!etfile_album && !ETFile_Album))
669 /* The "album" values correspond? */
670 {
671 /* The "AlbumList" item was found!
672 * Add the ETFile to this AlbumList item */
673 AlbumList->data = g_list_insert_sorted ((GList *)AlbumList->data,
674 ETFile,
675 (GCompareFunc)ET_Comp_Func_Sort_Etfile_Item_By_Ascending_Filename);
676 return file_list;
677 }
678
679 AlbumList = g_list_next (AlbumList);
680 }
681
682 /* The "AlbumList" item was NOT found! => Add a new "AlbumList"
683 * item (+...) item to the "ArtistList" list. */
684 etfilelist = g_list_append (NULL, ETFile);
685 ArtistList->data = g_list_insert_sorted ((GList *)ArtistList->data,
686 etfilelist,
687 (GCompareFunc)ET_Comp_Func_Sort_Album_Item_By_Ascending_Album);
688 return file_list;
689 }
690 }
691
692 /* The "ArtistList" item was NOT found! => Add a new "ArtistList" to the
693 * main list (=ETArtistAlbumFileList). */
694 etfilelist = g_list_append (NULL, ETFile);
695 AlbumList = g_list_append (NULL, etfilelist);
696
697 /* Sort the list by ascending Artist. */
698 return g_list_insert_sorted (file_list, AlbumList,
699 (GCompareFunc)ET_Comp_Func_Sort_Artist_Item_By_Ascending_Artist);
700 }
701
702 GList *
et_artist_album_list_new_from_file_list(GList * file_list)703 et_artist_album_list_new_from_file_list (GList *file_list)
704 {
705 GList *result = NULL;
706 GList *l;
707
708 for (l = g_list_first (file_list); l != NULL; l = g_list_next (l))
709 {
710 ET_File *ETFile = (ET_File *)l->data;
711 result = et_artist_album_list_add_file (result, ETFile);
712 }
713
714 return result;
715 }
716
717 /*
718 * Delete the corresponding file (allocated data was previously freed!). Return TRUE if deleted.
719 */
720 static gboolean
ET_Remove_File_From_Artist_Album_List(ET_File * ETFile)721 ET_Remove_File_From_Artist_Album_List (ET_File *ETFile)
722 {
723 GList *ArtistList;
724 GList *AlbumList;
725 GList *etfilelist;
726
727 g_return_val_if_fail (ETFile != NULL, FALSE);
728
729 /* Search for the ETFile in the list. */
730 for (ArtistList = ETCore->ETArtistAlbumFileList; ArtistList != NULL;
731 ArtistList = g_list_next (ArtistList))
732 {
733 for (AlbumList = g_list_first ((GList *)ArtistList->data);
734 AlbumList != NULL; AlbumList = g_list_next (AlbumList))
735 {
736 for (etfilelist = g_list_first ((GList *)AlbumList->data);
737 etfilelist != NULL; etfilelist = g_list_next (etfilelist))
738 {
739 ET_File *etfile = (ET_File *)etfilelist->data;
740
741 if (ETFile == etfile) /* The ETFile to delete was found! */
742 {
743 etfilelist = g_list_remove (etfilelist, ETFile);
744
745 if (etfilelist) /* Delete from AlbumList. */
746 {
747 AlbumList->data = (gpointer) g_list_first (etfilelist);
748 }
749 else
750 {
751 AlbumList = g_list_remove (AlbumList, AlbumList->data);
752
753 if (AlbumList) /* Delete from ArtistList. */
754 {
755 ArtistList->data = AlbumList;
756 }
757 else
758 {
759 /* Delete from the main list. */
760 ETCore->ETArtistAlbumFileList = g_list_remove (ArtistList,ArtistList->data);
761
762 return TRUE;
763 }
764
765 return TRUE;
766 }
767
768 return TRUE;
769 }
770 }
771 }
772 }
773
774 return FALSE; /* ETFile is NUL, or not found in the list. */
775 }
776
777 /*
778 * Returns the length of the list of displayed files
779 */
780 static guint
et_displayed_file_list_length(GList * displayed_list)781 et_displayed_file_list_length (GList *displayed_list)
782 {
783 GList *list;
784
785 list = g_list_first (displayed_list);
786 return g_list_length (list);
787 }
788
789 /*
790 * Renumber the list of displayed files (IndexKey) from 1 to n
791 */
792 static void
et_displayed_file_list_renumber(GList * displayed_list)793 et_displayed_file_list_renumber (GList *displayed_list)
794 {
795 GList *l = NULL;
796 guint i = 1;
797
798 for (l = g_list_first (displayed_list); l != NULL; l = g_list_next (l))
799 {
800 ((ET_File *)l->data)->IndexKey = i++;
801 }
802 }
803
804 /*
805 * Delete the corresponding file and free the allocated data. Return TRUE if deleted.
806 */
807 void
ET_Remove_File_From_File_List(ET_File * ETFile)808 ET_Remove_File_From_File_List (ET_File *ETFile)
809 {
810 GList *ETFileList = NULL; // Item containing the ETFile to delete... (in ETCore->ETFileList)
811 GList *ETFileDisplayedList = NULL; // Item containing the ETFile to delete... (in ETCore->ETFileDisplayedList)
812
813 // Remove infos of the file
814 ETCore->ETFileDisplayedList_TotalSize -= ((ET_File_Info *)ETFile->ETFileInfo)->size;
815 ETCore->ETFileDisplayedList_TotalDuration -= ((ET_File_Info *)ETFile->ETFileInfo)->duration;
816
817 // Find the ETFileList containing the ETFile item
818 ETFileDisplayedList = g_list_find(g_list_first(ETCore->ETFileDisplayedList),ETFile);
819 ETFileList = g_list_find (ETCore->ETFileList, ETFile);
820
821 // Note : this ETFileList must be used only for ETCore->ETFileDisplayedList, and not ETCore->ETFileDisplayed
822 if (ETCore->ETFileDisplayedList == ETFileDisplayedList)
823 {
824 if (ETFileList->next)
825 ETCore->ETFileDisplayedList = ETFileDisplayedList->next;
826 else if (ETFileList->prev)
827 ETCore->ETFileDisplayedList = ETFileDisplayedList->prev;
828 else
829 ETCore->ETFileDisplayedList = NULL;
830 }
831 // If the current displayed file is just removing, it will be unable to display it again!
832 if (ETCore->ETFileDisplayed == ETFile)
833 {
834 if (ETCore->ETFileDisplayedList)
835 ETCore->ETFileDisplayed = (ET_File *)ETCore->ETFileDisplayedList->data;
836 else
837 ETCore->ETFileDisplayed = (ET_File *)NULL;
838 }
839
840 /* Remove the file from the ETFileList list. */
841 ETCore->ETFileList = g_list_remove (ETCore->ETFileList, ETFile);
842
843 // Remove the file from the ETArtistAlbumList list
844 ET_Remove_File_From_Artist_Album_List(ETFile);
845
846 /* Remove the file from the ETFileDisplayedList list (if not already). */
847 ETCore->ETFileDisplayedList = g_list_remove (g_list_first (ETCore->ETFileDisplayedList),
848 ETFile);
849
850 // Free data of the file
851 ET_Free_File_List_Item(ETFile);
852
853 /* Recalculate length of ETFileDisplayedList list. */
854 ETCore->ETFileDisplayedList_Length = et_displayed_file_list_length (ETCore->ETFileDisplayedList);
855
856 /* To number the ETFile in the list. */
857 et_displayed_file_list_renumber (ETCore->ETFileDisplayedList);
858
859 // Displaying...
860 if (ETCore->ETFileDisplayedList)
861 {
862 if (ETCore->ETFileDisplayed)
863 {
864 ET_Displayed_File_List_By_Etfile(ETCore->ETFileDisplayed);
865 }else if (ETCore->ETFileDisplayedList->data)
866 {
867 // Select the new file (synchronize index,...)
868 ET_Displayed_File_List_By_Etfile((ET_File *)ETCore->ETFileDisplayedList->data);
869 }
870 }else
871 {
872 // Reinit the tag and file area
873 et_application_window_file_area_clear (ET_APPLICATION_WINDOW (MainWindow));
874 et_application_window_tag_area_clear (ET_APPLICATION_WINDOW (MainWindow));
875 et_application_window_update_actions (ET_APPLICATION_WINDOW (MainWindow));
876 }
877 }
878
879 /**************************
880 * File sorting functions *
881 **************************/
882
883 /*
884 * Set appropriate sort order for the given column_id
885 */
886 static void
set_sort_order_for_column_id(gint column_id,GtkTreeViewColumn * column,EtSortMode sort_type)887 set_sort_order_for_column_id (gint column_id, GtkTreeViewColumn *column,
888 EtSortMode sort_type)
889 {
890 EtApplicationWindow *window;
891 EtSortMode current_mode;
892
893 window = ET_APPLICATION_WINDOW (MainWindow);
894
895 /* Removing the sort indicator for the currently selected treeview
896 * column. */
897 current_mode = g_settings_get_enum (MainSettings, "sort-mode");
898
899 if (current_mode < ET_SORT_MODE_ASCENDING_CREATION_DATE)
900 {
901 gtk_tree_view_column_set_sort_indicator (et_application_window_browser_get_column_for_column_id (window, current_mode / 2),
902 FALSE);
903 }
904
905 if (sort_type < ET_SORT_MODE_ASCENDING_CREATION_DATE)
906 {
907 gtk_tree_view_column_clicked (et_application_window_browser_get_column_for_column_id (window, column_id));
908
909 if (sort_type % 2 == 0)
910 {
911 /* GTK_SORT_ASCENDING */
912 if (et_application_window_browser_get_sort_order_for_column_id (window, column_id)
913 == GTK_SORT_DESCENDING)
914 {
915 gtk_tree_view_column_set_sort_order (column,
916 GTK_SORT_ASCENDING);
917 }
918 }
919 else
920 {
921 /* GTK_SORT_DESCENDING */
922 if (et_application_window_browser_get_sort_order_for_column_id (window, column_id)
923 == GTK_SORT_ASCENDING)
924 {
925 gtk_tree_view_column_set_sort_order (column,
926 GTK_SORT_DESCENDING);
927 }
928 }
929 }
930 }
931
932 /*
933 * Sort an 'ETFileList'
934 */
935 GList *
ET_Sort_File_List(GList * ETFileList,EtSortMode Sorting_Type)936 ET_Sort_File_List (GList *ETFileList,
937 EtSortMode Sorting_Type)
938 {
939 EtApplicationWindow *window;
940 GtkTreeViewColumn *column;
941 GList *etfilelist;
942 gint column_id = Sorting_Type / 2;
943
944 window = ET_APPLICATION_WINDOW (MainWindow);
945 column = et_application_window_browser_get_column_for_column_id (window,
946 column_id);
947
948 /* Important to rewind before. */
949 etfilelist = g_list_first (ETFileList);
950
951 set_sort_order_for_column_id (column_id, column, Sorting_Type);
952
953 /* Sort... */
954 switch (Sorting_Type)
955 {
956 case ET_SORT_MODE_ASCENDING_FILENAME:
957 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Ascending_Filename);
958 break;
959 case ET_SORT_MODE_DESCENDING_FILENAME:
960 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Descending_Filename);
961 break;
962 case ET_SORT_MODE_ASCENDING_TITLE:
963 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Ascending_Title);
964 break;
965 case ET_SORT_MODE_DESCENDING_TITLE:
966 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Descending_Title);
967 break;
968 case ET_SORT_MODE_ASCENDING_ARTIST:
969 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Ascending_Artist);
970 break;
971 case ET_SORT_MODE_DESCENDING_ARTIST:
972 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Descending_Artist);
973 break;
974 case ET_SORT_MODE_ASCENDING_ALBUM_ARTIST:
975 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Ascending_Album_Artist);
976 break;
977 case ET_SORT_MODE_DESCENDING_ALBUM_ARTIST:
978 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Descending_Album_Artist);
979 break;
980 case ET_SORT_MODE_ASCENDING_ALBUM:
981 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Ascending_Album);
982 break;
983 case ET_SORT_MODE_DESCENDING_ALBUM:
984 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Descending_Album);
985 break;
986 case ET_SORT_MODE_ASCENDING_YEAR:
987 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Ascending_Year);
988 break;
989 case ET_SORT_MODE_DESCENDING_YEAR:
990 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Descending_Year);
991 break;
992 case ET_SORT_MODE_ASCENDING_DISC_NUMBER:
993 etfilelist = g_list_sort (etfilelist,
994 (GCompareFunc)et_comp_func_sort_file_by_ascending_disc_number);
995 break;
996 case ET_SORT_MODE_DESCENDING_DISC_NUMBER:
997 etfilelist = g_list_sort (etfilelist,
998 (GCompareFunc)et_comp_func_sort_file_by_descending_disc_number);
999 break;
1000 case ET_SORT_MODE_ASCENDING_TRACK_NUMBER:
1001 etfilelist = g_list_sort (etfilelist,
1002 (GCompareFunc)ET_Comp_Func_Sort_File_By_Ascending_Track_Number);
1003 break;
1004 case ET_SORT_MODE_DESCENDING_TRACK_NUMBER:
1005 etfilelist = g_list_sort (etfilelist,
1006 (GCompareFunc)ET_Comp_Func_Sort_File_By_Descending_Track_Number);
1007 break;
1008 case ET_SORT_MODE_ASCENDING_GENRE:
1009 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Ascending_Genre);
1010 break;
1011 case ET_SORT_MODE_DESCENDING_GENRE:
1012 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Descending_Genre);
1013 break;
1014 case ET_SORT_MODE_ASCENDING_COMMENT:
1015 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Ascending_Comment);
1016 break;
1017 case ET_SORT_MODE_DESCENDING_COMMENT:
1018 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Descending_Comment);
1019 break;
1020 case ET_SORT_MODE_ASCENDING_COMPOSER:
1021 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Ascending_Composer);
1022 break;
1023 case ET_SORT_MODE_DESCENDING_COMPOSER:
1024 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Descending_Composer);
1025 break;
1026 case ET_SORT_MODE_ASCENDING_ORIG_ARTIST:
1027 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Ascending_Orig_Artist);
1028 break;
1029 case ET_SORT_MODE_DESCENDING_ORIG_ARTIST:
1030 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Descending_Orig_Artist);
1031 break;
1032 case ET_SORT_MODE_ASCENDING_COPYRIGHT:
1033 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Ascending_Copyright);
1034 break;
1035 case ET_SORT_MODE_DESCENDING_COPYRIGHT:
1036 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Descending_Copyright);
1037 break;
1038 case ET_SORT_MODE_ASCENDING_URL:
1039 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Ascending_Url);
1040 break;
1041 case ET_SORT_MODE_DESCENDING_URL:
1042 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Descending_Url);
1043 break;
1044 case ET_SORT_MODE_ASCENDING_ENCODED_BY:
1045 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Ascending_Encoded_By);
1046 break;
1047 case ET_SORT_MODE_DESCENDING_ENCODED_BY:
1048 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Descending_Encoded_By);
1049 break;
1050 case ET_SORT_MODE_ASCENDING_CREATION_DATE:
1051 etfilelist = g_list_sort (etfilelist,
1052 (GCompareFunc)ET_Comp_Func_Sort_File_By_Ascending_Creation_Date);
1053 break;
1054 case ET_SORT_MODE_DESCENDING_CREATION_DATE:
1055 etfilelist = g_list_sort (etfilelist,
1056 (GCompareFunc)ET_Comp_Func_Sort_File_By_Descending_Creation_Date);
1057 break;
1058 case ET_SORT_MODE_ASCENDING_FILE_TYPE:
1059 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Ascending_File_Type);
1060 break;
1061 case ET_SORT_MODE_DESCENDING_FILE_TYPE:
1062 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Descending_File_Type);
1063 break;
1064 case ET_SORT_MODE_ASCENDING_FILE_SIZE:
1065 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Ascending_File_Size);
1066 break;
1067 case ET_SORT_MODE_DESCENDING_FILE_SIZE:
1068 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Descending_File_Size);
1069 break;
1070 case ET_SORT_MODE_ASCENDING_FILE_DURATION:
1071 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Ascending_File_Duration);
1072 break;
1073 case ET_SORT_MODE_DESCENDING_FILE_DURATION:
1074 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Descending_File_Duration);
1075 break;
1076 case ET_SORT_MODE_ASCENDING_FILE_BITRATE:
1077 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Ascending_File_Bitrate);
1078 break;
1079 case ET_SORT_MODE_DESCENDING_FILE_BITRATE:
1080 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Descending_File_Bitrate);
1081 break;
1082 case ET_SORT_MODE_ASCENDING_FILE_SAMPLERATE:
1083 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Ascending_File_Samplerate);
1084 break;
1085 case ET_SORT_MODE_DESCENDING_FILE_SAMPLERATE:
1086 etfilelist = g_list_sort(etfilelist,(GCompareFunc)ET_Comp_Func_Sort_File_By_Descending_File_Samplerate);
1087 break;
1088 default:
1089 g_assert_not_reached ();
1090 break;
1091 }
1092 /* Save sorting mode (note: needed when called from UI). */
1093 g_settings_set_enum (MainSettings, "sort-mode", Sorting_Type);
1094
1095 //ETFileList = g_list_first(etfilelist);
1096 return etfilelist;
1097 }
1098
1099 /*
1100 * Returns the first item of the "displayed list"
1101 */
1102 GList *
ET_Displayed_File_List_First(void)1103 ET_Displayed_File_List_First (void)
1104 {
1105 ETCore->ETFileDisplayedList = g_list_first(ETCore->ETFileDisplayedList);
1106 return ETCore->ETFileDisplayedList;
1107 }
1108
1109 /*
1110 * Returns the previous item of the "displayed list". When no more item, it returns NULL.
1111 */
1112 GList *
ET_Displayed_File_List_Previous(void)1113 ET_Displayed_File_List_Previous (void)
1114 {
1115 if (ETCore->ETFileDisplayedList && ETCore->ETFileDisplayedList->prev)
1116 return ETCore->ETFileDisplayedList = ETCore->ETFileDisplayedList->prev;
1117 else
1118 return NULL;
1119 }
1120
1121 /*
1122 * Returns the next item of the "displayed list".
1123 * When no more item, it returns NULL to don't "overwrite" the list.
1124 */
1125 GList *
ET_Displayed_File_List_Next(void)1126 ET_Displayed_File_List_Next (void)
1127 {
1128 if (ETCore->ETFileDisplayedList && ETCore->ETFileDisplayedList->next)
1129 return ETCore->ETFileDisplayedList = ETCore->ETFileDisplayedList->next;
1130 else
1131 return NULL;
1132 }
1133
1134 /*
1135 * Returns the last item of the "displayed list"
1136 */
1137 GList *
ET_Displayed_File_List_Last(void)1138 ET_Displayed_File_List_Last (void)
1139 {
1140 ETCore->ETFileDisplayedList = g_list_last(ETCore->ETFileDisplayedList);
1141 return ETCore->ETFileDisplayedList;
1142 }
1143
1144 /*
1145 * Returns the item of the "displayed list" which correspond to the given 'ETFile' (used into browser list).
1146 */
1147 GList *
ET_Displayed_File_List_By_Etfile(const ET_File * ETFile)1148 ET_Displayed_File_List_By_Etfile (const ET_File *ETFile)
1149 {
1150 GList *etfilelist;
1151
1152 etfilelist = g_list_find (g_list_first (ETCore->ETFileDisplayedList),
1153 ETFile);
1154
1155 if (etfilelist)
1156 {
1157 /* To "save" the position like in ET_File_List_Next... (not very good -
1158 * FIXME) */
1159 ETCore->ETFileDisplayedList = etfilelist;
1160 }
1161
1162 return etfilelist;
1163 }
1164
1165 /*
1166 * Load the list of displayed files (calculate length, size, ...)
1167 * It contains part (filtrated : view by artists and albums) or full ETCore->ETFileList list
1168 */
1169 void
et_displayed_file_list_set(GList * ETFileList)1170 et_displayed_file_list_set (GList *ETFileList)
1171 {
1172 GList *l = NULL;
1173
1174 ETCore->ETFileDisplayedList = g_list_first(ETFileList);
1175
1176 ETCore->ETFileDisplayedList_Length = et_displayed_file_list_length (ETCore->ETFileDisplayedList);
1177 ETCore->ETFileDisplayedList_TotalSize = 0;
1178 ETCore->ETFileDisplayedList_TotalDuration = 0;
1179
1180 // Get size and duration of files in the list
1181 for (l = ETCore->ETFileDisplayedList; l != NULL; l = g_list_next (l))
1182 {
1183 ETCore->ETFileDisplayedList_TotalSize += ((ET_File_Info *)((ET_File *)l->data)->ETFileInfo)->size;
1184 ETCore->ETFileDisplayedList_TotalDuration += ((ET_File_Info *)((ET_File *)l->data)->ETFileInfo)->duration;
1185 }
1186
1187 /* Sort the file list. */
1188 ET_Sort_File_List (ETCore->ETFileDisplayedList,
1189 g_settings_get_enum (MainSettings,
1190 "sort-mode"));
1191
1192 /* Synchronize, so that the core file list pointer always points to the
1193 * head of the list. */
1194 ETCore->ETFileList = g_list_first (ETCore->ETFileList);
1195
1196 /* Should renums ETCore->ETFileDisplayedList only! */
1197 et_displayed_file_list_renumber (ETCore->ETFileDisplayedList);
1198 }
1199
1200 /*
1201 * Function used to update path of filenames into list after renaming a parent directory
1202 * (for ex: "/mp3/old_path/file.mp3" to "/mp3/new_path/file.mp3"
1203 */
1204 void
et_file_list_update_directory_name(GList * file_list,const gchar * old_path,const gchar * new_path)1205 et_file_list_update_directory_name (GList *file_list,
1206 const gchar *old_path,
1207 const gchar *new_path)
1208 {
1209 GList *filelist;
1210 ET_File *file;
1211 GList *filenamelist;
1212 gchar *filename;
1213 gchar *old_path_tmp;
1214
1215 g_return_if_fail (file_list != NULL);
1216 g_return_if_fail (!et_str_empty (old_path));
1217 g_return_if_fail (!et_str_empty (new_path));
1218
1219 /* Add '/' to end of path to avoid ambiguity between a directory and a
1220 * filename... */
1221 if (old_path[strlen (old_path) - 1] == G_DIR_SEPARATOR)
1222 {
1223 old_path_tmp = g_strdup (old_path);
1224 }
1225 else
1226 {
1227 old_path_tmp = g_strconcat (old_path, G_DIR_SEPARATOR_S, NULL);
1228 }
1229
1230 for (filelist = g_list_first (file_list); filelist != NULL;
1231 filelist = g_list_next (filelist))
1232 {
1233 if ((file = filelist->data))
1234 {
1235 for (filenamelist = file->FileNameList; filenamelist != NULL;
1236 filenamelist = g_list_next (filenamelist))
1237 {
1238 File_Name *FileName = (File_Name *)filenamelist->data;
1239
1240 if ( FileName && (filename=FileName->value) )
1241 {
1242 /* Replace path of filename. */
1243 if (strncmp (filename, old_path_tmp, strlen (old_path_tmp))
1244 == 0)
1245 {
1246 gchar *filename_tmp;
1247
1248 // Create the new filename
1249 filename_tmp = g_strconcat (new_path,
1250 (new_path[strlen (new_path) - 1] == G_DIR_SEPARATOR) ? "" : G_DIR_SEPARATOR_S,
1251 &filename[strlen (old_path_tmp)],NULL);
1252
1253 ET_Set_Filename_File_Name_Item (FileName, NULL,
1254 filename_tmp);
1255 g_free (filename_tmp);
1256 }
1257 }
1258 }
1259 }
1260 }
1261
1262 g_free (old_path_tmp);
1263 }
1264
1265 /*
1266 * Execute one 'undo' in the main undo list (it selects the last ETFile changed,
1267 * before to apply an undo action)
1268 */
1269 ET_File *
ET_Undo_History_File_Data(void)1270 ET_Undo_History_File_Data (void)
1271 {
1272 ET_File *ETFile;
1273 const ET_History_File *ETHistoryFile;
1274
1275 g_return_val_if_fail (ETCore->ETHistoryFileList != NULL, NULL);
1276 g_return_val_if_fail (et_history_list_has_undo (ETCore->ETHistoryFileList), NULL);
1277
1278 ETHistoryFile = (ET_History_File *)ETCore->ETHistoryFileList->data;
1279 ETFile = (ET_File *)ETHistoryFile->ETFile;
1280 ET_Displayed_File_List_By_Etfile(ETFile);
1281 ET_Undo_File_Data(ETFile);
1282
1283 if (ETCore->ETHistoryFileList->prev)
1284 ETCore->ETHistoryFileList = ETCore->ETHistoryFileList->prev;
1285 return ETFile;
1286 }
1287
1288 /*
1289 * et_history_list_has_undo:
1290 * @history_list: the end of a history list
1291 *
1292 * Returns: %TRUE if undo file list contains undo data, %FALSE otherwise
1293 */
1294 gboolean
et_history_list_has_undo(GList * history_list)1295 et_history_list_has_undo (GList *history_list)
1296 {
1297 return history_list && history_list->prev;
1298 }
1299
1300
1301 /*
1302 * Execute one 'redo' in the main undo list
1303 */
1304 ET_File *
ET_Redo_History_File_Data(void)1305 ET_Redo_History_File_Data (void)
1306 {
1307 ET_File *ETFile;
1308 ET_History_File *ETHistoryFile;
1309
1310 if (!ETCore->ETHistoryFileList
1311 || !et_history_list_has_redo (ETCore->ETHistoryFileList))
1312 {
1313 return NULL;
1314 }
1315
1316 ETHistoryFile = (ET_History_File *)ETCore->ETHistoryFileList->next->data;
1317 ETFile = (ET_File *)ETHistoryFile->ETFile;
1318 ET_Displayed_File_List_By_Etfile(ETFile);
1319 ET_Redo_File_Data(ETFile);
1320
1321 if (ETCore->ETHistoryFileList->next)
1322 ETCore->ETHistoryFileList = ETCore->ETHistoryFileList->next;
1323 return ETFile;
1324 }
1325
1326 /*
1327 * et_history_list_has_redo:
1328 * @history_list: the end of a history list
1329 *
1330 * Returns: %TRUE if undo file list contains redo data, %FALSE otherwise
1331 */
1332 gboolean
et_history_list_has_redo(GList * history_list)1333 et_history_list_has_redo (GList *history_list)
1334 {
1335 return history_list && history_list->next;
1336 }
1337
1338 /*
1339 * Add a ETFile item to the main undo list of files
1340 */
1341 GList *
et_history_list_add(GList * history_list,ET_File * ETFile)1342 et_history_list_add (GList *history_list,
1343 ET_File *ETFile)
1344 {
1345 ET_History_File *ETHistoryFile;
1346 GList *result;
1347
1348 g_return_val_if_fail (ETFile != NULL, FALSE);
1349
1350 ETHistoryFile = g_slice_new0 (ET_History_File);
1351 ETHistoryFile->ETFile = ETFile;
1352
1353 /* The undo list must contains one item before the 'first undo' data */
1354 if (!history_list)
1355 {
1356 result = g_list_append (NULL,
1357 g_slice_new0 (ET_History_File));
1358 }
1359 else
1360 {
1361 result = history_list;
1362 }
1363
1364 /* Add the item to the list (cut end of list from the current element) */
1365 result = g_list_append (result, ETHistoryFile);
1366 /* TODO: Investigate whether this is sensible. */
1367 result = g_list_last (result);
1368
1369 return result;
1370 }
1371
1372 /*
1373 * et_file_list_check_all_saved:
1374 * @etfilelist: (element-type ET_File) (allow-none): a list of files
1375 *
1376 * Checks if some files, in the list, have been changed but not saved.
1377 *
1378 * Returns: %TRUE if all files have been saved, %FALSE otherwise
1379 */
1380 gboolean
et_file_list_check_all_saved(GList * etfilelist)1381 et_file_list_check_all_saved (GList *etfilelist)
1382 {
1383 if (!etfilelist)
1384 {
1385 return TRUE;
1386 }
1387 else
1388 {
1389 GList *l;
1390
1391 for (l = g_list_first (etfilelist); l != NULL; l = g_list_next (l))
1392 {
1393 if (!et_file_check_saved ((ET_File *)l->data))
1394 {
1395 return FALSE;
1396 }
1397 }
1398
1399 return TRUE;
1400 }
1401 }
1402
1403 /*
1404 * Returns the number of file in the directory of the selected file.
1405 * Parameter "path" should be in UTF-8
1406 */
1407 guint
et_file_list_get_n_files_in_path(GList * file_list,const gchar * path_utf8)1408 et_file_list_get_n_files_in_path (GList *file_list,
1409 const gchar *path_utf8)
1410 {
1411 gchar *path_key;
1412 GList *l;
1413 guint count = 0;
1414
1415 g_return_val_if_fail (path_utf8 != NULL, count);
1416
1417 path_key = g_utf8_collate_key (path_utf8, -1);
1418
1419 for (l = g_list_first (file_list); l != NULL; l = g_list_next (l))
1420 {
1421 ET_File *ETFile = (ET_File *)l->data;
1422 const gchar *cur_filename_utf8 = ((File_Name *)((GList *)ETFile->FileNameCur)->data)->value_utf8;
1423 gchar *dirname_utf8 = g_path_get_dirname(cur_filename_utf8);
1424 gchar *dirname_key = g_utf8_collate_key (dirname_utf8, -1);
1425
1426 if (strcmp (dirname_utf8, path_utf8) == 0)
1427 {
1428 count++;
1429 }
1430
1431 g_free (dirname_utf8);
1432 g_free (dirname_key);
1433 }
1434
1435 g_free (path_key);
1436
1437 return count;
1438 }
1439