2.5 filebrowser
[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_remlink(&filelist->loadimages, oimg);
596                         BLI_remove_thread(&filelist->threads, oimg);
597                         limg = oimg->next;
598                         MEM_freeN(oimg);
599                         refresh = 1;
600                 } else {
601                         limg= limg->next;
602                 }
603         }
604         filelist->changed=refresh;
605 }
606
607 void filelist_loadimage(struct FileList* filelist, int index)
608 {
609         ImBuf *imb = NULL;
610         int imgwidth = filelist->prv_w;
611         int imgheight = filelist->prv_h;
612         short ex, ey, dx, dy;
613         float scaledx, scaledy;
614         int fidx = 0;
615         
616         if ( (index < 0) || (index >= filelist->numfiltered) ) {
617                 return;
618         }
619         fidx = filelist->fidx[index];
620
621         if (!filelist->filelist[fidx].image)
622         {
623
624                 if ( (filelist->filelist[fidx].flags & IMAGEFILE) || (filelist->filelist[fidx].flags & MOVIEFILE) ) {                           
625                         imb = IMB_thumb_read(filelist->dir, filelist->filelist[fidx].relname, THB_NORMAL);
626                 } 
627                 if (imb) {
628                         if (imb->x > imb->y) {
629                                 scaledx = (float)imgwidth;
630                                 scaledy =  ( (float)imb->y/(float)imb->x )*imgwidth;
631                         }
632                         else {
633                                 scaledy = (float)imgheight;
634                                 scaledx =  ( (float)imb->x/(float)imb->y )*imgheight;
635                         }
636                         ex = (short)scaledx;
637                         ey = (short)scaledy;
638                         
639                         dx = imgwidth - ex;
640                         dy = imgheight - ey;
641                         
642                         // IMB_scaleImBuf(imb, ex, ey);
643                         filelist->filelist[fidx].image = imb;
644                 } else {
645                         /* prevent loading image twice */
646                         FileImage* limg = filelist->loadimages.first;
647                         short found= 0;
648                         while(limg) {
649                                 if (limg->index == fidx) {
650                                         found= 1;
651                                         break;
652                                 }
653                                 limg= limg->next;
654                         }
655                         if (!found) {
656                                 FileImage* limg = MEM_callocN(sizeof(struct FileImage), "loadimage");
657                                 limg->index= fidx;
658                                 limg->lock= 0;
659                                 limg->filelist= filelist;
660                                 BLI_addtail(&filelist->loadimages, limg);
661                         }
662                 }               
663         }
664 }
665
666 struct ImBuf * filelist_getimage(struct FileList* filelist, int index)
667 {
668         ImBuf* ibuf = NULL;
669         int fidx = 0;   
670         if ( (index < 0) || (index >= filelist->numfiltered) ) {
671                 return NULL;
672         }
673         fidx = filelist->fidx[index];
674         ibuf = filelist->filelist[fidx].image;
675
676         return ibuf;
677 }
678
679 struct ImBuf * filelist_geticon(struct FileList* filelist, int index)
680 {
681         ImBuf* ibuf= NULL;
682         struct direntry *file= NULL;
683         int fidx = 0;   
684         if ( (index < 0) || (index >= filelist->numfiltered) ) {
685                 return NULL;
686         }
687         fidx = filelist->fidx[index];
688         file = &filelist->filelist[fidx];
689         if (file->type & S_IFDIR) {
690                         if ( strcmp(filelist->filelist[fidx].relname, "..") == 0) {
691                                 ibuf = gSpecialFileImages[SPECIAL_IMG_PARENT];
692                         } else if  ( strcmp(filelist->filelist[fidx].relname, ".") == 0) {
693                                 ibuf = gSpecialFileImages[SPECIAL_IMG_REFRESH];
694                         } else {
695                 ibuf = gSpecialFileImages[SPECIAL_IMG_FOLDER];
696                         }
697         } else {
698                 ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE];
699         }
700
701         if (file->flags & BLENDERFILE) {
702                 ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE];
703         } else if ( (file->flags & MOVIEFILE) || (file->flags & MOVIEFILE_ICON) ) {
704                 ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE];
705         } else if (file->flags & SOUNDFILE) {
706                 ibuf = gSpecialFileImages[SPECIAL_IMG_SOUNDFILE];
707         } else if (file->flags & PYSCRIPTFILE) {
708                 ibuf = gSpecialFileImages[SPECIAL_IMG_PYTHONFILE];
709         } else if (file->flags & FTFONTFILE) {
710                 ibuf = gSpecialFileImages[SPECIAL_IMG_FONTFILE];
711         } else if (file->flags & TEXTFILE) {
712                 ibuf = gSpecialFileImages[SPECIAL_IMG_TEXTFILE];
713         } else if (file->flags & IMAGEFILE) {
714                 ibuf = gSpecialFileImages[SPECIAL_IMG_LOADING];
715         }
716
717         return ibuf;
718 }
719
720 struct direntry * filelist_file(struct FileList* filelist, int index)
721 {
722         int fidx = 0;
723         
724         if ( (index < 0) || (index >= filelist->numfiltered) ) {
725                 return NULL;
726         }
727         fidx = filelist->fidx[index];
728
729         return &filelist->filelist[fidx];
730 }
731
732 int filelist_find(struct FileList* filelist, char *file)
733 {
734         int index = -1;
735         int i;
736         int fidx = -1;
737         
738         if (!filelist->fidx) 
739                 return fidx;
740
741         
742         for (i = 0; i < filelist->numfiles; ++i) {
743                 if ( strcmp(filelist->filelist[i].relname, file) == 0) {
744                         index = i;
745                         break;
746                 }
747         }
748
749         for (i = 0; i < filelist->numfiltered; ++i) {
750                 if (filelist->fidx[i] == index) {
751                         fidx = i;
752                         break;
753                 }
754         }
755         return fidx;
756 }
757
758 void filelist_hidedot(struct FileList* filelist, short hide)
759 {
760         filelist->hide_dot = hide;
761 }
762
763 void filelist_setfilter(struct FileList* filelist, unsigned int filter)
764 {
765         filelist->filter = filter;
766 }
767
768 static void filelist_read_dir(struct FileList* filelist)
769 {
770         char wdir[FILE_MAX];
771         if (!filelist) return;
772
773         filelist->fidx = 0;
774         filelist->filelist = 0;
775
776         BLI_getwdN(wdir);        
777
778         BLI_cleanup_dir(G.sce, filelist->dir);
779         BLI_hide_dot_files(filelist->hide_dot);
780         filelist->numfiles = BLI_getdir(filelist->dir, &(filelist->filelist));
781
782         chdir(wdir);
783         filelist_setfiletypes(filelist, G.have_quicktime);
784         filelist_filter(filelist);
785
786         if (!filelist->threads.first) {
787                 BLI_init_threads(&filelist->threads, exec_loadimages, 2);
788         }
789 }
790
791 static void filelist_read_main(struct FileList* filelist)
792 {
793         if (!filelist) return;
794         filelist_from_main(filelist);
795 }
796
797 static void filelist_read_library(struct FileList* filelist)
798 {
799         if (!filelist) return;
800         BLI_cleanup_dir(G.sce, filelist->dir);
801         filelist_from_library(filelist);
802         if(!filelist->libfiledata) {
803                 int num;
804                 struct direntry *file;
805                 filelist_read_dir(filelist);
806                 file = filelist->filelist;
807                 for(num=0; num<filelist->numfiles; num++, file++) {
808                         if(BLO_has_bfile_extension(file->relname)) {
809                                 char name[FILE_MAXDIR+FILE_MAXFILE];
810                         
811                                 BLI_strncpy(name, filelist->dir, sizeof(name));
812                                 strcat(name, file->relname);
813                                 
814                                 /* prevent current file being used as acceptable dir */
815                                 if (BLI_streq(G.main->name, name)==0) {
816                                         file->type &= ~S_IFMT;
817                                         file->type |= S_IFDIR;
818                                 }
819                         }
820                 }
821         }
822 }
823
824 void filelist_readdir(struct FileList* filelist)
825 {
826         filelist->read(filelist);
827 }
828
829 int filelist_empty(struct FileList* filelist)
830 {       
831         return filelist->filelist == 0;
832 }
833
834 void filelist_parent(struct FileList* filelist)
835 {
836         BLI_parent_dir(filelist->dir);
837         BLI_make_exist(filelist->dir);
838         filelist_readdir(filelist);
839 }
840
841 void filelist_setfiletypes(struct FileList* filelist, short has_quicktime)
842 {
843         struct direntry *file;
844         int num;
845
846         file= filelist->filelist;
847
848         for(num=0; num<filelist->numfiles; num++, file++) {
849                 file->flags= 0;
850                 file->type= file->s.st_mode;    /* restore the mess below */ 
851
852                         /* Don't check extensions for directories */ 
853                 if (file->type & S_IFDIR)
854                         continue;
855                                 
856                 
857                 
858                 if(BLO_has_bfile_extension(file->relname)) {
859                         file->flags |= BLENDERFILE;
860                 } else if(BLI_testextensie(file->relname, ".py")) {
861                                 file->flags |= PYSCRIPTFILE;
862                 } else if(BLI_testextensie(file->relname, ".txt")) {
863                                 file->flags |= TEXTFILE;
864                 } else if( BLI_testextensie(file->relname, ".ttf")
865                                         || BLI_testextensie(file->relname, ".ttc")
866                                         || BLI_testextensie(file->relname, ".pfb")
867                                         || BLI_testextensie(file->relname, ".otf")
868                                         || BLI_testextensie(file->relname, ".otc")) {
869                                 file->flags |= FTFONTFILE;                      
870                 } else if (has_quicktime){
871                         if(             BLI_testextensie(file->relname, ".int")
872                                 ||  BLI_testextensie(file->relname, ".inta")
873                                 ||  BLI_testextensie(file->relname, ".jpg")
874 #ifdef WITH_OPENJPEG
875                                 ||  BLI_testextensie(file->relname, ".jp2")
876 #endif
877                                 ||      BLI_testextensie(file->relname, ".jpeg")
878                                 ||      BLI_testextensie(file->relname, ".tga")
879                                 ||      BLI_testextensie(file->relname, ".rgb")
880                                 ||      BLI_testextensie(file->relname, ".rgba")
881                                 ||      BLI_testextensie(file->relname, ".bmp")
882                                 ||      BLI_testextensie(file->relname, ".png")
883                                 ||      BLI_testextensie(file->relname, ".iff")
884                                 ||      BLI_testextensie(file->relname, ".lbm")
885                                 ||      BLI_testextensie(file->relname, ".gif")
886                                 ||      BLI_testextensie(file->relname, ".psd")
887                                 ||      BLI_testextensie(file->relname, ".tif")
888                                 ||      BLI_testextensie(file->relname, ".tiff")
889                                 ||      BLI_testextensie(file->relname, ".pct")
890                                 ||      BLI_testextensie(file->relname, ".pict")
891                                 ||      BLI_testextensie(file->relname, ".pntg") //macpaint
892                                 ||      BLI_testextensie(file->relname, ".qtif")
893                                 ||      BLI_testextensie(file->relname, ".sgi")
894                                 ||      BLI_testextensie(file->relname, ".hdr")
895 #ifdef WITH_DDS
896                                 ||      BLI_testextensie(file->relname, ".dds")
897 #endif
898 #ifdef WITH_OPENEXR
899                                 ||      BLI_testextensie(file->relname, ".exr")
900 #endif
901                             ) {
902                                 file->flags |= IMAGEFILE;                       
903                         }
904                         else if(BLI_testextensie(file->relname, ".avi")
905                                 ||      BLI_testextensie(file->relname, ".flc")
906                                 ||      BLI_testextensie(file->relname, ".mov")
907                                 ||      BLI_testextensie(file->relname, ".movie")
908                                 ||      BLI_testextensie(file->relname, ".mp4")
909                                 ||      BLI_testextensie(file->relname, ".m4v")
910                                 ||      BLI_testextensie(file->relname, ".mv")) {
911                                 file->flags |= MOVIEFILE;                       
912                         }
913                         else if(BLI_testextensie(file->relname, ".wav")
914                                 ||      BLI_testextensie(file->relname, ".ogg")
915                                 ||      BLI_testextensie(file->relname, ".oga")
916                                 ||      BLI_testextensie(file->relname, ".mp3")
917                                 ||      BLI_testextensie(file->relname, ".mp2")
918                                 ||      BLI_testextensie(file->relname, ".ac3")
919                                 ||      BLI_testextensie(file->relname, ".aac")
920                                 ||      BLI_testextensie(file->relname, ".flac")
921                                 ||      BLI_testextensie(file->relname, ".wma")
922                                 ||      BLI_testextensie(file->relname, ".eac3")) {
923                                 file->flags |= SOUNDFILE;
924                         }
925                 } else { // no quicktime
926                         if(BLI_testextensie(file->relname, ".int")
927                                 ||      BLI_testextensie(file->relname, ".inta")
928                                 ||      BLI_testextensie(file->relname, ".jpg")
929                                 ||  BLI_testextensie(file->relname, ".jpeg")
930 #ifdef WITH_OPENJPEG
931                                 ||  BLI_testextensie(file->relname, ".jp2")
932 #endif
933                                 ||      BLI_testextensie(file->relname, ".tga")
934                                 ||      BLI_testextensie(file->relname, ".rgb")
935                                 ||      BLI_testextensie(file->relname, ".rgba")
936                                 ||      BLI_testextensie(file->relname, ".bmp")
937                                 ||      BLI_testextensie(file->relname, ".png")
938                                 ||      BLI_testextensie(file->relname, ".iff")
939                                 ||      BLI_testextensie(file->relname, ".tif")
940                                 ||      BLI_testextensie(file->relname, ".tiff")
941                                 ||      BLI_testextensie(file->relname, ".hdr")
942 #ifdef WITH_DDS
943                                 ||      BLI_testextensie(file->relname, ".dds")
944 #endif
945 #ifdef WITH_OPENEXR
946                                 ||      BLI_testextensie(file->relname, ".exr")
947 #endif
948                                 ||      BLI_testextensie(file->relname, ".lbm")
949                                 ||      BLI_testextensie(file->relname, ".sgi")) {
950                                 file->flags |= IMAGEFILE;                       
951                         }
952                         else if(BLI_testextensie(file->relname, ".avi")
953                                 ||      BLI_testextensie(file->relname, ".mp4")
954                                 ||      BLI_testextensie(file->relname, ".mv")) {
955                                 file->flags |= MOVIEFILE;                       
956                         }
957                         else if(BLI_testextensie(file->relname, ".wav")
958                                 ||      BLI_testextensie(file->relname, ".ogg")
959                                 ||      BLI_testextensie(file->relname, ".oga")
960                                 ||      BLI_testextensie(file->relname, ".mp3")
961                                 ||      BLI_testextensie(file->relname, ".mp2")
962                                 ||      BLI_testextensie(file->relname, ".ac3")
963                                 ||      BLI_testextensie(file->relname, ".aac")
964                                 ||      BLI_testextensie(file->relname, ".flac")
965                                 ||      BLI_testextensie(file->relname, ".wma")
966                                 ||      BLI_testextensie(file->relname, ".eac3")) {
967                                 file->flags |= SOUNDFILE;
968                         }
969                 }
970         }
971 }
972
973 void filelist_swapselect(struct FileList* filelist)
974 {
975         struct direntry *file;
976         int num, act= 0;
977         
978         file= filelist->filelist;
979         for(num=0; num<filelist->numfiles; num++, file++) {
980                 if(file->flags & ACTIVE) {
981                         act= 1;
982                         break;
983                 }
984         }
985         file= filelist->filelist+2;
986         for(num=2; num<filelist->numfiles; num++, file++) {
987                 if(act) file->flags &= ~ACTIVE;
988                 else file->flags |= ACTIVE;
989         }
990 }
991
992 void filelist_sort(struct FileList* filelist, short sort)
993 {
994         switch(sort) {
995         case FILE_SORT_ALPHA:
996                 qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_name);   
997                 break;
998         case FILE_SORT_TIME:
999                 qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_date);   
1000                 break;
1001         case FILE_SORT_SIZE:
1002                 qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_size);   
1003                 break;
1004         case FILE_SORT_EXTENSION:
1005                 qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_extension);      
1006         }
1007
1008         filelist_filter(filelist);
1009 }
1010
1011
1012 int filelist_islibrary(struct FileList* filelist, char* dir, char* group)
1013 {
1014         return BLO_is_a_library(filelist->dir, dir, group);
1015 }
1016
1017 static int groupname_to_code(char *group)
1018 {
1019         char buf[32];
1020         char *lslash;
1021         
1022         BLI_strncpy(buf, group, 31);
1023         lslash= BLI_last_slash(buf);
1024         if (lslash)
1025                 lslash[0]= '\0';
1026
1027         return BLO_idcode_from_name(buf);
1028 }
1029
1030 void filelist_from_library(struct FileList* filelist)
1031 {
1032         LinkNode *l, *names, *previews;
1033         struct ImBuf* ima;
1034         int ok, i, nnames, idcode;
1035         char filename[FILE_MAXDIR+FILE_MAXFILE];
1036         char dir[FILE_MAX], group[GROUP_MAX];   
1037         
1038         /* name test */
1039         ok= filelist_islibrary(filelist, dir, group);
1040         if (!ok) {
1041                 /* free */
1042                 if(filelist->libfiledata) BLO_blendhandle_close(filelist->libfiledata);
1043                 filelist->libfiledata= 0;
1044                 return;
1045         }
1046         
1047         BLI_strncpy(filename, G.sce, sizeof(filename)); // G.sce = last file loaded, for UI
1048
1049         /* there we go */
1050         /* for the time being only read filedata when libfiledata==0 */
1051         if (filelist->libfiledata==0) {
1052                 filelist->libfiledata= BLO_blendhandle_from_file(dir);
1053                 if(filelist->libfiledata==0) return;
1054         }
1055         
1056         idcode= groupname_to_code(group);
1057
1058                 // memory for strings is passed into filelist[i].relname
1059                 // and free'd in freefilelist
1060         previews = NULL;
1061         if (idcode) {
1062                 previews= BLO_blendhandle_get_previews(filelist->libfiledata, idcode);
1063                 names= BLO_blendhandle_get_datablock_names(filelist->libfiledata, idcode);
1064                 /* ugh, no rewind, need to reopen */
1065                 BLO_blendhandle_close(filelist->libfiledata);
1066                 filelist->libfiledata= BLO_blendhandle_from_file(dir);
1067                 
1068         } else {
1069                 names= BLO_blendhandle_get_linkable_groups(filelist->libfiledata);
1070         }
1071         
1072         nnames= BLI_linklist_length(names);
1073
1074         filelist->numfiles= nnames + 1;
1075         filelist->filelist= malloc(filelist->numfiles * sizeof(*filelist->filelist));
1076         memset(filelist->filelist, 0, filelist->numfiles * sizeof(*filelist->filelist));
1077
1078         filelist->filelist[0].relname= BLI_strdup("..");
1079         filelist->filelist[0].type |= S_IFDIR;
1080                 
1081         for (i=0, l= names; i<nnames; i++, l= l->next) {
1082                 char *blockname= l->link;
1083
1084                 filelist->filelist[i + 1].relname= BLI_strdup(blockname);
1085                 if (!idcode)
1086                         filelist->filelist[i + 1].type |= S_IFDIR;
1087         }
1088         
1089         if(previews) {
1090                 for (i=0, l= previews; i<nnames; i++, l= l->next) {
1091                         PreviewImage *img= l->link;
1092                         
1093                         if (img) {
1094                                 unsigned int w = img->w[PREVIEW_MIPMAP_LARGE];
1095                                 unsigned int h = img->h[PREVIEW_MIPMAP_LARGE];
1096                                 unsigned int *rect = img->rect[PREVIEW_MIPMAP_LARGE];
1097
1098                                 /* first allocate imbuf for copying preview into it */
1099                                 if (w > 0 && h > 0 && rect) {
1100                                         ima = IMB_allocImBuf(w, h, 32, IB_rect, 0);
1101                                         memcpy(ima->rect, rect, w*h*sizeof(unsigned int));
1102                                         filelist->filelist[i + 1].image = ima;
1103                                         filelist->filelist[i + 1].flags = IMAGEFILE;
1104                                 }
1105                         }
1106                 }
1107         }
1108
1109         BLI_linklist_free(names, free);
1110         if (previews) BLI_linklist_free(previews, (void(*)(void*)) MEM_freeN);
1111
1112         filelist_sort(filelist, FILE_SORT_ALPHA);
1113
1114         BLI_strncpy(G.sce, filename, sizeof(filename)); // prevent G.sce to change
1115
1116         filelist->filter = 0;
1117         filelist_filter(filelist);
1118 }
1119
1120 void filelist_hideparent(struct FileList* filelist, short hide)
1121 {
1122         filelist->hide_parent = hide;
1123 }
1124
1125 void filelist_from_main(struct FileList *filelist)
1126 {
1127         ID *id;
1128         struct direntry *files, *firstlib = NULL;
1129         ListBase *lb;
1130         int a, fake, idcode, ok, totlib, totbl;
1131         
1132         // filelist->type = FILE_MAIN; // XXXXX TODO: add modes to filebrowser
1133
1134         if(filelist->dir[0]=='/') filelist->dir[0]= 0;
1135         
1136         if(filelist->dir[0]) {
1137                 idcode= groupname_to_code(filelist->dir);
1138                 if(idcode==0) filelist->dir[0]= 0;
1139         }
1140         
1141         if( filelist->dir[0]==0) {
1142                 
1143                 /* make directories */
1144                 filelist->numfiles= 23;
1145                 filelist->filelist= (struct direntry *)malloc(filelist->numfiles * sizeof(struct direntry));
1146                 
1147                 for(a=0; a<filelist->numfiles; a++) {
1148                         memset( &(filelist->filelist[a]), 0 , sizeof(struct direntry));
1149                         filelist->filelist[a].type |= S_IFDIR;
1150                 }
1151                 
1152                 filelist->filelist[0].relname= BLI_strdup("..");
1153                 filelist->filelist[2].relname= BLI_strdup("Scene");
1154                 filelist->filelist[3].relname= BLI_strdup("Object");
1155                 filelist->filelist[4].relname= BLI_strdup("Mesh");
1156                 filelist->filelist[5].relname= BLI_strdup("Curve");
1157                 filelist->filelist[6].relname= BLI_strdup("Metaball");
1158                 filelist->filelist[7].relname= BLI_strdup("Material");
1159                 filelist->filelist[8].relname= BLI_strdup("Texture");
1160                 filelist->filelist[9].relname= BLI_strdup("Image");
1161                 filelist->filelist[10].relname= BLI_strdup("Ika");
1162                 filelist->filelist[11].relname= BLI_strdup("Wave");
1163                 filelist->filelist[12].relname= BLI_strdup("Lattice");
1164                 filelist->filelist[13].relname= BLI_strdup("Lamp");
1165                 filelist->filelist[14].relname= BLI_strdup("Camera");
1166                 filelist->filelist[15].relname= BLI_strdup("Ipo");
1167                 filelist->filelist[16].relname= BLI_strdup("World");
1168                 filelist->filelist[17].relname= BLI_strdup("Screen");
1169                 filelist->filelist[18].relname= BLI_strdup("VFont");
1170                 filelist->filelist[19].relname= BLI_strdup("Text");
1171                 filelist->filelist[20].relname= BLI_strdup("Armature");
1172                 filelist->filelist[21].relname= BLI_strdup("Action");
1173                 filelist->filelist[22].relname= BLI_strdup("NodeTree");
1174                 filelist_sort(filelist, FILE_SORT_ALPHA);
1175         }
1176         else {
1177
1178                 /* make files */
1179                 idcode= groupname_to_code(filelist->dir);
1180                 
1181                 lb= wich_libbase(G.main, idcode );
1182                 if(lb==0) return;
1183                 
1184                 id= lb->first;
1185                 filelist->numfiles= 0;
1186                 while(id) {
1187                         /* XXXXX TODO: the selection of the ipo blocktype might go somewhere else? 
1188                         if(filelist->has_func && idcode==ID_IP) {
1189                                 if(filelist->ipotype== ((Ipo *)id)->blocktype) filelist->numfiles++;
1190                         }
1191                         else */
1192                         if (!filelist->hide_dot || id->name[2] != '.') {
1193                                 filelist->numfiles++;
1194                         }
1195                         
1196                         id= id->next;
1197                 }
1198                 
1199                 /* XXXXX TODO: if databrowse F4 or append/link filelist->hide_parent has to be set */
1200                 if (!filelist->hide_parent) filelist->numfiles+= 1;
1201                 filelist->filelist= (struct direntry *)malloc(filelist->numfiles * sizeof(struct direntry));
1202                 
1203                 files = filelist->filelist;
1204                 
1205                 if (!filelist->hide_parent) {
1206                         memset( &(filelist->filelist[0]), 0 , sizeof(struct direntry));
1207                         filelist->filelist[0].relname= BLI_strdup("..");
1208                         filelist->filelist[0].type |= S_IFDIR;
1209                 
1210                         files++;
1211                 }
1212                 
1213                 id= lb->first;
1214                 totlib= totbl= 0;
1215                 
1216                 while(id) {
1217 #if 0 
1218                         // XXXXX TODO: this is deprecated, checks for correct IPO block? 
1219                         ok= 0;
1220                         if(filelist->has_func && idcode==ID_IP) {
1221                                 if(filelist->ipotype== ((Ipo *)id)->blocktype) ok= 1;
1222                         }
1223                         else ok= 1;
1224 #endif                  
1225                         ok = 1;
1226                         if(ok) {
1227                                 if (!filelist->hide_dot || id->name[2] != '.') {
1228                                         memset( files, 0 , sizeof(struct direntry));
1229                                         if(id->lib==NULL)
1230                                                 files->relname= BLI_strdup(id->name+2);
1231                                         else {
1232                                                 files->relname= MEM_mallocN(FILE_MAXDIR+FILE_MAXFILE+32, "filename for lib");
1233                                                 sprintf(files->relname, "%s | %s", id->lib->name, id->name+2);
1234                                         }
1235                                         /* files->type |= S_IFDIR; */
1236 #if 0                           // XXXXX TODO show the selection status of the objects
1237                                         if(!filelist->has_func) { /* F4 DATA BROWSE */
1238                                                 if(idcode==ID_OB) {
1239                                                         if( ((Object *)id)->flag & SELECT) files->flags |= ACTIVE;
1240                                                 }
1241                                                 else if(idcode==ID_SCE) {
1242                                                         if( ((Scene *)id)->r.scemode & R_BG_RENDER) files->flags |= ACTIVE;
1243                                                 }                                       
1244                                         }
1245 #endif
1246                                         files->nr= totbl+1;
1247                                         files->poin= id;
1248                                         fake= id->flag & LIB_FAKEUSER;
1249                                         if(idcode == ID_MA || idcode == ID_TE || idcode == ID_LA || idcode == ID_WO || idcode == ID_IM) {
1250                                                 files->flags |= IMAGEFILE;
1251                                         }
1252                                         if(id->lib && fake) sprintf(files->extra, "LF %d", id->us);
1253                                         else if(id->lib) sprintf(files->extra, "L    %d", id->us);
1254                                         else if(fake) sprintf(files->extra, "F    %d", id->us);
1255                                         else sprintf(files->extra, "      %d", id->us);
1256                                         
1257                                         if(id->lib) {
1258                                                 if(totlib==0) firstlib= files;
1259                                                 totlib++;
1260                                         }
1261                                         
1262                                         files++;
1263                                 }
1264                                 totbl++;
1265                         }
1266                         
1267                         id= id->next;
1268                 }
1269                 
1270                 /* only qsort of library blocks */
1271                 if(totlib>1) {
1272                         qsort(firstlib, totlib, sizeof(struct direntry), compare_name);
1273                 }
1274         }
1275         filelist->filter = 0;
1276         filelist_filter(filelist);
1277 }
1278