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