Code Cleanup: style and redundant casts
[blender.git] / source / blender / editors / space_file / filelist.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2007 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/space_file/filelist.c
29  *  \ingroup spfile
30  */
31
32
33 /* global includes */
34
35 #include <stdlib.h>
36 #include <math.h>
37 #include <string.h>
38
39 #ifndef WIN32
40 #include <unistd.h>
41 #else
42 #include <io.h>
43 #include <direct.h>
44 #endif   
45 #include "MEM_guardedalloc.h"
46
47 #include "BLI_blenlib.h"
48 #include "BLI_linklist.h"
49 #include "BLI_threads.h"
50 #include "BLI_utildefines.h"
51 #include "BLI_fileops_types.h"
52
53 #ifdef WIN32
54 #  include "BLI_winstuff.h"
55 #endif
56
57 #include "BKE_context.h"
58 #include "BKE_global.h"
59 #include "BKE_library.h"
60 #include "BKE_icons.h"
61 #include "BKE_main.h"
62 #include "BKE_report.h"
63 #include "BLO_readfile.h"
64 #include "BKE_idcode.h"
65
66 #include "DNA_space_types.h"
67
68 #include "ED_fileselect.h"
69 #include "ED_datafiles.h"
70
71 #include "IMB_imbuf.h"
72 #include "IMB_imbuf_types.h"
73 #include "IMB_thumbs.h"
74
75 #include "PIL_time.h"
76
77 #include "WM_api.h"
78 #include "WM_types.h"
79
80 #include "UI_resources.h"
81
82 #include "filelist.h"
83
84 /* max length of library group name within filesel */
85 #define GROUP_MAX 32
86
87 struct FileList;
88
89 typedef struct FileImage {
90         struct FileImage *next, *prev;
91         char path[FILE_MAX];
92         unsigned int flags;
93         int index;
94         short done;
95         ImBuf *img;
96 } FileImage;
97
98 typedef struct ThumbnailJob {
99         ListBase loadimages;
100         short *stop;
101         short *do_update;
102         struct FileList *filelist;
103         ReportList reports;
104 } ThumbnailJob;
105
106 typedef struct FileList {
107         struct direntry *filelist;
108         int *fidx;
109         int numfiles;
110         int numfiltered;
111         char dir[FILE_MAX];
112         short prv_w;
113         short prv_h;
114         short hide_dot;
115         unsigned int filter;
116         char filter_glob[64];
117         short changed;
118
119         struct BlendHandle *libfiledata;
120         short hide_parent;
121
122         void (*readf)(struct FileList *);
123         int (*filterf)(struct direntry *file, const char *dir, unsigned int filter, short hide_dot);
124
125 } FileList;
126
127 typedef struct FolderList {
128         struct FolderList *next, *prev;
129         char *foldername;
130 } FolderList;
131
132 #define SPECIAL_IMG_SIZE 48
133 #define SPECIAL_IMG_ROWS 4
134 #define SPECIAL_IMG_COLS 4
135
136 #define SPECIAL_IMG_FOLDER 0
137 #define SPECIAL_IMG_PARENT 1
138 #define SPECIAL_IMG_REFRESH 2
139 #define SPECIAL_IMG_BLENDFILE 3
140 #define SPECIAL_IMG_SOUNDFILE 4
141 #define SPECIAL_IMG_MOVIEFILE 5
142 #define SPECIAL_IMG_PYTHONFILE 6
143 #define SPECIAL_IMG_TEXTFILE 7
144 #define SPECIAL_IMG_FONTFILE 8
145 #define SPECIAL_IMG_UNKNOWNFILE 9
146 #define SPECIAL_IMG_LOADING 10
147 #define SPECIAL_IMG_BACKUP 11
148 #define SPECIAL_IMG_MAX SPECIAL_IMG_BACKUP + 1
149
150 static ImBuf *gSpecialFileImages[SPECIAL_IMG_MAX];
151
152
153 /* ******************* SORT ******************* */
154
155 static bool compare_is_directory(const struct direntry *entry)
156 {
157         /* for library browse .blend files may be treated as directories, but
158          * for sorting purposes they should be considered regular files */
159         if (S_ISDIR(entry->type))
160                 return !(entry->flags & (BLENDERFILE | BLENDERFILE_BACKUP));
161         
162         return false;
163 }
164
165 static int compare_name(const void *a1, const void *a2)
166 {
167         const struct direntry *entry1 = a1, *entry2 = a2;
168
169         /* type is equal to stat.st_mode */
170
171         if (compare_is_directory(entry1)) {
172                 if (compare_is_directory(entry2) == 0) return (-1);
173         }
174         else {
175                 if (compare_is_directory(entry2)) return (1);
176         }
177         if (S_ISREG(entry1->type)) {
178                 if (S_ISREG(entry2->type) == 0) return (-1);
179         }
180         else {
181                 if (S_ISREG(entry2->type)) return (1);
182         }
183         if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
184         if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
185         
186         /* make sure "." and ".." are always first */
187         if (strcmp(entry1->relname, ".") == 0) return (-1);
188         if (strcmp(entry2->relname, ".") == 0) return (1);
189         if (strcmp(entry1->relname, "..") == 0) return (-1);
190         if (strcmp(entry2->relname, "..") == 0) return (1);
191         
192         return (BLI_natstrcmp(entry1->relname, entry2->relname));
193 }
194
195 static int compare_date(const void *a1, const void *a2) 
196 {
197         const struct direntry *entry1 = a1, *entry2 = a2;
198         
199         /* type is equal to stat.st_mode */
200
201         if (compare_is_directory(entry1)) {
202                 if (compare_is_directory(entry2) == 0) return (-1);
203         }
204         else {
205                 if (compare_is_directory(entry2)) return (1);
206         }
207         if (S_ISREG(entry1->type)) {
208                 if (S_ISREG(entry2->type) == 0) return (-1);
209         }
210         else {
211                 if (S_ISREG(entry2->type)) return (1);
212         }
213         if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
214         if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
215
216         /* make sure "." and ".." are always first */
217         if (strcmp(entry1->relname, ".") == 0) return (-1);
218         if (strcmp(entry2->relname, ".") == 0) return (1);
219         if (strcmp(entry1->relname, "..") == 0) return (-1);
220         if (strcmp(entry2->relname, "..") == 0) return (1);
221         
222         if (entry1->s.st_mtime < entry2->s.st_mtime) return 1;
223         if (entry1->s.st_mtime > entry2->s.st_mtime) return -1;
224         
225         else return BLI_natstrcmp(entry1->relname, entry2->relname);
226 }
227
228 static int compare_size(const void *a1, const void *a2) 
229 {
230         const struct direntry *entry1 = a1, *entry2 = a2;
231
232         /* type is equal to stat.st_mode */
233
234         if (compare_is_directory(entry1)) {
235                 if (compare_is_directory(entry2) == 0) return (-1);
236         }
237         else {
238                 if (compare_is_directory(entry2)) return (1);
239         }
240         if (S_ISREG(entry1->type)) {
241                 if (S_ISREG(entry2->type) == 0) return (-1);
242         }
243         else {
244                 if (S_ISREG(entry2->type)) return (1);
245         }
246         if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
247         if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
248
249         /* make sure "." and ".." are always first */
250         if (strcmp(entry1->relname, ".") == 0) return (-1);
251         if (strcmp(entry2->relname, ".") == 0) return (1);
252         if (strcmp(entry1->relname, "..") == 0) return (-1);
253         if (strcmp(entry2->relname, "..") == 0) return (1);
254         
255         if (entry1->s.st_size < entry2->s.st_size) return 1;
256         if (entry1->s.st_size > entry2->s.st_size) return -1;
257         else return BLI_natstrcmp(entry1->relname, entry2->relname);
258 }
259
260 static int compare_extension(const void *a1, const void *a2)
261 {
262         const struct direntry *entry1 = a1, *entry2 = a2;
263         const char *sufix1, *sufix2;
264         const char *nil = "";
265
266         if (!(sufix1 = strstr(entry1->relname, ".blend.gz")))
267                 sufix1 = strrchr(entry1->relname, '.');
268         if (!(sufix2 = strstr(entry2->relname, ".blend.gz")))
269                 sufix2 = strrchr(entry2->relname, '.');
270         if (!sufix1) sufix1 = nil;
271         if (!sufix2) sufix2 = nil;
272
273         /* type is equal to stat.st_mode */
274
275         if (compare_is_directory(entry1)) {
276                 if (compare_is_directory(entry2) == 0) return (-1);
277         }
278         else {
279                 if (compare_is_directory(entry2)) return (1);
280         }
281         if (S_ISREG(entry1->type)) {
282                 if (S_ISREG(entry2->type) == 0) return (-1);
283         }
284         else {
285                 if (S_ISREG(entry2->type)) return (1);
286         }
287         if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
288         if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
289         
290         /* make sure "." and ".." are always first */
291         if (strcmp(entry1->relname, ".") == 0) return (-1);
292         if (strcmp(entry2->relname, ".") == 0) return (1);
293         if (strcmp(entry1->relname, "..") == 0) return (-1);
294         if (strcmp(entry2->relname, "..") == 0) return (1);
295         
296         return (BLI_strcasecmp(sufix1, sufix2));
297 }
298
299 static int is_hidden_file(const char *filename, short hide_dot)
300 {
301         int is_hidden = 0;
302
303         if (hide_dot) {
304                 if (filename[0] == '.' && filename[1] != '.' && filename[1] != 0) {
305                         is_hidden = 1; /* ignore .file */
306                 }
307                 else if (((filename[0] == '.') && (filename[1] == 0))) {
308                         is_hidden = 1; /* ignore . */
309                 }
310                 else {
311                         int len = strlen(filename);
312                         if ((len > 0) && (filename[len - 1] == '~')) {
313                                 is_hidden = 1;  /* ignore file~ */
314                         }
315                 }
316         }
317         else {
318                 if (((filename[0] == '.') && (filename[1] == 0))) {
319                         is_hidden = 1; /* ignore . */
320                 }
321         }
322         return is_hidden;
323 }
324
325 static int is_filtered_file(struct direntry *file, const char *UNUSED(dir), unsigned int filter, short hide_dot)
326 {
327         int is_filtered = 0;
328         if (filter) {
329                 if (file->flags & filter) {
330                         is_filtered = 1;
331                 }
332                 else if (file->type & S_IFDIR) {
333                         if (filter & FOLDERFILE) {
334                                 is_filtered = 1;
335                         }
336                 }
337         }
338         else {
339                 is_filtered = 1;
340         }
341         return is_filtered && !is_hidden_file(file->relname, hide_dot);
342 }
343
344 static int is_filtered_lib(struct direntry *file, const char *dir, unsigned int filter, short hide_dot)
345 {
346         int is_filtered = 0;
347         char tdir[FILE_MAX], tgroup[GROUP_MAX];
348         if (BLO_is_a_library(dir, tdir, tgroup)) {
349                 is_filtered = !is_hidden_file(file->relname, hide_dot);
350         }
351         else {
352                 is_filtered = is_filtered_file(file, dir, filter, hide_dot);
353         }
354         return is_filtered;
355 }
356
357 static int is_filtered_main(struct direntry *file, const char *UNUSED(dir), unsigned int UNUSED(filter), short hide_dot)
358 {
359         return !is_hidden_file(file->relname, hide_dot);
360 }
361
362 void filelist_filter(FileList *filelist)
363 {
364         int num_filtered = 0;
365         int i, j;
366
367         if (!filelist->filelist)
368                 return;
369
370         /* How many files are left after filter ? */
371         for (i = 0; i < filelist->numfiles; ++i) {
372                 struct direntry *file = &filelist->filelist[i];
373                 if (filelist->filterf(file, filelist->dir, filelist->filter, filelist->hide_dot)) {
374                         num_filtered++;
375                 }
376         }
377         
378         if (filelist->fidx) {
379                 MEM_freeN(filelist->fidx);
380                 filelist->fidx = NULL;
381         }
382         filelist->fidx = (int *)MEM_callocN(num_filtered * sizeof(int), "filteridx");
383         filelist->numfiltered = num_filtered;
384
385         for (i = 0, j = 0; i < filelist->numfiles; ++i) {
386                 struct direntry *file = &filelist->filelist[i];
387                 if (filelist->filterf(file, filelist->dir, filelist->filter, filelist->hide_dot)) {
388                         filelist->fidx[j++] = i;
389                 }
390         }
391 }
392
393 void filelist_init_icons(void)
394 {
395         short x, y, k;
396         ImBuf *bbuf;
397         ImBuf *ibuf;
398
399         BLI_assert(G.background == FALSE);
400
401 #ifdef WITH_HEADLESS
402         bbuf = NULL;
403 #else
404         bbuf = IMB_ibImageFromMemory((unsigned char *)datatoc_prvicons_png, datatoc_prvicons_png_size, IB_rect, NULL, "<splash>");
405 #endif
406         if (bbuf) {
407                 for (y = 0; y < SPECIAL_IMG_ROWS; y++) {
408                         for (x = 0; x < SPECIAL_IMG_COLS; x++) {
409                                 int tile = SPECIAL_IMG_COLS * y + x;
410                                 if (tile < SPECIAL_IMG_MAX) {
411                                         ibuf = IMB_allocImBuf(SPECIAL_IMG_SIZE, SPECIAL_IMG_SIZE, 32, IB_rect);
412                                         for (k = 0; k < SPECIAL_IMG_SIZE; k++) {
413                                                 memcpy(&ibuf->rect[k * SPECIAL_IMG_SIZE], &bbuf->rect[(k + y * SPECIAL_IMG_SIZE) * SPECIAL_IMG_SIZE * SPECIAL_IMG_COLS + x * SPECIAL_IMG_SIZE], SPECIAL_IMG_SIZE * sizeof(int));
414                                         }
415                                         gSpecialFileImages[tile] = ibuf;
416                                 }
417                         }
418                 }
419                 IMB_freeImBuf(bbuf);
420         }
421 }
422
423 void filelist_free_icons(void)
424 {
425         int i;
426
427         BLI_assert(G.background == FALSE);
428
429         for (i = 0; i < SPECIAL_IMG_MAX; ++i) {
430                 IMB_freeImBuf(gSpecialFileImages[i]);
431                 gSpecialFileImages[i] = NULL;
432         }
433 }
434
435 /* -----------------FOLDERLIST (previous/next) -------------- */
436 ListBase *folderlist_new(void)
437 {
438         ListBase *p = MEM_callocN(sizeof(ListBase), "folderlist");
439         return p;
440 }
441
442 void folderlist_popdir(struct ListBase *folderlist, char *dir)
443 {
444         const char *prev_dir;
445         struct FolderList *folder;
446         folder = folderlist->last;
447
448         if (folder) {
449                 /* remove the current directory */
450                 MEM_freeN(folder->foldername);
451                 BLI_freelinkN(folderlist, folder);
452
453                 folder = folderlist->last;
454                 if (folder) {
455                         prev_dir = folder->foldername;
456                         BLI_strncpy(dir, prev_dir, FILE_MAXDIR);
457                 }
458         }
459         /* delete the folder next or use setdir directly before PREVIOUS OP */
460 }
461
462 void folderlist_pushdir(ListBase *folderlist, const char *dir)
463 {
464         struct FolderList *folder, *previous_folder;
465         previous_folder = folderlist->last;
466
467         /* check if already exists */
468         if (previous_folder && previous_folder->foldername) {
469                 if (BLI_path_cmp(previous_folder->foldername, dir) == 0) {
470                         return;
471                 }
472         }
473
474         /* create next folder element */
475         folder = (FolderList *)MEM_mallocN(sizeof(FolderList), "FolderList");
476         folder->foldername = BLI_strdup(dir);
477
478         /* add it to the end of the list */
479         BLI_addtail(folderlist, folder);
480 }
481
482 const char *folderlist_peeklastdir(ListBase *folderlist)
483 {
484         struct FolderList *folder;
485
486         if (!folderlist->last)
487                 return NULL;
488
489         folder = folderlist->last;
490         return folder->foldername;
491 }
492
493 int folderlist_clear_next(struct SpaceFile *sfile)
494 {
495         struct FolderList *folder;
496
497         /* if there is no folder_next there is nothing we can clear */
498         if (!sfile->folders_next)
499                 return 0;
500
501         /* if previous_folder, next_folder or refresh_folder operators are executed it doesn't clear folder_next */
502         folder = sfile->folders_prev->last;
503         if ((!folder) || (BLI_path_cmp(folder->foldername, sfile->params->dir) == 0))
504                 return 0;
505
506         /* eventually clear flist->folders_next */
507         return 1;
508 }
509
510 /* not listbase itself */
511 void folderlist_free(ListBase *folderlist)
512 {
513         if (folderlist) {
514                 FolderList *folder;
515                 for (folder = folderlist->first; folder; folder = folder->next)
516                         MEM_freeN(folder->foldername);
517                 BLI_freelistN(folderlist);
518         }
519 }
520
521 ListBase *folderlist_duplicate(ListBase *folderlist)
522 {
523         
524         if (folderlist) {
525                 ListBase *folderlistn = MEM_callocN(sizeof(ListBase), "copy folderlist");
526                 FolderList *folder;
527                 
528                 BLI_duplicatelist(folderlistn, folderlist);
529                 
530                 for (folder = folderlistn->first; folder; folder = folder->next) {
531                         folder->foldername = MEM_dupallocN(folder->foldername);
532                 }
533                 return folderlistn;
534         }
535         return NULL;
536 }
537
538
539 static void filelist_read_main(struct FileList *filelist);
540 static void filelist_read_library(struct FileList *filelist);
541 static void filelist_read_dir(struct FileList *filelist);
542
543 /* ------------------FILELIST------------------------ */
544 FileList *filelist_new(short type)
545 {
546         FileList *p = MEM_callocN(sizeof(FileList), "filelist");
547         switch (type) {
548                 case FILE_MAIN:
549                         p->readf = filelist_read_main;
550                         p->filterf = is_filtered_main;
551                         break;
552                 case FILE_LOADLIB:
553                         p->readf = filelist_read_library;
554                         p->filterf = is_filtered_lib;
555                         break;
556                 default:
557                         p->readf = filelist_read_dir;
558                         p->filterf = is_filtered_file;
559                         break;
560
561         }
562         return p;
563 }
564
565
566 void filelist_free(struct FileList *filelist)
567 {
568         if (!filelist) {
569                 printf("Attempting to delete empty filelist.\n");
570                 return;
571         }
572         
573         if (filelist->fidx) {
574                 MEM_freeN(filelist->fidx);
575                 filelist->fidx = NULL;
576         }
577
578         BLI_free_filelist(filelist->filelist, filelist->numfiles);
579         filelist->numfiles = 0;
580         filelist->filelist = NULL;
581         filelist->filter = 0;
582         filelist->filter_glob[0] = '\0';
583         filelist->numfiltered = 0;
584         filelist->hide_dot = 0;
585 }
586
587 void filelist_freelib(struct FileList *filelist)
588 {
589         if (filelist->libfiledata)
590                 BLO_blendhandle_close(filelist->libfiledata);
591         filelist->libfiledata = NULL;
592 }
593
594 BlendHandle *filelist_lib(struct FileList *filelist)
595 {
596         return filelist->libfiledata;
597 }
598
599 int filelist_numfiles(struct FileList *filelist)
600 {
601         return filelist->numfiltered;
602 }
603
604 const char *filelist_dir(struct FileList *filelist)
605 {
606         return filelist->dir;
607 }
608
609 void filelist_setdir(struct FileList *filelist, const char *dir)
610 {
611         BLI_strncpy(filelist->dir, dir, sizeof(filelist->dir));
612 }
613
614 void filelist_imgsize(struct FileList *filelist, short w, short h)
615 {
616         filelist->prv_w = w;
617         filelist->prv_h = h;
618 }
619
620 short filelist_changed(struct FileList *filelist)
621 {
622         return filelist->changed;
623 }
624
625 ImBuf *filelist_getimage(struct FileList *filelist, int index)
626 {
627         ImBuf *ibuf = NULL;
628         int fidx = 0;
629
630         BLI_assert(G.background == FALSE);
631
632         if ((index < 0) || (index >= filelist->numfiltered)) {
633                 return NULL;
634         }
635         fidx = filelist->fidx[index];
636         ibuf = filelist->filelist[fidx].image;
637
638         return ibuf;
639 }
640
641 ImBuf *filelist_geticon(struct FileList *filelist, int index)
642 {
643         ImBuf *ibuf = NULL;
644         struct direntry *file = NULL;
645         int fidx = 0;
646
647         BLI_assert(G.background == FALSE);
648
649         if ((index < 0) || (index >= filelist->numfiltered)) {
650                 return NULL;
651         }
652         fidx = filelist->fidx[index];
653         file = &filelist->filelist[fidx];
654         if (file->type & S_IFDIR) {
655                 if (strcmp(filelist->filelist[fidx].relname, "..") == 0) {
656                         ibuf = gSpecialFileImages[SPECIAL_IMG_PARENT];
657                 }
658                 else if (strcmp(filelist->filelist[fidx].relname, ".") == 0) {
659                         ibuf = gSpecialFileImages[SPECIAL_IMG_REFRESH];
660                 }
661                 else {
662                         ibuf = gSpecialFileImages[SPECIAL_IMG_FOLDER];
663                 }
664         }
665         else {
666                 ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE];
667         }
668
669         if (file->flags & BLENDERFILE) {
670                 ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE];
671         }
672         else if ((file->flags & MOVIEFILE) || (file->flags & MOVIEFILE_ICON)) {
673                 ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE];
674         }
675         else if (file->flags & SOUNDFILE) {
676                 ibuf = gSpecialFileImages[SPECIAL_IMG_SOUNDFILE];
677         }
678         else if (file->flags & PYSCRIPTFILE) {
679                 ibuf = gSpecialFileImages[SPECIAL_IMG_PYTHONFILE];
680         }
681         else if (file->flags & FTFONTFILE) {
682                 ibuf = gSpecialFileImages[SPECIAL_IMG_FONTFILE];
683         }
684         else if (file->flags & TEXTFILE) {
685                 ibuf = gSpecialFileImages[SPECIAL_IMG_TEXTFILE];
686         }
687         else if (file->flags & IMAGEFILE) {
688                 ibuf = gSpecialFileImages[SPECIAL_IMG_LOADING];
689         }
690         else if (file->flags & BLENDERFILE_BACKUP) {
691                 ibuf = gSpecialFileImages[SPECIAL_IMG_BACKUP];
692         }
693
694         return ibuf;
695 }
696
697 struct direntry *filelist_file(struct FileList *filelist, int index)
698 {
699         int fidx = 0;
700         
701         if ((index < 0) || (index >= filelist->numfiltered)) {
702                 return NULL;
703         }
704         fidx = filelist->fidx[index];
705
706         return &filelist->filelist[fidx];
707 }
708
709 int filelist_find(struct FileList *filelist, const char *filename)
710 {
711         int index = -1;
712         int i;
713         int fidx = -1;
714         
715         if (!filelist->fidx) 
716                 return fidx;
717
718         
719         for (i = 0; i < filelist->numfiles; ++i) {
720                 if (strcmp(filelist->filelist[i].relname, filename) == 0) {  /* not dealing with user input so don't need BLI_path_cmp */
721                         index = i;
722                         break;
723                 }
724         }
725
726         for (i = 0; i < filelist->numfiltered; ++i) {
727                 if (filelist->fidx[i] == index) {
728                         fidx = i;
729                         break;
730                 }
731         }
732         return fidx;
733 }
734
735 void filelist_hidedot(struct FileList *filelist, short hide)
736 {
737         filelist->hide_dot = hide;
738 }
739
740 void filelist_setfilter(struct FileList *filelist, unsigned int filter)
741 {
742         filelist->filter = filter;
743 }
744
745 void filelist_setfilter_types(struct FileList *filelist, const char *filter_glob)
746 {
747         BLI_strncpy(filelist->filter_glob, filter_glob, sizeof(filelist->filter_glob));
748 }
749
750 /* would recognize .blend as well */
751 static int file_is_blend_backup(const char *str)
752 {
753         short a, b;
754         int retval = 0;
755         
756         a = strlen(str);
757         b = 7;
758         
759         if (a == 0 || b >= a) {
760                 /* pass */
761         }
762         else {
763                 char *loc;
764                 
765                 if (a > b + 1)
766                         b++;
767                 
768                 /* allow .blend1 .blend2 .blend32 */
769                 loc = BLI_strcasestr(str + a - b, ".blend");
770                 
771                 if (loc)
772                         retval = 1;
773         }
774         
775         return (retval);
776 }
777
778 static int path_extension_type(const char *path)
779 {
780         if (BLO_has_bfile_extension(path)) {
781                 return BLENDERFILE;
782         }
783         else if (file_is_blend_backup(path)) {
784                 return BLENDERFILE_BACKUP;
785         }
786         else if (BLI_testextensie(path, ".app")) {
787                 return APPLICATIONBUNDLE;
788         }
789         else if (BLI_testextensie(path, ".py")) {
790                 return PYSCRIPTFILE;
791         }
792         else if (BLI_testextensie(path, ".txt")  ||
793                  BLI_testextensie(path, ".glsl") ||
794                  BLI_testextensie(path, ".osl")  ||
795                  BLI_testextensie(path, ".data"))
796         {
797                 return TEXTFILE;
798         }
799         else if (BLI_testextensie(path, ".ttf") ||
800                  BLI_testextensie(path, ".ttc") ||
801                  BLI_testextensie(path, ".pfb") ||
802                  BLI_testextensie(path, ".otf") ||
803                  BLI_testextensie(path, ".otc"))
804         {
805                 return FTFONTFILE;
806         }
807         else if (BLI_testextensie(path, ".btx")) {
808                 return BTXFILE;
809         }
810         else if (BLI_testextensie(path, ".dae")) {
811                 return COLLADAFILE;
812         }
813         else if (BLI_testextensie_array(path, imb_ext_image) ||
814                  (G.have_quicktime && BLI_testextensie_array(path, imb_ext_image_qt)))
815         {
816                 return IMAGEFILE;
817         }
818         else if (BLI_testextensie(path, ".ogg")) {
819                 if (IMB_isanim(path)) {
820                         return MOVIEFILE;
821                 }
822                 else {
823                         return SOUNDFILE;
824                 }
825         }
826         else if (BLI_testextensie_array(path, imb_ext_movie)) {
827                 return MOVIEFILE;
828         }
829         else if (BLI_testextensie_array(path, imb_ext_audio)) {
830                 return SOUNDFILE;
831         }
832         return 0;
833 }
834
835 static int file_extension_type(const char *dir, const char *relname)
836 {
837         char path[FILE_MAX];
838         BLI_join_dirfile(path, sizeof(path), dir, relname);
839         return path_extension_type(path);
840 }
841
842 int ED_file_extension_icon(const char *path)
843 {
844         int type = path_extension_type(path);
845         
846         if (type == BLENDERFILE)
847                 return ICON_FILE_BLEND;
848         else if (type == BLENDERFILE_BACKUP)
849                 return ICON_FILE_BACKUP;
850         else if (type == IMAGEFILE)
851                 return ICON_FILE_IMAGE;
852         else if (type == MOVIEFILE)
853                 return ICON_FILE_MOVIE;
854         else if (type == PYSCRIPTFILE)
855                 return ICON_FILE_SCRIPT;
856         else if (type == SOUNDFILE)
857                 return ICON_FILE_SOUND;
858         else if (type == FTFONTFILE)
859                 return ICON_FILE_FONT;
860         else if (type == BTXFILE)
861                 return ICON_FILE_BLANK;
862         else if (type == COLLADAFILE)
863                 return ICON_FILE_BLANK;
864         else if (type == TEXTFILE)
865                 return ICON_FILE_TEXT;
866         
867         return ICON_FILE_BLANK;
868 }
869
870 static void filelist_setfiletypes(struct FileList *filelist)
871 {
872         struct direntry *file;
873         int num;
874         
875         file = filelist->filelist;
876         
877         for (num = 0; num < filelist->numfiles; num++, file++) {
878                 file->type = file->s.st_mode;  /* restore the mess below */
879 #ifndef __APPLE__
880                 /* Don't check extensions for directories, allow in OSX cause bundles have extensions*/
881                 if (file->type & S_IFDIR) {
882                         continue;
883                 }
884 #endif
885                 file->flags = file_extension_type(filelist->dir, file->relname);
886                 
887                 if (filelist->filter_glob[0] &&
888                     BLI_testextensie_glob(file->relname, filelist->filter_glob))
889                 {
890                         file->flags = OPERATORFILE;
891                 }
892                 
893         }
894 }
895
896 static void filelist_read_dir(struct FileList *filelist)
897 {
898         if (!filelist) return;
899
900         filelist->fidx = NULL;
901         filelist->filelist = NULL;
902
903         BLI_cleanup_dir(G.main->name, filelist->dir);
904         filelist->numfiles = BLI_dir_contents(filelist->dir, &(filelist->filelist));
905
906         filelist_setfiletypes(filelist);
907         filelist_filter(filelist);
908 }
909
910 static void filelist_read_main(struct FileList *filelist)
911 {
912         if (!filelist) return;
913         filelist_from_main(filelist);
914 }
915
916 static void filelist_read_library(struct FileList *filelist)
917 {
918         if (!filelist) return;
919         BLI_cleanup_dir(G.main->name, filelist->dir);
920         filelist_from_library(filelist);
921         if (!filelist->libfiledata) {
922                 int num;
923                 struct direntry *file;
924
925                 BLI_make_exist(filelist->dir);
926                 filelist_read_dir(filelist);
927                 file = filelist->filelist;
928                 for (num = 0; num < filelist->numfiles; num++, file++) {
929                         if (BLO_has_bfile_extension(file->relname)) {
930                                 char name[FILE_MAX];
931
932                                 BLI_join_dirfile(name, sizeof(name), filelist->dir, file->relname);
933
934                                 /* prevent current file being used as acceptable dir */
935                                 if (BLI_path_cmp(G.main->name, name) != 0) {
936                                         file->type &= ~S_IFMT;
937                                         file->type |= S_IFDIR;
938                                 }
939                         }
940                 }
941         }
942 }
943
944 void filelist_readdir(struct FileList *filelist)
945 {
946         filelist->readf(filelist);
947 }
948
949 int filelist_empty(struct FileList *filelist)
950 {       
951         return filelist->filelist == NULL;
952 }
953
954 void filelist_parent(struct FileList *filelist)
955 {
956         BLI_parent_dir(filelist->dir);
957         BLI_make_exist(filelist->dir);
958         filelist_readdir(filelist);
959 }
960
961 void filelist_select_file(struct FileList *filelist, int index, FileSelType select, unsigned int flag, FileCheckType check)
962 {
963         struct direntry *file = filelist_file(filelist, index);
964         if (file != NULL) {
965                 int check_ok = 0; 
966                 switch (check) {
967                         case CHECK_DIRS:
968                                 check_ok = S_ISDIR(file->type);
969                                 break;
970                         case CHECK_ALL:
971                                 check_ok = 1;
972                                 break;
973                         case CHECK_FILES:
974                         default:
975                                 check_ok = !S_ISDIR(file->type);
976                                 break;
977                 }
978                 if (check_ok) {
979                         switch (select) {
980                                 case FILE_SEL_REMOVE:
981                                         file->selflag &= ~flag;
982                                         break;
983                                 case FILE_SEL_ADD:
984                                         file->selflag |= flag;
985                                         break;
986                                 case FILE_SEL_TOGGLE:
987                                         file->selflag ^= flag;
988                                         break;
989                         }
990                 }
991         }
992 }
993
994 void filelist_select(struct FileList *filelist, FileSelection *sel, FileSelType select, unsigned int flag, FileCheckType check)
995 {
996         /* select all valid files between first and last indicated */
997         if ((sel->first >= 0) && (sel->first < filelist->numfiltered) && (sel->last >= 0) && (sel->last < filelist->numfiltered)) {
998                 int current_file;
999                 for (current_file = sel->first; current_file <= sel->last; current_file++) {
1000                         filelist_select_file(filelist, current_file, select, flag, check);
1001                 }
1002         }
1003 }
1004
1005 int filelist_is_selected(struct FileList *filelist, int index, FileCheckType check)
1006 {
1007         struct direntry *file = filelist_file(filelist, index);
1008         if (!file) {
1009                 return 0;
1010         }
1011         switch (check) {
1012                 case CHECK_DIRS:
1013                         return S_ISDIR(file->type) && (file->selflag & SELECTED_FILE);
1014                 case CHECK_FILES:
1015                         return S_ISREG(file->type) && (file->selflag & SELECTED_FILE);
1016                 case CHECK_ALL:
1017                 default:
1018                         return (file->selflag & SELECTED_FILE);
1019         }
1020 }
1021
1022 void filelist_sort(struct FileList *filelist, short sort)
1023 {
1024         switch (sort) {
1025                 case FILE_SORT_ALPHA:
1026                         qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_name);
1027                         break;
1028                 case FILE_SORT_TIME:
1029                         qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_date);
1030                         break;
1031                 case FILE_SORT_SIZE:
1032                         qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_size);
1033                         break;
1034                 case FILE_SORT_EXTENSION:
1035                         qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_extension);
1036                         break;
1037         }
1038
1039         filelist_filter(filelist);
1040 }
1041
1042
1043 int filelist_islibrary(struct FileList *filelist, char *dir, char *group)
1044 {
1045         return BLO_is_a_library(filelist->dir, dir, group);
1046 }
1047
1048 static int groupname_to_code(const char *group)
1049 {
1050         char buf[32];
1051         char *lslash;
1052         
1053         BLI_strncpy(buf, group, sizeof(buf));
1054         lslash = (char *)BLI_last_slash(buf);
1055         if (lslash)
1056                 lslash[0] = '\0';
1057
1058         return BKE_idcode_from_name(buf);
1059 }
1060  
1061 void filelist_from_library(struct FileList *filelist)
1062 {
1063         LinkNode *l, *names, *previews;
1064         struct ImBuf *ima;
1065         int ok, i, nprevs, nnames, idcode;
1066         char filename[FILE_MAX];
1067         char dir[FILE_MAX], group[GROUP_MAX];
1068         
1069         /* name test */
1070         ok = filelist_islibrary(filelist, dir, group);
1071         if (!ok) {
1072                 /* free */
1073                 if (filelist->libfiledata) BLO_blendhandle_close(filelist->libfiledata);
1074                 filelist->libfiledata = NULL;
1075                 return;
1076         }
1077         
1078         BLI_strncpy(filename, G.main->name, sizeof(filename));
1079
1080         /* there we go */
1081         /* for the time being only read filedata when libfiledata==0 */
1082         if (filelist->libfiledata == NULL) {
1083                 filelist->libfiledata = BLO_blendhandle_from_file(dir, NULL);
1084                 if (filelist->libfiledata == NULL) return;
1085         }
1086         
1087         idcode = groupname_to_code(group);
1088
1089         /* memory for strings is passed into filelist[i].relname
1090          * and freed in freefilelist */
1091         if (idcode) {
1092                 previews = BLO_blendhandle_get_previews(filelist->libfiledata, idcode, &nprevs);
1093                 names = BLO_blendhandle_get_datablock_names(filelist->libfiledata, idcode, &nnames);
1094                 /* ugh, no rewind, need to reopen */
1095                 BLO_blendhandle_close(filelist->libfiledata);
1096                 filelist->libfiledata = BLO_blendhandle_from_file(dir, NULL);
1097                 
1098         }
1099         else {
1100                 previews = NULL;
1101                 nprevs = 0;
1102                 names = BLO_blendhandle_get_linkable_groups(filelist->libfiledata);
1103                 nnames = BLI_linklist_length(names);
1104         }
1105
1106         filelist->numfiles = nnames + 1;
1107         filelist->filelist = malloc(filelist->numfiles * sizeof(*filelist->filelist));
1108         memset(filelist->filelist, 0, filelist->numfiles * sizeof(*filelist->filelist));
1109
1110         filelist->filelist[0].relname = BLI_strdup("..");
1111         filelist->filelist[0].type |= S_IFDIR;
1112                 
1113         for (i = 0, l = names; i < nnames; i++, l = l->next) {
1114                 char *blockname = l->link;
1115
1116                 filelist->filelist[i + 1].relname = BLI_strdup(blockname);
1117                 if (idcode) {
1118                         filelist->filelist[i + 1].type |= S_IFREG;
1119                 }
1120                 else {
1121                         filelist->filelist[i + 1].type |= S_IFDIR;
1122                 }
1123         }
1124         
1125         if (previews && (nnames != nprevs)) {
1126                 printf("filelist_from_library: error, found %d items, %d previews\n", nnames, nprevs);
1127         }
1128         else if (previews) {
1129                 for (i = 0, l = previews; i < nnames; i++, l = l->next) {
1130                         PreviewImage *img = l->link;
1131                         
1132                         if (img) {
1133                                 unsigned int w = img->w[ICON_SIZE_PREVIEW];
1134                                 unsigned int h = img->h[ICON_SIZE_PREVIEW];
1135                                 unsigned int *rect = img->rect[ICON_SIZE_PREVIEW];
1136
1137                                 /* first allocate imbuf for copying preview into it */
1138                                 if (w > 0 && h > 0 && rect) {
1139                                         ima = IMB_allocImBuf(w, h, 32, IB_rect);
1140                                         memcpy(ima->rect, rect, w * h * sizeof(unsigned int));
1141                                         filelist->filelist[i + 1].image = ima;
1142                                         filelist->filelist[i + 1].flags = IMAGEFILE;
1143                                 }
1144                         }
1145                 }
1146         }
1147
1148         BLI_linklist_free(names, free);
1149         if (previews) BLI_linklist_free(previews, BKE_previewimg_freefunc);
1150
1151         filelist_sort(filelist, FILE_SORT_ALPHA);
1152
1153         BLI_strncpy(G.main->name, filename, sizeof(filename));  /* prevent G.main->name to change */
1154
1155         filelist->filter = 0;
1156         filelist_filter(filelist);
1157 }
1158
1159 void filelist_hideparent(struct FileList *filelist, short hide)
1160 {
1161         filelist->hide_parent = hide;
1162 }
1163
1164 void filelist_from_main(struct FileList *filelist)
1165 {
1166         ID *id;
1167         struct direntry *files, *firstlib = NULL;
1168         ListBase *lb;
1169         int a, fake, idcode, ok, totlib, totbl;
1170         
1171         // filelist->type = FILE_MAIN; // XXXXX TODO: add modes to filebrowser
1172
1173         if (filelist->dir[0] == '/') filelist->dir[0] = 0;
1174         
1175         if (filelist->dir[0]) {
1176                 idcode = groupname_to_code(filelist->dir);
1177                 if (idcode == 0) filelist->dir[0] = 0;
1178         }
1179         
1180         if (filelist->dir[0] == 0) {
1181                 
1182                 /* make directories */
1183 #ifdef WITH_FREESTYLE
1184                 filelist->numfiles = 25;
1185 #else
1186                 filelist->numfiles = 24;
1187 #endif
1188                 filelist->filelist = (struct direntry *)malloc(filelist->numfiles * sizeof(struct direntry));
1189                 
1190                 for (a = 0; a < filelist->numfiles; a++) {
1191                         memset(&(filelist->filelist[a]), 0, sizeof(struct direntry));
1192                         filelist->filelist[a].type |= S_IFDIR;
1193                 }
1194                 
1195                 filelist->filelist[0].relname = BLI_strdup("..");
1196                 filelist->filelist[2].relname = BLI_strdup("Scene");
1197                 filelist->filelist[3].relname = BLI_strdup("Object");
1198                 filelist->filelist[4].relname = BLI_strdup("Mesh");
1199                 filelist->filelist[5].relname = BLI_strdup("Curve");
1200                 filelist->filelist[6].relname = BLI_strdup("Metaball");
1201                 filelist->filelist[7].relname = BLI_strdup("Material");
1202                 filelist->filelist[8].relname = BLI_strdup("Texture");
1203                 filelist->filelist[9].relname = BLI_strdup("Image");
1204                 filelist->filelist[10].relname = BLI_strdup("Ika");
1205                 filelist->filelist[11].relname = BLI_strdup("Wave");
1206                 filelist->filelist[12].relname = BLI_strdup("Lattice");
1207                 filelist->filelist[13].relname = BLI_strdup("Lamp");
1208                 filelist->filelist[14].relname = BLI_strdup("Camera");
1209                 filelist->filelist[15].relname = BLI_strdup("Ipo");
1210                 filelist->filelist[16].relname = BLI_strdup("World");
1211                 filelist->filelist[17].relname = BLI_strdup("Screen");
1212                 filelist->filelist[18].relname = BLI_strdup("VFont");
1213                 filelist->filelist[19].relname = BLI_strdup("Text");
1214                 filelist->filelist[20].relname = BLI_strdup("Armature");
1215                 filelist->filelist[21].relname = BLI_strdup("Action");
1216                 filelist->filelist[22].relname = BLI_strdup("NodeTree");
1217                 filelist->filelist[23].relname = BLI_strdup("Speaker");
1218 #ifdef WITH_FREESTYLE
1219                 filelist->filelist[24].relname = BLI_strdup("FreestyleLineStyle");
1220 #endif
1221                 filelist_sort(filelist, FILE_SORT_ALPHA);
1222         }
1223         else {
1224
1225                 /* make files */
1226                 idcode = groupname_to_code(filelist->dir);
1227                 
1228                 lb = which_libbase(G.main, idcode);
1229                 if (lb == NULL) return;
1230                 
1231                 id = lb->first;
1232                 filelist->numfiles = 0;
1233                 while (id) {
1234                         if (!filelist->hide_dot || id->name[2] != '.') {
1235                                 filelist->numfiles++;
1236                         }
1237                         
1238                         id = id->next;
1239                 }
1240                 
1241                 /* XXXXX TODO: if databrowse F4 or append/link filelist->hide_parent has to be set */
1242                 if (!filelist->hide_parent) filelist->numfiles += 1;
1243                 filelist->filelist = filelist->numfiles > 0 ? (struct direntry *)malloc(filelist->numfiles * sizeof(struct direntry)) : NULL;
1244
1245                 files = filelist->filelist;
1246                 
1247                 if (!filelist->hide_parent) {
1248                         memset(&(filelist->filelist[0]), 0, sizeof(struct direntry));
1249                         filelist->filelist[0].relname = BLI_strdup("..");
1250                         filelist->filelist[0].type |= S_IFDIR;
1251                 
1252                         files++;
1253                 }
1254                 
1255                 id = lb->first;
1256                 totlib = totbl = 0;
1257                 
1258                 while (id) {
1259                         ok = 1;
1260                         if (ok) {
1261                                 if (!filelist->hide_dot || id->name[2] != '.') {
1262                                         memset(files, 0, sizeof(struct direntry));
1263                                         if (id->lib == NULL) {
1264                                                 files->relname = BLI_strdup(id->name + 2);
1265                                         }
1266                                         else {
1267                                                 files->relname = MEM_mallocN(FILE_MAX + (MAX_ID_NAME - 2),     "filename for lib");
1268                                                 BLI_snprintf(files->relname, FILE_MAX + (MAX_ID_NAME - 2) + 3, "%s | %s", id->lib->name, id->name + 2);
1269                                         }
1270                                         files->type |= S_IFREG;
1271 #if 0               /* XXXXX TODO show the selection status of the objects */
1272                                         if (!filelist->has_func) { /* F4 DATA BROWSE */
1273                                                 if (idcode == ID_OB) {
1274                                                         if ( ((Object *)id)->flag & SELECT) files->selflag |= SELECTED_FILE;
1275                                                 }
1276                                                 else if (idcode == ID_SCE) {
1277                                                         if ( ((Scene *)id)->r.scemode & R_BG_RENDER) files->selflag |= SELECTED_FILE;
1278                                                 }
1279                                         }
1280 #endif
1281                                         files->nr = totbl + 1;
1282                                         files->poin = id;
1283                                         fake = id->flag & LIB_FAKEUSER;
1284                                         if (idcode == ID_MA || idcode == ID_TE || idcode == ID_LA || idcode == ID_WO || idcode == ID_IM) {
1285                                                 files->flags |= IMAGEFILE;
1286                                         }
1287                                         if      (id->lib && fake) BLI_snprintf(files->extra, sizeof(files->extra), "LF %d",    id->us);
1288                                         else if (id->lib)         BLI_snprintf(files->extra, sizeof(files->extra), "L    %d",  id->us);
1289                                         else if (fake)            BLI_snprintf(files->extra, sizeof(files->extra), "F    %d",  id->us);
1290                                         else                      BLI_snprintf(files->extra, sizeof(files->extra), "      %d", id->us);
1291                                         
1292                                         if (id->lib) {
1293                                                 if (totlib == 0) firstlib = files;
1294                                                 totlib++;
1295                                         }
1296                                         
1297                                         files++;
1298                                 }
1299                                 totbl++;
1300                         }
1301                         
1302                         id = id->next;
1303                 }
1304                 
1305                 /* only qsort of library blocks */
1306                 if (totlib > 1) {
1307                         qsort(firstlib, totlib, sizeof(struct direntry), compare_name);
1308                 }
1309         }
1310         filelist->filter = 0;
1311         filelist_filter(filelist);
1312 }
1313
1314 static void thumbnail_joblist_free(ThumbnailJob *tj)
1315 {
1316         FileImage *limg = tj->loadimages.first;
1317         
1318         /* free the images not yet copied to the filelist -> these will get freed with the filelist */
1319         for (; limg; limg = limg->next) {
1320                 if ((limg->img) && (!limg->done)) {
1321                         IMB_freeImBuf(limg->img);
1322                 }
1323         }
1324         BLI_freelistN(&tj->loadimages);
1325 }
1326
1327 static void thumbnails_startjob(void *tjv, short *stop, short *do_update, float *UNUSED(progress))
1328 {
1329         ThumbnailJob *tj = tjv;
1330         FileImage *limg = tj->loadimages.first;
1331
1332         tj->stop = stop;
1333         tj->do_update = do_update;
1334
1335         while ((*stop == 0) && (limg)) {
1336                 if (limg->flags & IMAGEFILE) {
1337                         limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_IMAGE);
1338                 }
1339                 else if (limg->flags & (BLENDERFILE | BLENDERFILE_BACKUP)) {
1340                         limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_BLEND);
1341                 }
1342                 else if (limg->flags & MOVIEFILE) {
1343                         limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_MOVIE);
1344                         if (!limg->img) {
1345                                 /* remember that file can't be loaded via IMB_open_anim */
1346                                 limg->flags &= ~MOVIEFILE;
1347                                 limg->flags |= MOVIEFILE_ICON;
1348                         }
1349                 }
1350                 *do_update = TRUE;
1351                 PIL_sleep_ms(10);
1352                 limg = limg->next;
1353         }
1354 }
1355
1356 static void thumbnails_update(void *tjv)
1357 {
1358         ThumbnailJob *tj = tjv;
1359
1360         if (tj->filelist && tj->filelist->filelist) {
1361                 FileImage *limg = tj->loadimages.first;
1362                 while (limg) {
1363                         if (!limg->done && limg->img) {
1364                                 tj->filelist->filelist[limg->index].image = limg->img;
1365                                 /* update flag for movie files where thumbnail can't be created */
1366                                 if (limg->flags & MOVIEFILE_ICON) {
1367                                         tj->filelist->filelist[limg->index].flags &= ~MOVIEFILE;
1368                                         tj->filelist->filelist[limg->index].flags |= MOVIEFILE_ICON;
1369                                 }
1370                                 limg->done = TRUE;
1371                         }
1372                         limg = limg->next;
1373                 }
1374         }
1375 }
1376
1377 static void thumbnails_free(void *tjv)
1378 {
1379         ThumbnailJob *tj = tjv;
1380         thumbnail_joblist_free(tj);
1381         MEM_freeN(tj);
1382 }
1383
1384
1385 void thumbnails_start(FileList *filelist, const bContext *C)
1386 {
1387         wmJob *wm_job;
1388         ThumbnailJob *tj;
1389         int idx;
1390         
1391         /* prepare job data */
1392         tj = MEM_callocN(sizeof(ThumbnailJob), "thumbnails\n");
1393         tj->filelist = filelist;
1394         for (idx = 0; idx < filelist->numfiles; idx++) {
1395                 if (!filelist->filelist[idx].image) {
1396                         if ((filelist->filelist[idx].flags & (IMAGEFILE | MOVIEFILE | BLENDERFILE | BLENDERFILE_BACKUP))) {
1397                                 FileImage *limg = MEM_callocN(sizeof(FileImage), "loadimage");
1398                                 BLI_strncpy(limg->path, filelist->filelist[idx].path, FILE_MAX);
1399                                 limg->index = idx;
1400                                 limg->flags = filelist->filelist[idx].flags;
1401                                 BLI_addtail(&tj->loadimages, limg);
1402                         }
1403                 }
1404         }
1405
1406         BKE_reports_init(&tj->reports, RPT_PRINT);
1407
1408         /* setup job */
1409         wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), filelist, "Thumbnails",
1410                              0, WM_JOB_TYPE_FILESEL_THUMBNAIL);
1411         WM_jobs_customdata_set(wm_job, tj, thumbnails_free);
1412         WM_jobs_timer(wm_job, 0.5, NC_WINDOW, NC_WINDOW);
1413         WM_jobs_callbacks(wm_job, thumbnails_startjob, NULL, thumbnails_update, NULL);
1414
1415         /* start the job */
1416         WM_jobs_start(CTX_wm_manager(C), wm_job);
1417 }
1418
1419 void thumbnails_stop(wmWindowManager *wm, FileList *filelist)
1420 {
1421         WM_jobs_kill(wm, filelist, NULL);
1422 }
1423
1424 int thumbnails_running(wmWindowManager *wm, FileList *filelist)
1425 {
1426         return WM_jobs_test(wm, filelist, WM_JOB_TYPE_FILESEL_THUMBNAIL);
1427 }