Blender V2.61 - r43446

filelist.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version. 
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2007 Blender Foundation.
00019  * All rights reserved.
00020  *
00021  * The Original Code is: all of this file.
00022  *
00023  * Contributor(s): none yet.
00024  *
00025  * ***** END GPL LICENSE BLOCK *****
00026  */
00027 
00033 /* global includes */
00034 
00035 #include <stdlib.h>
00036 #include <math.h>
00037 #include <string.h>
00038 
00039 #ifndef WIN32
00040 #include <unistd.h>
00041 #else
00042 #include <io.h>
00043 #include <direct.h>
00044 #endif   
00045 #include "MEM_guardedalloc.h"
00046 
00047 #include "BLI_blenlib.h"
00048 #include "BLI_linklist.h"
00049 #include "BLI_threads.h"
00050 #include "BLI_utildefines.h"
00051 
00052 #ifdef WIN32
00053 #include "BLI_winstuff.h"
00054 #endif
00055 
00056 #include "BKE_context.h"
00057 #include "BKE_global.h"
00058 #include "BKE_library.h"
00059 #include "BKE_icons.h"
00060 #include "BKE_main.h"
00061 #include "BKE_report.h"
00062 #include "BLO_readfile.h"
00063 #include "BKE_idcode.h"
00064 
00065 #include "DNA_space_types.h"
00066 
00067 #include "ED_fileselect.h"
00068 #include "ED_datafiles.h"
00069 
00070 #include "IMB_imbuf.h"
00071 #include "IMB_imbuf_types.h"
00072 #include "IMB_thumbs.h"
00073 
00074 #include "PIL_time.h"
00075 
00076 #include "WM_api.h"
00077 #include "WM_types.h"
00078 
00079 #include "UI_resources.h"
00080 
00081 #include "filelist.h"
00082 
00083 /* max length of library group name within filesel */
00084 #define GROUP_MAX 32
00085 
00086 struct FileList;
00087 
00088 typedef struct FileImage {
00089     struct FileImage *next, *prev;
00090     char path[FILE_MAX];
00091     unsigned int flags;
00092     int index;
00093     short done;
00094     ImBuf *img;
00095 } FileImage;
00096 
00097 typedef struct ThumbnailJob {
00098     ListBase loadimages;
00099     short *stop;
00100     short *do_update;
00101     struct FileList* filelist;
00102     ReportList reports;
00103 } ThumbnailJob;
00104 
00105 typedef struct FileList
00106 {
00107     struct direntry *filelist;
00108     int *fidx;
00109     int numfiles;
00110     int numfiltered;
00111     char dir[FILE_MAX];
00112     short prv_w;
00113     short prv_h;
00114     short hide_dot;
00115     unsigned int filter;
00116     char filter_glob[64];
00117     short changed;
00118 
00119     struct BlendHandle *libfiledata;
00120     short hide_parent;
00121 
00122     void (*readf)(struct FileList *);
00123     int  (*filterf)(struct direntry* file, const char* dir, unsigned int filter, short hide_dot);
00124 
00125 } FileList;
00126 
00127 typedef struct FolderList
00128 {
00129     struct FolderList *next, *prev;
00130     char *foldername;
00131 } FolderList;
00132 
00133 #define SPECIAL_IMG_SIZE 48
00134 #define SPECIAL_IMG_ROWS 4
00135 #define SPECIAL_IMG_COLS 4
00136 
00137 #define SPECIAL_IMG_FOLDER 0
00138 #define SPECIAL_IMG_PARENT 1
00139 #define SPECIAL_IMG_REFRESH 2
00140 #define SPECIAL_IMG_BLENDFILE 3
00141 #define SPECIAL_IMG_SOUNDFILE 4
00142 #define SPECIAL_IMG_MOVIEFILE 5
00143 #define SPECIAL_IMG_PYTHONFILE 6
00144 #define SPECIAL_IMG_TEXTFILE 7
00145 #define SPECIAL_IMG_FONTFILE 8
00146 #define SPECIAL_IMG_UNKNOWNFILE 9
00147 #define SPECIAL_IMG_LOADING 10
00148 #define SPECIAL_IMG_MAX SPECIAL_IMG_LOADING + 1
00149 
00150 static ImBuf* gSpecialFileImages[SPECIAL_IMG_MAX];
00151 
00152 
00153 /* ******************* SORT ******************* */
00154 
00155 static int compare_name(const void *a1, const void *a2)
00156 {
00157     const struct direntry *entry1=a1, *entry2=a2;
00158 
00159     /* type is equal to stat.st_mode */
00160 
00161     if (S_ISDIR(entry1->type)){
00162         if (S_ISDIR(entry2->type)==0) return (-1);
00163     } else{
00164         if (S_ISDIR(entry2->type)) return (1);
00165     }
00166     if (S_ISREG(entry1->type)){
00167         if (S_ISREG(entry2->type)==0) return (-1);
00168     } else{
00169         if (S_ISREG(entry2->type)) return (1);
00170     }
00171     if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
00172     if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
00173     
00174     /* make sure "." and ".." are always first */
00175     if( strcmp(entry1->relname, ".")==0 ) return (-1);
00176     if( strcmp(entry2->relname, ".")==0 ) return (1);
00177     if( strcmp(entry1->relname, "..")==0 ) return (-1);
00178     if( strcmp(entry2->relname, "..")==0 ) return (1);
00179     
00180     return (BLI_natstrcmp(entry1->relname,entry2->relname));
00181 }
00182 
00183 static int compare_date(const void *a1, const void *a2) 
00184 {
00185     const struct direntry *entry1=a1, *entry2=a2;
00186     
00187     /* type is equal to stat.st_mode */
00188 
00189     if (S_ISDIR(entry1->type)){
00190         if (S_ISDIR(entry2->type)==0) return (-1);
00191     } else{
00192         if (S_ISDIR(entry2->type)) return (1);
00193     }
00194     if (S_ISREG(entry1->type)){
00195         if (S_ISREG(entry2->type)==0) return (-1);
00196     } else{
00197         if (S_ISREG(entry2->type)) return (1);
00198     }
00199     if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
00200     if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
00201 
00202     /* make sure "." and ".." are always first */
00203     if( strcmp(entry1->relname, ".")==0 ) return (-1);
00204     if( strcmp(entry2->relname, ".")==0 ) return (1);
00205     if( strcmp(entry1->relname, "..")==0 ) return (-1);
00206     if( strcmp(entry2->relname, "..")==0 ) return (1);
00207     
00208     if ( entry1->s.st_mtime < entry2->s.st_mtime) return 1;
00209     if ( entry1->s.st_mtime > entry2->s.st_mtime) return -1;
00210     
00211     else return BLI_natstrcmp(entry1->relname,entry2->relname);
00212 }
00213 
00214 static int compare_size(const void *a1, const void *a2) 
00215 {
00216     const struct direntry *entry1=a1, *entry2=a2;
00217 
00218     /* type is equal to stat.st_mode */
00219 
00220     if (S_ISDIR(entry1->type)){
00221         if (S_ISDIR(entry2->type)==0) return (-1);
00222     } else{
00223         if (S_ISDIR(entry2->type)) return (1);
00224     }
00225     if (S_ISREG(entry1->type)){
00226         if (S_ISREG(entry2->type)==0) return (-1);
00227     } else{
00228         if (S_ISREG(entry2->type)) return (1);
00229     }
00230     if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
00231     if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
00232 
00233     /* make sure "." and ".." are always first */
00234     if( strcmp(entry1->relname, ".")==0 ) return (-1);
00235     if( strcmp(entry2->relname, ".")==0 ) return (1);
00236     if( strcmp(entry1->relname, "..")==0 ) return (-1);
00237     if( strcmp(entry2->relname, "..")==0 ) return (1);
00238     
00239     if ( entry1->s.st_size < entry2->s.st_size) return 1;
00240     if ( entry1->s.st_size > entry2->s.st_size) return -1;
00241     else return BLI_natstrcmp(entry1->relname,entry2->relname);
00242 }
00243 
00244 static int compare_extension(const void *a1, const void *a2)
00245 {
00246     const struct direntry *entry1=a1, *entry2=a2;
00247     const char *sufix1, *sufix2;
00248     const char *nil="";
00249 
00250     if (!(sufix1= strstr (entry1->relname, ".blend.gz"))) 
00251         sufix1= strrchr (entry1->relname, '.');
00252     if (!(sufix2= strstr (entry2->relname, ".blend.gz")))
00253         sufix2= strrchr (entry2->relname, '.');
00254     if (!sufix1) sufix1= nil;
00255     if (!sufix2) sufix2= nil;
00256 
00257     /* type is equal to stat.st_mode */
00258 
00259     if (S_ISDIR(entry1->type)){
00260         if (S_ISDIR(entry2->type)==0) return (-1);
00261     } else{
00262         if (S_ISDIR(entry2->type)) return (1);
00263     }
00264     if (S_ISREG(entry1->type)){
00265         if (S_ISREG(entry2->type)==0) return (-1);
00266     } else{
00267         if (S_ISREG(entry2->type)) return (1);
00268     }
00269     if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1);
00270     if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
00271     
00272     /* make sure "." and ".." are always first */
00273     if( strcmp(entry1->relname, ".")==0 ) return (-1);
00274     if( strcmp(entry2->relname, ".")==0 ) return (1);
00275     if( strcmp(entry1->relname, "..")==0 ) return (-1);
00276     if( strcmp(entry2->relname, "..")==0 ) return (1);
00277     
00278     return (BLI_strcasecmp(sufix1, sufix2));
00279 }
00280 
00281 static int is_hidden_file(const char* filename, short hide_dot)
00282 {
00283     int is_hidden=0;
00284 
00285     if (hide_dot) {
00286         if(filename[0]=='.' && filename[1]!='.' && filename[1]!=0) {
00287             is_hidden=1; /* ignore .file */
00288         } else if (((filename[0] == '.') && (filename[1] == 0) )) {
00289             is_hidden=1; /* ignore . */
00290         } else {
00291             int len=strlen(filename);
00292             if( (len>0) && (filename[len-1]=='~') ) {
00293                 is_hidden=1;  /* ignore file~ */
00294             }
00295         } 
00296     } else {
00297         if (((filename[0] == '.') && (filename[1] == 0) )) {
00298             is_hidden=1; /* ignore . */
00299         }
00300     }
00301     return is_hidden;
00302 }
00303 
00304 static int is_filtered_file(struct direntry* file, const char* UNUSED(dir), unsigned int filter, short hide_dot)
00305 {
00306     int is_filtered=0;
00307     if (filter) {
00308         if (file->flags & filter) {
00309             is_filtered=1;
00310         } else if (file->type & S_IFDIR) {
00311             if (filter & FOLDERFILE) {
00312                 is_filtered = 1;
00313             }
00314         }
00315     } else {
00316         is_filtered = 1;
00317     }
00318     return is_filtered && !is_hidden_file(file->relname, hide_dot);
00319 }
00320 
00321 static int is_filtered_lib(struct direntry* file, const char* dir, unsigned int filter, short hide_dot)
00322 {
00323     int is_filtered=0;
00324     char tdir[FILE_MAX], tgroup[GROUP_MAX];
00325     if (BLO_is_a_library(dir, tdir, tgroup)) {
00326         is_filtered = !is_hidden_file(file->relname, hide_dot);
00327     } else {
00328         is_filtered = is_filtered_file(file, dir, filter, hide_dot);
00329     }
00330     return is_filtered;
00331 }
00332 
00333 static int is_filtered_main(struct direntry* file, const char* UNUSED(dir), unsigned int UNUSED(filter), short hide_dot)
00334 {
00335     return !is_hidden_file(file->relname, hide_dot);
00336 }
00337 
00338 void filelist_filter(FileList* filelist)
00339 {
00340     int num_filtered = 0;
00341     int i, j;
00342     
00343     if (!filelist->filelist)
00344         return;
00345 
00346     // How many files are left after filter ?
00347     for (i = 0; i < filelist->numfiles; ++i) {
00348         struct direntry *file = &filelist->filelist[i];
00349         if ( filelist->filterf(file, filelist->dir, filelist->filter, filelist->hide_dot) ) {
00350             num_filtered++;
00351         } 
00352     }
00353     
00354     if (filelist->fidx) {
00355         MEM_freeN(filelist->fidx);
00356         filelist->fidx = NULL;
00357     }
00358     filelist->fidx = (int *)MEM_callocN(num_filtered*sizeof(int), "filteridx");
00359     filelist->numfiltered = num_filtered;
00360 
00361     for (i = 0, j=0; i < filelist->numfiles; ++i) {
00362         struct direntry *file = &filelist->filelist[i];
00363         if ( filelist->filterf(file, filelist->dir, filelist->filter, filelist->hide_dot) ) {
00364             filelist->fidx[j++] = i;
00365         }
00366     }
00367 }
00368 
00369 void filelist_init_icons(void)
00370 {
00371     short x, y, k;
00372     ImBuf *bbuf;
00373     ImBuf *ibuf;
00374 #ifdef WITH_HEADLESS
00375     bbuf = NULL;
00376 #else
00377     bbuf = IMB_ibImageFromMemory((unsigned char*)datatoc_prvicons, datatoc_prvicons_size, IB_rect, "<splash>");
00378 #endif
00379     if (bbuf) {
00380         for (y=0; y<SPECIAL_IMG_ROWS; y++) {
00381             for (x=0; x<SPECIAL_IMG_COLS; x++) {
00382                 int tile = SPECIAL_IMG_COLS*y + x; 
00383                 if (tile < SPECIAL_IMG_MAX) {
00384                     ibuf = IMB_allocImBuf(SPECIAL_IMG_SIZE, SPECIAL_IMG_SIZE, 32, IB_rect);
00385                     for (k=0; k<SPECIAL_IMG_SIZE; k++) {
00386                         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));
00387                     }
00388                     gSpecialFileImages[tile] = ibuf;
00389                 }
00390             }
00391         }
00392         IMB_freeImBuf(bbuf);
00393     }
00394 }
00395 
00396 void filelist_free_icons(void)
00397 {
00398     int i;
00399     for (i=0; i < SPECIAL_IMG_MAX; ++i) {
00400         IMB_freeImBuf(gSpecialFileImages[i]);
00401         gSpecialFileImages[i] = NULL;
00402     }
00403 }
00404 
00405 //-----------------FOLDERLIST (previous/next) --------------//
00406 struct ListBase* folderlist_new(void)
00407 {
00408     ListBase* p = MEM_callocN( sizeof(ListBase), "folderlist" );
00409     return p;
00410 }
00411 
00412 void folderlist_popdir(struct ListBase* folderlist, char *dir)
00413 {
00414     const char *prev_dir;
00415     struct FolderList *folder;
00416     folder = folderlist->last;
00417 
00418     if(folder){
00419         // remove the current directory
00420         MEM_freeN(folder->foldername);
00421         BLI_freelinkN(folderlist, folder);
00422 
00423         folder = folderlist->last;
00424         if(folder){
00425             prev_dir = folder->foldername;
00426             BLI_strncpy(dir, prev_dir, FILE_MAXDIR);
00427         }
00428     }
00429     // delete the folder next or use setdir directly before PREVIOUS OP
00430 }
00431 
00432 void folderlist_pushdir(ListBase* folderlist, const char *dir)
00433 {
00434     struct FolderList *folder, *previous_folder;
00435     previous_folder = folderlist->last;
00436 
00437     // check if already exists
00438     if(previous_folder && previous_folder->foldername){
00439         if(BLI_path_cmp(previous_folder->foldername, dir)==0){
00440             return;
00441         }
00442     }
00443 
00444     // create next folder element
00445     folder = (FolderList*)MEM_mallocN(sizeof(FolderList),"FolderList");
00446     folder->foldername = (char*)MEM_mallocN(sizeof(char)*(strlen(dir)+1), "foldername");
00447     folder->foldername[0] = '\0';
00448 
00449     BLI_strncpy(folder->foldername, dir, FILE_MAXDIR);
00450 
00451     // add it to the end of the list
00452     BLI_addtail(folderlist, folder);
00453 }
00454 
00455 int folderlist_clear_next(struct SpaceFile *sfile)
00456 {
00457     struct FolderList *folder;
00458 
00459     // if there is no folder_next there is nothing we can clear
00460     if (!sfile->folders_next)
00461         return 0;
00462 
00463     // if previous_folder, next_folder or refresh_folder operators are executed it doesn't clear folder_next
00464     folder = sfile->folders_prev->last;
00465     if ((!folder) ||(BLI_path_cmp(folder->foldername, sfile->params->dir) == 0))
00466         return 0;
00467 
00468     // eventually clear flist->folders_next
00469     return 1;
00470 }
00471 
00472 /* not listbase itself */
00473 void folderlist_free(ListBase* folderlist)
00474 {
00475     if (folderlist){
00476         FolderList *folder;
00477         for(folder= folderlist->first; folder; folder= folder->next)
00478             MEM_freeN(folder->foldername);
00479         BLI_freelistN(folderlist);
00480     }
00481 }
00482 
00483 ListBase *folderlist_duplicate(ListBase* folderlist)
00484 {
00485     
00486     if (folderlist) {
00487         ListBase *folderlistn= MEM_callocN(sizeof(ListBase), "copy folderlist");
00488         FolderList *folder;
00489         
00490         BLI_duplicatelist(folderlistn, folderlist);
00491         
00492         for(folder= folderlistn->first; folder; folder= folder->next) {
00493             folder->foldername= MEM_dupallocN(folder->foldername);
00494         }
00495         return folderlistn;
00496     }
00497     return NULL;
00498 }
00499 
00500 
00501 static void filelist_read_main(struct FileList* filelist);
00502 static void filelist_read_library(struct FileList* filelist);
00503 static void filelist_read_dir(struct FileList* filelist);
00504 
00505 //------------------FILELIST------------------------//
00506 struct FileList*    filelist_new(short type)
00507 {
00508     FileList* p = MEM_callocN( sizeof(FileList), "filelist" );
00509     switch(type) {
00510         case FILE_MAIN:
00511             p->readf = filelist_read_main;
00512             p->filterf = is_filtered_main;
00513             break;
00514         case FILE_LOADLIB:
00515             p->readf = filelist_read_library;
00516             p->filterf = is_filtered_lib;
00517             break;
00518         default:
00519             p->readf = filelist_read_dir;
00520             p->filterf = is_filtered_file;
00521 
00522     }
00523     return p;
00524 }
00525 
00526 
00527 void filelist_free(struct FileList* filelist)
00528 {
00529     int i;
00530 
00531     if (!filelist) {
00532         printf("Attempting to delete empty filelist.\n");
00533         return;
00534     }
00535     
00536     if (filelist->fidx) {
00537         MEM_freeN(filelist->fidx);
00538         filelist->fidx = NULL;
00539     }
00540 
00541     for (i = 0; i < filelist->numfiles; ++i) {
00542         if (filelist->filelist[i].image) {          
00543             IMB_freeImBuf(filelist->filelist[i].image);
00544         }
00545         filelist->filelist[i].image = NULL;
00546         if (filelist->filelist[i].relname)
00547             MEM_freeN(filelist->filelist[i].relname);
00548         if (filelist->filelist[i].path)
00549             MEM_freeN(filelist->filelist[i].path);
00550         filelist->filelist[i].relname = NULL;
00551         if (filelist->filelist[i].string)
00552             MEM_freeN(filelist->filelist[i].string);
00553         filelist->filelist[i].string = NULL;
00554     }
00555     
00556     filelist->numfiles = 0;
00557     free(filelist->filelist);
00558     filelist->filelist = NULL;  
00559     filelist->filter = 0;
00560     filelist->filter_glob[0] = '\0';
00561     filelist->numfiltered =0;
00562     filelist->hide_dot =0;
00563 }
00564 
00565 void filelist_freelib(struct FileList* filelist)
00566 {
00567     if(filelist->libfiledata)   
00568         BLO_blendhandle_close(filelist->libfiledata);
00569     filelist->libfiledata= NULL;
00570 }
00571 
00572 struct BlendHandle *filelist_lib(struct FileList* filelist)
00573 {
00574     return filelist->libfiledata;
00575 }
00576 
00577 int filelist_numfiles(struct FileList* filelist)
00578 {
00579     return filelist->numfiltered;
00580 }
00581 
00582 const char * filelist_dir(struct FileList* filelist)
00583 {
00584     return filelist->dir;
00585 }
00586 
00587 void filelist_setdir(struct FileList* filelist, const char *dir)
00588 {
00589     BLI_strncpy(filelist->dir, dir, FILE_MAX);
00590 }
00591 
00592 void filelist_imgsize(struct FileList* filelist, short w, short h)
00593 {
00594     filelist->prv_w = w;
00595     filelist->prv_h = h;
00596 }
00597 
00598 short filelist_changed(struct FileList* filelist)
00599 {
00600     return filelist->changed;
00601 }
00602 
00603 struct ImBuf * filelist_getimage(struct FileList* filelist, int index)
00604 {
00605     ImBuf* ibuf = NULL;
00606     int fidx = 0;   
00607     if ( (index < 0) || (index >= filelist->numfiltered) ) {
00608         return NULL;
00609     }
00610     fidx = filelist->fidx[index];
00611     ibuf = filelist->filelist[fidx].image;
00612 
00613     return ibuf;
00614 }
00615 
00616 struct ImBuf * filelist_geticon(struct FileList* filelist, int index)
00617 {
00618     ImBuf* ibuf= NULL;
00619     struct direntry *file= NULL;
00620     int fidx = 0;   
00621     if ( (index < 0) || (index >= filelist->numfiltered) ) {
00622         return NULL;
00623     }
00624     fidx = filelist->fidx[index];
00625     file = &filelist->filelist[fidx];
00626     if (file->type & S_IFDIR) {
00627         if ( strcmp(filelist->filelist[fidx].relname, "..") == 0) {
00628             ibuf = gSpecialFileImages[SPECIAL_IMG_PARENT];
00629         } else if  ( strcmp(filelist->filelist[fidx].relname, ".") == 0) {
00630             ibuf = gSpecialFileImages[SPECIAL_IMG_REFRESH];
00631         } else {
00632             ibuf = gSpecialFileImages[SPECIAL_IMG_FOLDER];
00633         }
00634     } else {
00635         ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE];
00636     }
00637 
00638     if (file->flags & BLENDERFILE) {
00639         ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE];
00640     } else if ( (file->flags & MOVIEFILE) || (file->flags & MOVIEFILE_ICON) ) {
00641         ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE];
00642     } else if (file->flags & SOUNDFILE) {
00643         ibuf = gSpecialFileImages[SPECIAL_IMG_SOUNDFILE];
00644     } else if (file->flags & PYSCRIPTFILE) {
00645         ibuf = gSpecialFileImages[SPECIAL_IMG_PYTHONFILE];
00646     } else if (file->flags & FTFONTFILE) {
00647         ibuf = gSpecialFileImages[SPECIAL_IMG_FONTFILE];
00648     } else if (file->flags & TEXTFILE) {
00649         ibuf = gSpecialFileImages[SPECIAL_IMG_TEXTFILE];
00650     } else if (file->flags & IMAGEFILE) {
00651         ibuf = gSpecialFileImages[SPECIAL_IMG_LOADING];
00652     }
00653 
00654     return ibuf;
00655 }
00656 
00657 struct direntry * filelist_file(struct FileList* filelist, int index)
00658 {
00659     int fidx = 0;
00660     
00661     if ( (index < 0) || (index >= filelist->numfiltered) ) {
00662         return NULL;
00663     }
00664     fidx = filelist->fidx[index];
00665 
00666     return &filelist->filelist[fidx];
00667 }
00668 
00669 int filelist_find(struct FileList* filelist, const char *filename)
00670 {
00671     int index = -1;
00672     int i;
00673     int fidx = -1;
00674     
00675     if (!filelist->fidx) 
00676         return fidx;
00677 
00678     
00679     for (i = 0; i < filelist->numfiles; ++i) {
00680         if ( strcmp(filelist->filelist[i].relname, filename) == 0) { /* not dealing with user input so dont need BLI_path_cmp */
00681             index = i;
00682             break;
00683         }
00684     }
00685 
00686     for (i = 0; i < filelist->numfiltered; ++i) {
00687         if (filelist->fidx[i] == index) {
00688             fidx = i;
00689             break;
00690         }
00691     }
00692     return fidx;
00693 }
00694 
00695 void filelist_hidedot(struct FileList* filelist, short hide)
00696 {
00697     filelist->hide_dot = hide;
00698 }
00699 
00700 void filelist_setfilter(struct FileList* filelist, unsigned int filter)
00701 {
00702     filelist->filter = filter;
00703 }
00704 
00705 void filelist_setfilter_types(struct FileList* filelist, const char *filter_glob)
00706 {
00707     BLI_strncpy(filelist->filter_glob, filter_glob, sizeof(filelist->filter_glob));
00708 }
00709 
00710 static int file_is_blend_backup(const char *str)
00711 {
00712     short a, b;
00713     int retval= 0;
00714     
00715     a= strlen(str);
00716     b= 7;
00717     
00718     if(a==0 || b>=a);
00719     else {
00720         char *loc;
00721         
00722         if(a > b+1)
00723             b++;
00724         
00725         /* allow .blend1 .blend2 .blend32 */
00726         loc= BLI_strcasestr(str+a-b, ".blend");
00727         
00728         if(loc)
00729             retval= 1;
00730     }
00731     
00732     return (retval);
00733 }
00734 
00735 
00736 static int file_extension_type(const char *relname)
00737 {
00738     if(BLO_has_bfile_extension(relname)) {
00739         return BLENDERFILE;
00740     } else if(file_is_blend_backup(relname)) {
00741         return BLENDERFILE_BACKUP;
00742     } else if(BLI_testextensie(relname, ".py")) {
00743         return PYSCRIPTFILE;
00744     } else if(BLI_testextensie(relname, ".txt")
00745               || BLI_testextensie(relname, ".glsl")
00746               || BLI_testextensie(relname, ".data")) {
00747         return TEXTFILE;
00748     } else if( BLI_testextensie(relname, ".ttf")
00749               || BLI_testextensie(relname, ".ttc")
00750               || BLI_testextensie(relname, ".pfb")
00751               || BLI_testextensie(relname, ".otf")
00752               || BLI_testextensie(relname, ".otc")) {
00753         return FTFONTFILE;          
00754     } else if(BLI_testextensie(relname, ".btx")) {
00755         return BTXFILE;
00756     } else if(BLI_testextensie(relname, ".dae")) {
00757         return COLLADAFILE;
00758     } else if(BLI_testextensie_array(relname, imb_ext_image)
00759               || (G.have_quicktime && BLI_testextensie_array(relname, imb_ext_image_qt))) {
00760         return IMAGEFILE;           
00761     } else if(BLI_testextensie_array(relname, imb_ext_movie)) {
00762         return MOVIEFILE;           
00763     } else if(BLI_testextensie_array(relname, imb_ext_audio)) {
00764         return SOUNDFILE;
00765     } 
00766     return 0;
00767 }
00768 
00769 int ED_file_extension_icon(const char *relname)
00770 {
00771     int type= file_extension_type(relname);
00772     
00773     if (type == BLENDERFILE || type==BLENDERFILE_BACKUP)
00774         return ICON_FILE_BLEND;
00775     else if (type ==  IMAGEFILE)
00776         return ICON_FILE_IMAGE;
00777     else if (type ==  MOVIEFILE)
00778         return ICON_FILE_MOVIE;
00779     else if (type ==  PYSCRIPTFILE)
00780         return ICON_FILE_SCRIPT;
00781     else if (type ==  SOUNDFILE) 
00782         return ICON_FILE_SOUND;
00783     else if (type ==  FTFONTFILE) 
00784         return ICON_FILE_FONT;
00785     else if (type ==  BTXFILE) 
00786         return ICON_FILE_BLANK;
00787     else if (type ==  COLLADAFILE) 
00788         return ICON_FILE_BLANK;
00789     
00790     return ICON_FILE_BLANK;
00791 }
00792 
00793 static void filelist_setfiletypes(struct FileList* filelist)
00794 {
00795     struct direntry *file;
00796     int num;
00797     
00798     file= filelist->filelist;
00799     
00800     for(num=0; num<filelist->numfiles; num++, file++) {
00801         file->type= file->s.st_mode;    /* restore the mess below */ 
00802         
00803         /* Don't check extensions for directories */ 
00804         if (file->type & S_IFDIR) {
00805             continue;
00806         }
00807         file->flags = file_extension_type(file->relname);
00808         
00809         if(filelist->filter_glob
00810            && BLI_testextensie_glob(file->relname, filelist->filter_glob)) {
00811             file->flags= OPERATORFILE;
00812         }
00813         
00814     }
00815 }
00816 
00817 static void filelist_read_dir(struct FileList* filelist)
00818 {
00819     char wdir[FILE_MAX]= "";
00820     if (!filelist) return;
00821 
00822     filelist->fidx = NULL;
00823     filelist->filelist = NULL;
00824 
00825     BLI_current_working_dir(wdir, sizeof(wdir));     /* backup cwd to restore after */
00826 
00827     BLI_cleanup_dir(G.main->name, filelist->dir);
00828     filelist->numfiles = BLI_dir_contents(filelist->dir, &(filelist->filelist));
00829 
00830     if(!chdir(wdir)) {} /* fix warning about not checking return value */
00831     filelist_setfiletypes(filelist);
00832     filelist_filter(filelist);
00833 }
00834 
00835 static void filelist_read_main(struct FileList* filelist)
00836 {
00837     if (!filelist) return;
00838     filelist_from_main(filelist);
00839 }
00840 
00841 static void filelist_read_library(struct FileList* filelist)
00842 {
00843     if (!filelist) return;
00844     BLI_cleanup_dir(G.main->name, filelist->dir);
00845     filelist_from_library(filelist);
00846     if(!filelist->libfiledata) {
00847         int num;
00848         struct direntry *file;
00849 
00850         BLI_make_exist(filelist->dir);
00851         filelist_read_dir(filelist);
00852         file = filelist->filelist;
00853         for(num=0; num<filelist->numfiles; num++, file++) {
00854             if(BLO_has_bfile_extension(file->relname)) {
00855                 char name[FILE_MAX];
00856             
00857                 BLI_strncpy(name, filelist->dir, sizeof(name));
00858                 strcat(name, file->relname);
00859                 
00860                 /* prevent current file being used as acceptable dir */
00861                 if (BLI_path_cmp(G.main->name, name) != 0) {
00862                     file->type &= ~S_IFMT;
00863                     file->type |= S_IFDIR;
00864                 }
00865             }
00866         }
00867     }
00868 }
00869 
00870 void filelist_readdir(struct FileList* filelist)
00871 {
00872     filelist->readf(filelist);
00873 }
00874 
00875 int filelist_empty(struct FileList* filelist)
00876 {   
00877     return filelist->filelist == NULL;
00878 }
00879 
00880 void filelist_parent(struct FileList* filelist)
00881 {
00882     BLI_parent_dir(filelist->dir);
00883     BLI_make_exist(filelist->dir);
00884     filelist_readdir(filelist);
00885 }
00886 
00887 void filelist_select_file(struct FileList* filelist, int index, FileSelType select, unsigned int flag, FileCheckType check)
00888 {
00889     struct direntry* file = filelist_file(filelist, index);
00890     if (file != NULL) { 
00891         int check_ok = 0; 
00892         switch (check) {
00893             case CHECK_DIRS:
00894                 check_ok = S_ISDIR(file->type);
00895                 break;
00896             case CHECK_ALL:
00897                 check_ok = 1;
00898                 break;
00899             case CHECK_FILES:
00900             default:
00901                 check_ok = !S_ISDIR(file->type);
00902                 break;
00903         }
00904         if (check_ok) {
00905             switch (select) {
00906                 case FILE_SEL_REMOVE:
00907                     file->selflag &= ~flag;
00908                     break;
00909                 case FILE_SEL_ADD:
00910                     file->selflag |= flag;
00911                     break;
00912                 case FILE_SEL_TOGGLE:
00913                     file->selflag ^= flag;
00914                     break;
00915             }
00916         }
00917     }
00918 }
00919 
00920 void filelist_select(struct FileList* filelist, FileSelection* sel, FileSelType select, unsigned int flag, FileCheckType check)
00921 {
00922     /* select all valid files between first and last indicated */
00923     if ( (sel->first >= 0) && (sel->first < filelist->numfiltered) && (sel->last >= 0) && (sel->last < filelist->numfiltered) ) {
00924         int current_file;
00925         for (current_file = sel->first; current_file <= sel->last; current_file++) {    
00926             filelist_select_file(filelist, current_file, select, flag, check);
00927         }
00928     }
00929 }
00930 
00931 int filelist_is_selected(struct FileList* filelist, int index, FileCheckType check)
00932 {
00933     struct direntry* file = filelist_file(filelist, index);
00934     if (!file) {
00935         return 0;
00936     }
00937     switch (check) {
00938         case CHECK_DIRS:
00939             return S_ISDIR(file->type) && (file->selflag & SELECTED_FILE);
00940         case CHECK_FILES:
00941             return S_ISREG(file->type) && (file->selflag & SELECTED_FILE);
00942         case CHECK_ALL:
00943         default:
00944             return (file->selflag & SELECTED_FILE);
00945     }
00946 }
00947 
00948 void filelist_sort(struct FileList* filelist, short sort)
00949 {
00950     switch(sort) {
00951     case FILE_SORT_ALPHA:
00952         qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_name);   
00953         break;
00954     case FILE_SORT_TIME:
00955         qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_date);   
00956         break;
00957     case FILE_SORT_SIZE:
00958         qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_size);   
00959         break;
00960     case FILE_SORT_EXTENSION:
00961         qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_extension);  
00962     }
00963 
00964     filelist_filter(filelist);
00965 }
00966 
00967 
00968 int filelist_islibrary(struct FileList* filelist, char* dir, char* group)
00969 {
00970     return BLO_is_a_library(filelist->dir, dir, group);
00971 }
00972 
00973 static int groupname_to_code(const char *group)
00974 {
00975     char buf[32];
00976     char *lslash;
00977     
00978     BLI_strncpy(buf, group, sizeof(buf));
00979     lslash= BLI_last_slash(buf);
00980     if (lslash)
00981         lslash[0]= '\0';
00982 
00983     return BKE_idcode_from_name(buf);
00984 }
00985  
00986 void filelist_from_library(struct FileList* filelist)
00987 {
00988     LinkNode *l, *names, *previews;
00989     struct ImBuf* ima;
00990     int ok, i, nprevs, nnames, idcode;
00991     char filename[FILE_MAX];
00992     char dir[FILE_MAX], group[GROUP_MAX];   
00993     
00994     /* name test */
00995     ok= filelist_islibrary(filelist, dir, group);
00996     if (!ok) {
00997         /* free */
00998         if(filelist->libfiledata) BLO_blendhandle_close(filelist->libfiledata);
00999         filelist->libfiledata= NULL;
01000         return;
01001     }
01002     
01003     BLI_strncpy(filename, G.main->name, sizeof(filename));
01004 
01005     /* there we go */
01006     /* for the time being only read filedata when libfiledata==0 */
01007     if (filelist->libfiledata == NULL) {
01008         filelist->libfiledata= BLO_blendhandle_from_file(dir, NULL);
01009         if(filelist->libfiledata == NULL) return;
01010     }
01011     
01012     idcode= groupname_to_code(group);
01013 
01014     /* memory for strings is passed into filelist[i].relname
01015      * and free'd in freefilelist */
01016     if (idcode) {
01017         previews= BLO_blendhandle_get_previews(filelist->libfiledata, idcode, &nprevs);
01018         names= BLO_blendhandle_get_datablock_names(filelist->libfiledata, idcode, &nnames);
01019         /* ugh, no rewind, need to reopen */
01020         BLO_blendhandle_close(filelist->libfiledata);
01021         filelist->libfiledata= BLO_blendhandle_from_file(dir, NULL);
01022         
01023     } else {
01024         previews= NULL;
01025         nprevs= 0;
01026         names= BLO_blendhandle_get_linkable_groups(filelist->libfiledata);
01027         nnames= BLI_linklist_length(names);
01028     }
01029 
01030     filelist->numfiles= nnames + 1;
01031     filelist->filelist= malloc(filelist->numfiles * sizeof(*filelist->filelist));
01032     memset(filelist->filelist, 0, filelist->numfiles * sizeof(*filelist->filelist));
01033 
01034     filelist->filelist[0].relname= BLI_strdup("..");
01035     filelist->filelist[0].type |= S_IFDIR;
01036         
01037     for (i=0, l= names; i<nnames; i++, l= l->next) {
01038         char *blockname= l->link;
01039 
01040         filelist->filelist[i + 1].relname= BLI_strdup(blockname);
01041         if (idcode) {
01042             filelist->filelist[i + 1].type |= S_IFREG;
01043         } else {
01044             filelist->filelist[i + 1].type |= S_IFDIR;
01045         }
01046     }
01047     
01048     if(previews && (nnames != nprevs)) {
01049         printf("filelist_from_library: error, found %d items, %d previews\n", nnames, nprevs);
01050     }
01051     else if(previews) {
01052         for (i=0, l= previews; i<nnames; i++, l= l->next) {
01053             PreviewImage *img= l->link;
01054             
01055             if (img) {
01056                 unsigned int w = img->w[ICON_SIZE_PREVIEW];
01057                 unsigned int h = img->h[ICON_SIZE_PREVIEW];
01058                 unsigned int *rect = img->rect[ICON_SIZE_PREVIEW];
01059 
01060                 /* first allocate imbuf for copying preview into it */
01061                 if (w > 0 && h > 0 && rect) {
01062                     ima = IMB_allocImBuf(w, h, 32, IB_rect);
01063                     memcpy(ima->rect, rect, w*h*sizeof(unsigned int));
01064                     filelist->filelist[i + 1].image = ima;
01065                     filelist->filelist[i + 1].flags = IMAGEFILE;
01066                 }
01067             }
01068         }
01069     }
01070 
01071     BLI_linklist_free(names, free);
01072     if (previews) BLI_linklist_free(previews, BKE_previewimg_freefunc);
01073 
01074     filelist_sort(filelist, FILE_SORT_ALPHA);
01075 
01076     BLI_strncpy(G.main->name, filename, sizeof(filename));  // prevent G.main->name to change
01077 
01078     filelist->filter = 0;
01079     filelist_filter(filelist);
01080 }
01081 
01082 void filelist_hideparent(struct FileList* filelist, short hide)
01083 {
01084     filelist->hide_parent = hide;
01085 }
01086 
01087 void filelist_from_main(struct FileList *filelist)
01088 {
01089     ID *id;
01090     struct direntry *files, *firstlib = NULL;
01091     ListBase *lb;
01092     int a, fake, idcode, ok, totlib, totbl;
01093     
01094     // filelist->type = FILE_MAIN; // XXXXX TODO: add modes to filebrowser
01095 
01096     if(filelist->dir[0]=='/') filelist->dir[0]= 0;
01097     
01098     if(filelist->dir[0]) {
01099         idcode= groupname_to_code(filelist->dir);
01100         if(idcode==0) filelist->dir[0]= 0;
01101     }
01102     
01103     if( filelist->dir[0]==0) {
01104         
01105         /* make directories */
01106         filelist->numfiles= 24;
01107         filelist->filelist= (struct direntry *)malloc(filelist->numfiles * sizeof(struct direntry));
01108         
01109         for(a=0; a<filelist->numfiles; a++) {
01110             memset( &(filelist->filelist[a]), 0 , sizeof(struct direntry));
01111             filelist->filelist[a].type |= S_IFDIR;
01112         }
01113         
01114         filelist->filelist[0].relname= BLI_strdup("..");
01115         filelist->filelist[2].relname= BLI_strdup("Scene");
01116         filelist->filelist[3].relname= BLI_strdup("Object");
01117         filelist->filelist[4].relname= BLI_strdup("Mesh");
01118         filelist->filelist[5].relname= BLI_strdup("Curve");
01119         filelist->filelist[6].relname= BLI_strdup("Metaball");
01120         filelist->filelist[7].relname= BLI_strdup("Material");
01121         filelist->filelist[8].relname= BLI_strdup("Texture");
01122         filelist->filelist[9].relname= BLI_strdup("Image");
01123         filelist->filelist[10].relname= BLI_strdup("Ika");
01124         filelist->filelist[11].relname= BLI_strdup("Wave");
01125         filelist->filelist[12].relname= BLI_strdup("Lattice");
01126         filelist->filelist[13].relname= BLI_strdup("Lamp");
01127         filelist->filelist[14].relname= BLI_strdup("Camera");
01128         filelist->filelist[15].relname= BLI_strdup("Ipo");
01129         filelist->filelist[16].relname= BLI_strdup("World");
01130         filelist->filelist[17].relname= BLI_strdup("Screen");
01131         filelist->filelist[18].relname= BLI_strdup("VFont");
01132         filelist->filelist[19].relname= BLI_strdup("Text");
01133         filelist->filelist[20].relname= BLI_strdup("Armature");
01134         filelist->filelist[21].relname= BLI_strdup("Action");
01135         filelist->filelist[22].relname= BLI_strdup("NodeTree");
01136         filelist->filelist[23].relname= BLI_strdup("Speaker");
01137         filelist_sort(filelist, FILE_SORT_ALPHA);
01138     }
01139     else {
01140 
01141         /* make files */
01142         idcode= groupname_to_code(filelist->dir);
01143         
01144         lb= which_libbase(G.main, idcode );
01145         if(lb == NULL) return;
01146         
01147         id= lb->first;
01148         filelist->numfiles= 0;
01149         while(id) {
01150             if (!filelist->hide_dot || id->name[2] != '.') {
01151                 filelist->numfiles++;
01152             }
01153             
01154             id= id->next;
01155         }
01156         
01157         /* XXXXX TODO: if databrowse F4 or append/link filelist->hide_parent has to be set */
01158         if (!filelist->hide_parent) filelist->numfiles+= 1;
01159         filelist->filelist= filelist->numfiles > 0 ? (struct direntry *)malloc(filelist->numfiles * sizeof(struct direntry)) : NULL;
01160 
01161         files = filelist->filelist;
01162         
01163         if (!filelist->hide_parent) {
01164             memset( &(filelist->filelist[0]), 0 , sizeof(struct direntry));
01165             filelist->filelist[0].relname= BLI_strdup("..");
01166             filelist->filelist[0].type |= S_IFDIR;
01167         
01168             files++;
01169         }
01170         
01171         id= lb->first;
01172         totlib= totbl= 0;
01173         
01174         while(id) {
01175             ok = 1;
01176             if(ok) {
01177                 if (!filelist->hide_dot || id->name[2] != '.') {
01178                     memset( files, 0 , sizeof(struct direntry));
01179                     if(id->lib==NULL)
01180                         files->relname= BLI_strdup(id->name+2);
01181                     else {
01182                         files->relname= MEM_mallocN(FILE_MAX+32, "filename for lib");
01183                         sprintf(files->relname, "%s | %s", id->lib->name, id->name+2);
01184                     }
01185                     files->type |= S_IFREG;
01186 #if 0               // XXXXX TODO show the selection status of the objects
01187                     if(!filelist->has_func) { /* F4 DATA BROWSE */
01188                         if(idcode==ID_OB) {
01189                             if( ((Object *)id)->flag & SELECT) files->selflag |= SELECTED_FILE;
01190                         }
01191                         else if(idcode==ID_SCE) {
01192                             if( ((Scene *)id)->r.scemode & R_BG_RENDER) files->selflag |= SELECTED_FILE;
01193                         }                   
01194                     }
01195 #endif
01196                     files->nr= totbl+1;
01197                     files->poin= id;
01198                     fake= id->flag & LIB_FAKEUSER;
01199                     if(idcode == ID_MA || idcode == ID_TE || idcode == ID_LA || idcode == ID_WO || idcode == ID_IM) {
01200                         files->flags |= IMAGEFILE;
01201                     }
01202                     if(id->lib && fake) BLI_snprintf(files->extra, sizeof(files->extra), "LF %d", id->us);
01203                     else if(id->lib) BLI_snprintf(files->extra, sizeof(files->extra), "L    %d", id->us);
01204                     else if(fake) BLI_snprintf(files->extra, sizeof(files->extra), "F    %d", id->us);
01205                     else BLI_snprintf(files->extra, sizeof(files->extra), "      %d", id->us);
01206                     
01207                     if(id->lib) {
01208                         if(totlib==0) firstlib= files;
01209                         totlib++;
01210                     }
01211                     
01212                     files++;
01213                 }
01214                 totbl++;
01215             }
01216             
01217             id= id->next;
01218         }
01219         
01220         /* only qsort of library blocks */
01221         if(totlib>1) {
01222             qsort(firstlib, totlib, sizeof(struct direntry), compare_name);
01223         }
01224     }
01225     filelist->filter = 0;
01226     filelist_filter(filelist);
01227 }
01228 
01229 static void thumbnail_joblist_free(ThumbnailJob *tj)
01230 {
01231     FileImage* limg = tj->loadimages.first;
01232     
01233     /* free the images not yet copied to the filelist -> these will get freed with the filelist */
01234     for( ; limg; limg= limg->next) {
01235         if ((limg->img) && (!limg->done)) {
01236             IMB_freeImBuf(limg->img);
01237         }
01238     }
01239     BLI_freelistN(&tj->loadimages);
01240 }
01241 
01242 static void thumbnails_startjob(void *tjv, short *stop, short *do_update, float *UNUSED(progress))
01243 {
01244     ThumbnailJob *tj= tjv;
01245     FileImage* limg = tj->loadimages.first;
01246 
01247     tj->stop= stop;
01248     tj->do_update= do_update;
01249 
01250     while ( (*stop==0) && (limg) ) {
01251         if ( limg->flags & IMAGEFILE ) {
01252             limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_IMAGE);
01253         } else if ( limg->flags & BLENDERFILE ) {
01254             limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_BLEND);
01255         } else if ( limg->flags & MOVIEFILE ) {
01256             limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_MOVIE);
01257             if (!limg->img) {
01258                     /* remember that file can't be loaded via IMB_open_anim */
01259                     limg->flags &= ~MOVIEFILE;
01260                     limg->flags |= MOVIEFILE_ICON;
01261                 }
01262         }
01263         *do_update = 1;
01264         PIL_sleep_ms(10);
01265         limg = limg->next;
01266     }
01267 }
01268 
01269 static void thumbnails_update(void *tjv)
01270 {
01271     ThumbnailJob *tj= tjv;
01272 
01273     if (tj->filelist && tj->filelist->filelist) {
01274         FileImage* limg = tj->loadimages.first;
01275         while (limg) {
01276             if (!limg->done && limg->img) {
01277                 tj->filelist->filelist[limg->index].image = limg->img;
01278                 /* update flag for movie files where thumbnail can't be created */
01279                 if (limg->flags & MOVIEFILE_ICON) {
01280                     tj->filelist->filelist[limg->index].flags &= ~MOVIEFILE;
01281                     tj->filelist->filelist[limg->index].flags |= MOVIEFILE_ICON;
01282                 }
01283                 limg->done=1;
01284             }
01285             limg = limg->next;
01286         }
01287     }
01288 }
01289 
01290 static void thumbnails_free(void *tjv)
01291 {
01292     ThumbnailJob *tj= tjv;
01293     thumbnail_joblist_free(tj);
01294     MEM_freeN(tj);
01295 }
01296 
01297 
01298 void thumbnails_start(struct FileList* filelist, const struct bContext* C)
01299 {
01300     wmJob *steve;
01301     ThumbnailJob *tj;
01302     int idx;
01303     
01304     /* prepare job data */
01305     tj= MEM_callocN(sizeof(ThumbnailJob), "thumbnails\n");
01306     tj->filelist = filelist;
01307     for (idx = 0; idx < filelist->numfiles;idx++) {
01308         if (!filelist->filelist[idx].image) {
01309             if ( (filelist->filelist[idx].flags & (IMAGEFILE|MOVIEFILE|BLENDERFILE)) ) {
01310                 FileImage* limg = MEM_callocN(sizeof(struct FileImage), "loadimage");
01311                 BLI_strncpy(limg->path, filelist->filelist[idx].path, FILE_MAX);
01312                 limg->index= idx;
01313                 limg->flags= filelist->filelist[idx].flags;
01314                 BLI_addtail(&tj->loadimages, limg);
01315             }
01316         }
01317     }
01318 
01319     BKE_reports_init(&tj->reports, RPT_PRINT);
01320 
01321     /* setup job */
01322     steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), filelist, "Thumbnails", 0);
01323     WM_jobs_customdata(steve, tj, thumbnails_free);
01324     WM_jobs_timer(steve, 0.5, NC_WINDOW, NC_WINDOW);
01325     WM_jobs_callbacks(steve, thumbnails_startjob, NULL, thumbnails_update, NULL);
01326 
01327     /* start the job */
01328     WM_jobs_start(CTX_wm_manager(C), steve);
01329 }
01330 
01331 void thumbnails_stop(struct FileList* filelist, const struct bContext* C)
01332 {
01333     WM_jobs_kill(CTX_wm_manager(C), filelist, NULL);
01334 }
01335 
01336 int thumbnails_running(struct FileList* filelist, const struct bContext* C)
01337 {
01338     return WM_jobs_test(CTX_wm_manager(C), filelist);
01339 }