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