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