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