/* * $Id$ * * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2007 Blender Foundation. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL LICENSE BLOCK ***** */ /** \file blender/editors/space_file/filelist.c * \ingroup spfile */ /* global includes */ #include #include #include #ifndef WIN32 #include #else #include #include #endif #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" #include "BLI_linklist.h" #include "BLI_storage_types.h" #include "BLI_threads.h" #include "BLI_utildefines.h" #ifdef WIN32 #include "BLI_winstuff.h" #endif #include "BKE_context.h" #include "BKE_global.h" #include "BKE_library.h" #include "BKE_icons.h" #include "BKE_main.h" #include "BKE_report.h" #include "BLO_readfile.h" #include "BKE_idcode.h" #include "DNA_space_types.h" #include "ED_fileselect.h" #include "ED_datafiles.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" #include "IMB_thumbs.h" #include "PIL_time.h" #include "WM_api.h" #include "WM_types.h" #include "UI_resources.h" #include "filelist.h" /* max length of library group name within filesel */ #define GROUP_MAX 32 struct FileList; typedef struct FileImage { struct FileImage *next, *prev; char path[FILE_MAX]; unsigned int flags; int index; short done; ImBuf *img; } FileImage; typedef struct ThumbnailJob { ListBase loadimages; short *stop; short *do_update; struct FileList* filelist; ReportList reports; } ThumbnailJob; typedef struct FileList { struct direntry *filelist; int *fidx; int numfiles; int numfiltered; char dir[FILE_MAX]; short prv_w; short prv_h; short hide_dot; unsigned int filter; char filter_glob[64]; short changed; struct BlendHandle *libfiledata; short hide_parent; void (*readf)(struct FileList *); int (*filterf)(struct direntry* file, const char* dir, unsigned int filter, short hide_dot); } FileList; typedef struct FolderList { struct FolderList *next, *prev; char *foldername; } FolderList; #define SPECIAL_IMG_SIZE 48 #define SPECIAL_IMG_ROWS 4 #define SPECIAL_IMG_COLS 4 #define SPECIAL_IMG_FOLDER 0 #define SPECIAL_IMG_PARENT 1 #define SPECIAL_IMG_REFRESH 2 #define SPECIAL_IMG_BLENDFILE 3 #define SPECIAL_IMG_SOUNDFILE 4 #define SPECIAL_IMG_MOVIEFILE 5 #define SPECIAL_IMG_PYTHONFILE 6 #define SPECIAL_IMG_TEXTFILE 7 #define SPECIAL_IMG_FONTFILE 8 #define SPECIAL_IMG_UNKNOWNFILE 9 #define SPECIAL_IMG_LOADING 10 #define SPECIAL_IMG_MAX SPECIAL_IMG_LOADING + 1 static ImBuf* gSpecialFileImages[SPECIAL_IMG_MAX]; /* ******************* SORT ******************* */ static int compare_name(const void *a1, const void *a2) { const struct direntry *entry1=a1, *entry2=a2; /* type is equal to stat.st_mode */ if (S_ISDIR(entry1->type)){ if (S_ISDIR(entry2->type)==0) return (-1); } else{ if (S_ISDIR(entry2->type)) return (1); } if (S_ISREG(entry1->type)){ if (S_ISREG(entry2->type)==0) return (-1); } else{ if (S_ISREG(entry2->type)) return (1); } if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1); if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1); /* make sure "." and ".." are always first */ if( strcmp(entry1->relname, ".")==0 ) return (-1); if( strcmp(entry2->relname, ".")==0 ) return (1); if( strcmp(entry1->relname, "..")==0 ) return (-1); if( strcmp(entry2->relname, "..")==0 ) return (1); return (BLI_natstrcmp(entry1->relname,entry2->relname)); } static int compare_date(const void *a1, const void *a2) { const struct direntry *entry1=a1, *entry2=a2; /* type is equal to stat.st_mode */ if (S_ISDIR(entry1->type)){ if (S_ISDIR(entry2->type)==0) return (-1); } else{ if (S_ISDIR(entry2->type)) return (1); } if (S_ISREG(entry1->type)){ if (S_ISREG(entry2->type)==0) return (-1); } else{ if (S_ISREG(entry2->type)) return (1); } if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1); if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1); /* make sure "." and ".." are always first */ if( strcmp(entry1->relname, ".")==0 ) return (-1); if( strcmp(entry2->relname, ".")==0 ) return (1); if( strcmp(entry1->relname, "..")==0 ) return (-1); if( strcmp(entry2->relname, "..")==0 ) return (1); if ( entry1->s.st_mtime < entry2->s.st_mtime) return 1; if ( entry1->s.st_mtime > entry2->s.st_mtime) return -1; else return BLI_natstrcmp(entry1->relname,entry2->relname); } static int compare_size(const void *a1, const void *a2) { const struct direntry *entry1=a1, *entry2=a2; /* type is equal to stat.st_mode */ if (S_ISDIR(entry1->type)){ if (S_ISDIR(entry2->type)==0) return (-1); } else{ if (S_ISDIR(entry2->type)) return (1); } if (S_ISREG(entry1->type)){ if (S_ISREG(entry2->type)==0) return (-1); } else{ if (S_ISREG(entry2->type)) return (1); } if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1); if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1); /* make sure "." and ".." are always first */ if( strcmp(entry1->relname, ".")==0 ) return (-1); if( strcmp(entry2->relname, ".")==0 ) return (1); if( strcmp(entry1->relname, "..")==0 ) return (-1); if( strcmp(entry2->relname, "..")==0 ) return (1); if ( entry1->s.st_size < entry2->s.st_size) return 1; if ( entry1->s.st_size > entry2->s.st_size) return -1; else return BLI_natstrcmp(entry1->relname,entry2->relname); } static int compare_extension(const void *a1, const void *a2) { const struct direntry *entry1=a1, *entry2=a2; const char *sufix1, *sufix2; const char *nil=""; if (!(sufix1= strstr (entry1->relname, ".blend.gz"))) sufix1= strrchr (entry1->relname, '.'); if (!(sufix2= strstr (entry2->relname, ".blend.gz"))) sufix2= strrchr (entry2->relname, '.'); if (!sufix1) sufix1= nil; if (!sufix2) sufix2= nil; /* type is equal to stat.st_mode */ if (S_ISDIR(entry1->type)){ if (S_ISDIR(entry2->type)==0) return (-1); } else{ if (S_ISDIR(entry2->type)) return (1); } if (S_ISREG(entry1->type)){ if (S_ISREG(entry2->type)==0) return (-1); } else{ if (S_ISREG(entry2->type)) return (1); } if ((entry1->type & S_IFMT) < (entry2->type & S_IFMT)) return (-1); if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1); /* make sure "." and ".." are always first */ if( strcmp(entry1->relname, ".")==0 ) return (-1); if( strcmp(entry2->relname, ".")==0 ) return (1); if( strcmp(entry1->relname, "..")==0 ) return (-1); if( strcmp(entry2->relname, "..")==0 ) return (1); return (BLI_strcasecmp(sufix1, sufix2)); } static int is_hidden_file(const char* filename, short hide_dot) { int is_hidden=0; if (hide_dot) { if(filename[0]=='.' && filename[1]!='.' && filename[1]!=0) { is_hidden=1; /* ignore .file */ } else if (((filename[0] == '.') && (filename[1] == 0) )) { is_hidden=1; /* ignore . */ } else { int len=strlen(filename); if( (len>0) && (filename[len-1]=='~') ) { is_hidden=1; /* ignore file~ */ } } } else { if (((filename[0] == '.') && (filename[1] == 0) )) { is_hidden=1; /* ignore . */ } } return is_hidden; } static int is_filtered_file(struct direntry* file, const char* UNUSED(dir), unsigned int filter, short hide_dot) { int is_filtered=0; if (filter) { if (file->flags & filter) { is_filtered=1; } else if (file->type & S_IFDIR) { if (filter & FOLDERFILE) { is_filtered = 1; } } } else { is_filtered = 1; } return is_filtered && !is_hidden_file(file->relname, hide_dot); } static int is_filtered_lib(struct direntry* file, const char* dir, unsigned int filter, short hide_dot) { int is_filtered=0; char tdir[FILE_MAX], tgroup[GROUP_MAX]; if (BLO_is_a_library(dir, tdir, tgroup)) { is_filtered = !is_hidden_file(file->relname, hide_dot); } else { is_filtered = is_filtered_file(file, dir, filter, hide_dot); } return is_filtered; } static int is_filtered_main(struct direntry* file, const char* UNUSED(dir), unsigned int UNUSED(filter), short hide_dot) { return !is_hidden_file(file->relname, hide_dot); } void filelist_filter(FileList* filelist) { int num_filtered = 0; int i, j; if (!filelist->filelist) return; // How many files are left after filter ? for (i = 0; i < filelist->numfiles; ++i) { struct direntry *file = &filelist->filelist[i]; if ( filelist->filterf(file, filelist->dir, filelist->filter, filelist->hide_dot) ) { num_filtered++; } } if (filelist->fidx) { MEM_freeN(filelist->fidx); filelist->fidx = NULL; } filelist->fidx = (int *)MEM_callocN(num_filtered*sizeof(int), "filteridx"); filelist->numfiltered = num_filtered; for (i = 0, j=0; i < filelist->numfiles; ++i) { struct direntry *file = &filelist->filelist[i]; if ( filelist->filterf(file, filelist->dir, filelist->filter, filelist->hide_dot) ) { filelist->fidx[j++] = i; } } } void filelist_init_icons(void) { short x, y, k; ImBuf *bbuf; ImBuf *ibuf; #ifdef WITH_HEADLESS bbuf = NULL; #else bbuf = IMB_ibImageFromMemory((unsigned char*)datatoc_prvicons, datatoc_prvicons_size, IB_rect); #endif if (bbuf) { for (y=0; yrect[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)); } gSpecialFileImages[tile] = ibuf; } } } IMB_freeImBuf(bbuf); } } void filelist_free_icons(void) { int i; for (i=0; i < SPECIAL_IMG_MAX; ++i) { IMB_freeImBuf(gSpecialFileImages[i]); gSpecialFileImages[i] = NULL; } } //-----------------FOLDERLIST (previous/next) --------------// struct ListBase* folderlist_new(void) { ListBase* p = MEM_callocN( sizeof(ListBase), "folderlist" ); return p; } void folderlist_popdir(struct ListBase* folderlist, char *dir) { const char *prev_dir; struct FolderList *folder; folder = folderlist->last; if(folder){ // remove the current directory MEM_freeN(folder->foldername); BLI_freelinkN(folderlist, folder); folder = folderlist->last; if(folder){ prev_dir = folder->foldername; BLI_strncpy(dir, prev_dir, FILE_MAXDIR); } } // delete the folder next or use setdir directly before PREVIOUS OP } void folderlist_pushdir(ListBase* folderlist, const char *dir) { struct FolderList *folder, *previous_folder; previous_folder = folderlist->last; // check if already exists if(previous_folder && previous_folder->foldername){ if(BLI_path_cmp(previous_folder->foldername, dir)==0){ return; } } // create next folder element folder = (FolderList*)MEM_mallocN(sizeof(FolderList),"FolderList"); folder->foldername = (char*)MEM_mallocN(sizeof(char)*(strlen(dir)+1), "foldername"); folder->foldername[0] = '\0'; BLI_strncpy(folder->foldername, dir, FILE_MAXDIR); // add it to the end of the list BLI_addtail(folderlist, folder); } int folderlist_clear_next(struct SpaceFile *sfile) { struct FolderList *folder; // if there is no folder_next there is nothing we can clear if (!sfile->folders_next) return 0; // if previous_folder, next_folder or refresh_folder operators are executed it doesn't clear folder_next folder = sfile->folders_prev->last; if ((!folder) ||(BLI_path_cmp(folder->foldername, sfile->params->dir) == 0)) return 0; // eventually clear flist->folders_next return 1; } /* not listbase itself */ void folderlist_free(ListBase* folderlist) { if (folderlist){ FolderList *folder; for(folder= folderlist->first; folder; folder= folder->next) MEM_freeN(folder->foldername); BLI_freelistN(folderlist); } } ListBase *folderlist_duplicate(ListBase* folderlist) { if (folderlist) { ListBase *folderlistn= MEM_callocN(sizeof(ListBase), "copy folderlist"); FolderList *folder; BLI_duplicatelist(folderlistn, folderlist); for(folder= folderlistn->first; folder; folder= folder->next) { folder->foldername= MEM_dupallocN(folder->foldername); } return folderlistn; } return NULL; } static void filelist_read_main(struct FileList* filelist); static void filelist_read_library(struct FileList* filelist); static void filelist_read_dir(struct FileList* filelist); //------------------FILELIST------------------------// struct FileList* filelist_new(short type) { FileList* p = MEM_callocN( sizeof(FileList), "filelist" ); switch(type) { case FILE_MAIN: p->readf = filelist_read_main; p->filterf = is_filtered_main; break; case FILE_LOADLIB: p->readf = filelist_read_library; p->filterf = is_filtered_lib; break; default: p->readf = filelist_read_dir; p->filterf = is_filtered_file; } return p; } void filelist_free(struct FileList* filelist) { int i; if (!filelist) { printf("Attempting to delete empty filelist.\n"); return; } if (filelist->fidx) { MEM_freeN(filelist->fidx); filelist->fidx = NULL; } for (i = 0; i < filelist->numfiles; ++i) { if (filelist->filelist[i].image) { IMB_freeImBuf(filelist->filelist[i].image); } filelist->filelist[i].image = NULL; if (filelist->filelist[i].relname) MEM_freeN(filelist->filelist[i].relname); if (filelist->filelist[i].path) MEM_freeN(filelist->filelist[i].path); filelist->filelist[i].relname = NULL; if (filelist->filelist[i].string) MEM_freeN(filelist->filelist[i].string); filelist->filelist[i].string = NULL; } filelist->numfiles = 0; free(filelist->filelist); filelist->filelist = NULL; filelist->filter = 0; filelist->filter_glob[0] = '\0'; filelist->numfiltered =0; filelist->hide_dot =0; } void filelist_freelib(struct FileList* filelist) { if(filelist->libfiledata) BLO_blendhandle_close(filelist->libfiledata); filelist->libfiledata= NULL; } struct BlendHandle *filelist_lib(struct FileList* filelist) { return filelist->libfiledata; } int filelist_numfiles(struct FileList* filelist) { return filelist->numfiltered; } const char * filelist_dir(struct FileList* filelist) { return filelist->dir; } void filelist_setdir(struct FileList* filelist, const char *dir) { BLI_strncpy(filelist->dir, dir, FILE_MAX); } void filelist_imgsize(struct FileList* filelist, short w, short h) { filelist->prv_w = w; filelist->prv_h = h; } short filelist_changed(struct FileList* filelist) { return filelist->changed; } struct ImBuf * filelist_getimage(struct FileList* filelist, int index) { ImBuf* ibuf = NULL; int fidx = 0; if ( (index < 0) || (index >= filelist->numfiltered) ) { return NULL; } fidx = filelist->fidx[index]; ibuf = filelist->filelist[fidx].image; return ibuf; } struct ImBuf * filelist_geticon(struct FileList* filelist, int index) { ImBuf* ibuf= NULL; struct direntry *file= NULL; int fidx = 0; if ( (index < 0) || (index >= filelist->numfiltered) ) { return NULL; } fidx = filelist->fidx[index]; file = &filelist->filelist[fidx]; if (file->type & S_IFDIR) { if ( strcmp(filelist->filelist[fidx].relname, "..") == 0) { ibuf = gSpecialFileImages[SPECIAL_IMG_PARENT]; } else if ( strcmp(filelist->filelist[fidx].relname, ".") == 0) { ibuf = gSpecialFileImages[SPECIAL_IMG_REFRESH]; } else { ibuf = gSpecialFileImages[SPECIAL_IMG_FOLDER]; } } else { ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE]; } if (file->flags & BLENDERFILE) { ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE]; } else if ( (file->flags & MOVIEFILE) || (file->flags & MOVIEFILE_ICON) ) { ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE]; } else if (file->flags & SOUNDFILE) { ibuf = gSpecialFileImages[SPECIAL_IMG_SOUNDFILE]; } else if (file->flags & PYSCRIPTFILE) { ibuf = gSpecialFileImages[SPECIAL_IMG_PYTHONFILE]; } else if (file->flags & FTFONTFILE) { ibuf = gSpecialFileImages[SPECIAL_IMG_FONTFILE]; } else if (file->flags & TEXTFILE) { ibuf = gSpecialFileImages[SPECIAL_IMG_TEXTFILE]; } else if (file->flags & IMAGEFILE) { ibuf = gSpecialFileImages[SPECIAL_IMG_LOADING]; } return ibuf; } struct direntry * filelist_file(struct FileList* filelist, int index) { int fidx = 0; if ( (index < 0) || (index >= filelist->numfiltered) ) { return NULL; } fidx = filelist->fidx[index]; return &filelist->filelist[fidx]; } int filelist_find(struct FileList* filelist, char *file) { int index = -1; int i; int fidx = -1; if (!filelist->fidx) return fidx; for (i = 0; i < filelist->numfiles; ++i) { if ( strcmp(filelist->filelist[i].relname, file) == 0) { /* not dealing with user input so dont need BLI_path_cmp */ index = i; break; } } for (i = 0; i < filelist->numfiltered; ++i) { if (filelist->fidx[i] == index) { fidx = i; break; } } return fidx; } void filelist_hidedot(struct FileList* filelist, short hide) { filelist->hide_dot = hide; } void filelist_setfilter(struct FileList* filelist, unsigned int filter) { filelist->filter = filter; } void filelist_setfilter_types(struct FileList* filelist, const char *filter_glob) { BLI_strncpy(filelist->filter_glob, filter_glob, sizeof(filelist->filter_glob)); } static int file_is_blend_backup(const char *str) { short a, b; int retval= 0; a= strlen(str); b= 7; if(a==0 || b>=a); else { char *loc; if(a > b+1) b++; /* allow .blend1 .blend2 .blend32 */ loc= BLI_strcasestr(str+a-b, ".blend"); if(loc) retval= 1; } return (retval); } static int file_extension_type(const char *relname) { if(BLO_has_bfile_extension(relname)) { return BLENDERFILE; } else if(file_is_blend_backup(relname)) { return BLENDERFILE_BACKUP; } else if(BLI_testextensie(relname, ".py")) { return PYSCRIPTFILE; } else if(BLI_testextensie(relname, ".txt") || BLI_testextensie(relname, ".glsl") || BLI_testextensie(relname, ".data")) { return TEXTFILE; } else if( BLI_testextensie(relname, ".ttf") || BLI_testextensie(relname, ".ttc") || BLI_testextensie(relname, ".pfb") || BLI_testextensie(relname, ".otf") || BLI_testextensie(relname, ".otc")) { return FTFONTFILE; } else if(BLI_testextensie(relname, ".btx")) { return BTXFILE; } else if(BLI_testextensie(relname, ".dae")) { return COLLADAFILE; } else if(BLI_testextensie_array(relname, imb_ext_image) || (G.have_quicktime && BLI_testextensie_array(relname, imb_ext_image_qt))) { return IMAGEFILE; } else if(BLI_testextensie_array(relname, imb_ext_movie)) { return MOVIEFILE; } else if(BLI_testextensie_array(relname, imb_ext_audio)) { return SOUNDFILE; } return 0; } int ED_file_extension_icon(const char *relname) { int type= file_extension_type(relname); if (type == BLENDERFILE || type==BLENDERFILE_BACKUP) return ICON_FILE_BLEND; else if (type == IMAGEFILE) return ICON_FILE_IMAGE; else if (type == MOVIEFILE) return ICON_FILE_MOVIE; else if (type == PYSCRIPTFILE) return ICON_FILE_SCRIPT; else if (type == SOUNDFILE) return ICON_FILE_SOUND; else if (type == FTFONTFILE) return ICON_FILE_FONT; else if (type == BTXFILE) return ICON_FILE_BLANK; else if (type == COLLADAFILE) return ICON_FILE_BLANK; return ICON_FILE_BLANK; } static void filelist_setfiletypes(struct FileList* filelist) { struct direntry *file; int num; file= filelist->filelist; for(num=0; numnumfiles; num++, file++) { file->type= file->s.st_mode; /* restore the mess below */ /* Don't check extensions for directories */ if (file->type & S_IFDIR) { continue; } file->flags = file_extension_type(file->relname); if(filelist->filter_glob && BLI_testextensie_glob(file->relname, filelist->filter_glob)) { file->flags= OPERATORFILE; } } } static void filelist_read_dir(struct FileList* filelist) { char wdir[FILE_MAX]= ""; if (!filelist) return; filelist->fidx = NULL; filelist->filelist = NULL; BLI_getwdN(wdir, sizeof(wdir)); /* backup cwd to restore after */ BLI_cleanup_dir(G.main->name, filelist->dir); filelist->numfiles = BLI_getdir(filelist->dir, &(filelist->filelist)); if(!chdir(wdir)) {} /* fix warning about not checking return value */ filelist_setfiletypes(filelist); filelist_filter(filelist); } static void filelist_read_main(struct FileList* filelist) { if (!filelist) return; filelist_from_main(filelist); } static void filelist_read_library(struct FileList* filelist) { if (!filelist) return; BLI_cleanup_dir(G.main->name, filelist->dir); filelist_from_library(filelist); if(!filelist->libfiledata) { int num; struct direntry *file; BLI_make_exist(filelist->dir); filelist_read_dir(filelist); file = filelist->filelist; for(num=0; numnumfiles; num++, file++) { if(BLO_has_bfile_extension(file->relname)) { char name[FILE_MAXDIR+FILE_MAXFILE]; BLI_strncpy(name, filelist->dir, sizeof(name)); strcat(name, file->relname); /* prevent current file being used as acceptable dir */ if (BLI_path_cmp(G.main->name, name) != 0) { file->type &= ~S_IFMT; file->type |= S_IFDIR; } } } } } void filelist_readdir(struct FileList* filelist) { filelist->readf(filelist); } int filelist_empty(struct FileList* filelist) { return filelist->filelist == NULL; } void filelist_parent(struct FileList* filelist) { BLI_parent_dir(filelist->dir); BLI_make_exist(filelist->dir); filelist_readdir(filelist); } void filelist_select_file(struct FileList* filelist, int index, FileSelType select, unsigned int flag, FileCheckType check) { struct direntry* file = filelist_file(filelist, index); if (file != NULL) { int check_ok = 0; switch (check) { case CHECK_DIRS: check_ok = S_ISDIR(file->type); break; case CHECK_ALL: check_ok = 1; break; case CHECK_FILES: default: check_ok = !S_ISDIR(file->type); break; } if (check_ok) { switch (select) { case FILE_SEL_REMOVE: file->selflag &= ~flag; break; case FILE_SEL_ADD: file->selflag |= flag; break; case FILE_SEL_TOGGLE: file->selflag ^= flag; break; } } } } void filelist_select(struct FileList* filelist, FileSelection* sel, FileSelType select, unsigned int flag, FileCheckType check) { /* select all valid files between first and last indicated */ if ( (sel->first >= 0) && (sel->first < filelist->numfiltered) && (sel->last >= 0) && (sel->last < filelist->numfiltered) ) { int current_file; for (current_file = sel->first; current_file <= sel->last; current_file++) { filelist_select_file(filelist, current_file, select, flag, check); } } } int filelist_is_selected(struct FileList* filelist, int index, FileCheckType check) { struct direntry* file = filelist_file(filelist, index); if (!file) { return 0; } switch (check) { case CHECK_DIRS: return S_ISDIR(file->type) && (file->selflag & SELECTED_FILE); case CHECK_FILES: return S_ISREG(file->type) && (file->selflag & SELECTED_FILE); case CHECK_ALL: default: return (file->selflag & SELECTED_FILE); } } void filelist_sort(struct FileList* filelist, short sort) { switch(sort) { case FILE_SORT_ALPHA: qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_name); break; case FILE_SORT_TIME: qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_date); break; case FILE_SORT_SIZE: qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_size); break; case FILE_SORT_EXTENSION: qsort(filelist->filelist, filelist->numfiles, sizeof(struct direntry), compare_extension); } filelist_filter(filelist); } int filelist_islibrary(struct FileList* filelist, char* dir, char* group) { return BLO_is_a_library(filelist->dir, dir, group); } static int groupname_to_code(char *group) { char buf[32]; char *lslash; BLI_strncpy(buf, group, sizeof(buf)); lslash= BLI_last_slash(buf); if (lslash) lslash[0]= '\0'; return BKE_idcode_from_name(buf); } void filelist_from_library(struct FileList* filelist) { LinkNode *l, *names, *previews; struct ImBuf* ima; int ok, i, nprevs, nnames, idcode; char filename[FILE_MAXDIR+FILE_MAXFILE]; char dir[FILE_MAX], group[GROUP_MAX]; /* name test */ ok= filelist_islibrary(filelist, dir, group); if (!ok) { /* free */ if(filelist->libfiledata) BLO_blendhandle_close(filelist->libfiledata); filelist->libfiledata= NULL; return; } BLI_strncpy(filename, G.main->name, sizeof(filename)); /* there we go */ /* for the time being only read filedata when libfiledata==0 */ if (filelist->libfiledata == NULL) { filelist->libfiledata= BLO_blendhandle_from_file(dir, NULL); if(filelist->libfiledata == NULL) return; } idcode= groupname_to_code(group); /* memory for strings is passed into filelist[i].relname * and free'd in freefilelist */ if (idcode) { previews= BLO_blendhandle_get_previews(filelist->libfiledata, idcode, &nprevs); names= BLO_blendhandle_get_datablock_names(filelist->libfiledata, idcode, &nnames); /* ugh, no rewind, need to reopen */ BLO_blendhandle_close(filelist->libfiledata); filelist->libfiledata= BLO_blendhandle_from_file(dir, NULL); } else { previews= NULL; nprevs= 0; names= BLO_blendhandle_get_linkable_groups(filelist->libfiledata); nnames= BLI_linklist_length(names); } filelist->numfiles= nnames + 1; filelist->filelist= malloc(filelist->numfiles * sizeof(*filelist->filelist)); memset(filelist->filelist, 0, filelist->numfiles * sizeof(*filelist->filelist)); filelist->filelist[0].relname= BLI_strdup(".."); filelist->filelist[0].type |= S_IFDIR; for (i=0, l= names; inext) { char *blockname= l->link; filelist->filelist[i + 1].relname= BLI_strdup(blockname); if (idcode) { filelist->filelist[i + 1].type |= S_IFREG; } else { filelist->filelist[i + 1].type |= S_IFDIR; } } if(previews && (nnames != nprevs)) { printf("filelist_from_library: error, found %d items, %d previews\n", nnames, nprevs); } else if(previews) { for (i=0, l= previews; inext) { PreviewImage *img= l->link; if (img) { unsigned int w = img->w[ICON_SIZE_PREVIEW]; unsigned int h = img->h[ICON_SIZE_PREVIEW]; unsigned int *rect = img->rect[ICON_SIZE_PREVIEW]; /* first allocate imbuf for copying preview into it */ if (w > 0 && h > 0 && rect) { ima = IMB_allocImBuf(w, h, 32, IB_rect); memcpy(ima->rect, rect, w*h*sizeof(unsigned int)); filelist->filelist[i + 1].image = ima; filelist->filelist[i + 1].flags = IMAGEFILE; } } } } BLI_linklist_free(names, free); if (previews) BLI_linklist_free(previews, BKE_previewimg_freefunc); filelist_sort(filelist, FILE_SORT_ALPHA); BLI_strncpy(G.main->name, filename, sizeof(filename)); // prevent G.main->name to change filelist->filter = 0; filelist_filter(filelist); } void filelist_hideparent(struct FileList* filelist, short hide) { filelist->hide_parent = hide; } void filelist_from_main(struct FileList *filelist) { ID *id; struct direntry *files, *firstlib = NULL; ListBase *lb; int a, fake, idcode, ok, totlib, totbl; // filelist->type = FILE_MAIN; // XXXXX TODO: add modes to filebrowser if(filelist->dir[0]=='/') filelist->dir[0]= 0; if(filelist->dir[0]) { idcode= groupname_to_code(filelist->dir); if(idcode==0) filelist->dir[0]= 0; } if( filelist->dir[0]==0) { /* make directories */ filelist->numfiles= 24; filelist->filelist= (struct direntry *)malloc(filelist->numfiles * sizeof(struct direntry)); for(a=0; anumfiles; a++) { memset( &(filelist->filelist[a]), 0 , sizeof(struct direntry)); filelist->filelist[a].type |= S_IFDIR; } filelist->filelist[0].relname= BLI_strdup(".."); filelist->filelist[2].relname= BLI_strdup("Scene"); filelist->filelist[3].relname= BLI_strdup("Object"); filelist->filelist[4].relname= BLI_strdup("Mesh"); filelist->filelist[5].relname= BLI_strdup("Curve"); filelist->filelist[6].relname= BLI_strdup("Metaball"); filelist->filelist[7].relname= BLI_strdup("Material"); filelist->filelist[8].relname= BLI_strdup("Texture"); filelist->filelist[9].relname= BLI_strdup("Image"); filelist->filelist[10].relname= BLI_strdup("Ika"); filelist->filelist[11].relname= BLI_strdup("Wave"); filelist->filelist[12].relname= BLI_strdup("Lattice"); filelist->filelist[13].relname= BLI_strdup("Lamp"); filelist->filelist[14].relname= BLI_strdup("Camera"); filelist->filelist[15].relname= BLI_strdup("Ipo"); filelist->filelist[16].relname= BLI_strdup("World"); filelist->filelist[17].relname= BLI_strdup("Screen"); filelist->filelist[18].relname= BLI_strdup("VFont"); filelist->filelist[19].relname= BLI_strdup("Text"); filelist->filelist[20].relname= BLI_strdup("Armature"); filelist->filelist[21].relname= BLI_strdup("Action"); filelist->filelist[22].relname= BLI_strdup("NodeTree"); filelist->filelist[23].relname= BLI_strdup("Speaker"); filelist_sort(filelist, FILE_SORT_ALPHA); } else { /* make files */ idcode= groupname_to_code(filelist->dir); lb= which_libbase(G.main, idcode ); if(lb == NULL) return; id= lb->first; filelist->numfiles= 0; while(id) { if (!filelist->hide_dot || id->name[2] != '.') { filelist->numfiles++; } id= id->next; } /* XXXXX TODO: if databrowse F4 or append/link filelist->hide_parent has to be set */ if (!filelist->hide_parent) filelist->numfiles+= 1; filelist->filelist= filelist->numfiles > 0 ? (struct direntry *)malloc(filelist->numfiles * sizeof(struct direntry)) : NULL; files = filelist->filelist; if (!filelist->hide_parent) { memset( &(filelist->filelist[0]), 0 , sizeof(struct direntry)); filelist->filelist[0].relname= BLI_strdup(".."); filelist->filelist[0].type |= S_IFDIR; files++; } id= lb->first; totlib= totbl= 0; while(id) { ok = 1; if(ok) { if (!filelist->hide_dot || id->name[2] != '.') { memset( files, 0 , sizeof(struct direntry)); if(id->lib==NULL) files->relname= BLI_strdup(id->name+2); else { files->relname= MEM_mallocN(FILE_MAXDIR+FILE_MAXFILE+32, "filename for lib"); sprintf(files->relname, "%s | %s", id->lib->name, id->name+2); } files->type |= S_IFREG; #if 0 // XXXXX TODO show the selection status of the objects if(!filelist->has_func) { /* F4 DATA BROWSE */ if(idcode==ID_OB) { if( ((Object *)id)->flag & SELECT) files->selflag |= SELECTED_FILE; } else if(idcode==ID_SCE) { if( ((Scene *)id)->r.scemode & R_BG_RENDER) files->selflag |= SELECTED_FILE; } } #endif files->nr= totbl+1; files->poin= id; fake= id->flag & LIB_FAKEUSER; if(idcode == ID_MA || idcode == ID_TE || idcode == ID_LA || idcode == ID_WO || idcode == ID_IM) { files->flags |= IMAGEFILE; } if(id->lib && fake) sprintf(files->extra, "LF %d", id->us); else if(id->lib) sprintf(files->extra, "L %d", id->us); else if(fake) sprintf(files->extra, "F %d", id->us); else sprintf(files->extra, " %d", id->us); if(id->lib) { if(totlib==0) firstlib= files; totlib++; } files++; } totbl++; } id= id->next; } /* only qsort of library blocks */ if(totlib>1) { qsort(firstlib, totlib, sizeof(struct direntry), compare_name); } } filelist->filter = 0; filelist_filter(filelist); } static void thumbnail_joblist_free(ThumbnailJob *tj) { FileImage* limg = tj->loadimages.first; /* free the images not yet copied to the filelist -> these will get freed with the filelist */ for( ; limg; limg= limg->next) { if ((limg->img) && (!limg->done)) { IMB_freeImBuf(limg->img); } } BLI_freelistN(&tj->loadimages); } static void thumbnails_startjob(void *tjv, short *stop, short *do_update, float *UNUSED(progress)) { ThumbnailJob *tj= tjv; FileImage* limg = tj->loadimages.first; tj->stop= stop; tj->do_update= do_update; while ( (*stop==0) && (limg) ) { if ( limg->flags & IMAGEFILE ) { limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_IMAGE); } else if ( limg->flags & BLENDERFILE ) { limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_BLEND); } else if ( limg->flags & MOVIEFILE ) { limg->img = IMB_thumb_manage(limg->path, THB_NORMAL, THB_SOURCE_MOVIE); if (!limg->img) { /* remember that file can't be loaded via IMB_open_anim */ limg->flags &= ~MOVIEFILE; limg->flags |= MOVIEFILE_ICON; } } *do_update = 1; PIL_sleep_ms(10); limg = limg->next; } } static void thumbnails_update(void *tjv) { ThumbnailJob *tj= tjv; if (tj->filelist && tj->filelist->filelist) { FileImage* limg = tj->loadimages.first; while (limg) { if (!limg->done && limg->img) { tj->filelist->filelist[limg->index].image = limg->img; /* update flag for movie files where thumbnail can't be created */ if (limg->flags & MOVIEFILE_ICON) { tj->filelist->filelist[limg->index].flags &= ~MOVIEFILE; tj->filelist->filelist[limg->index].flags |= MOVIEFILE_ICON; } limg->done=1; } limg = limg->next; } } } static void thumbnails_free(void *tjv) { ThumbnailJob *tj= tjv; thumbnail_joblist_free(tj); MEM_freeN(tj); } void thumbnails_start(struct FileList* filelist, const struct bContext* C) { wmJob *steve; ThumbnailJob *tj; int idx; /* prepare job data */ tj= MEM_callocN(sizeof(ThumbnailJob), "thumbnails\n"); tj->filelist = filelist; for (idx = 0; idx < filelist->numfiles;idx++) { if (!filelist->filelist[idx].image) { if ( (filelist->filelist[idx].flags & (IMAGEFILE|MOVIEFILE|BLENDERFILE)) ) { FileImage* limg = MEM_callocN(sizeof(struct FileImage), "loadimage"); BLI_strncpy(limg->path, filelist->filelist[idx].path, FILE_MAX); limg->index= idx; limg->flags= filelist->filelist[idx].flags; BLI_addtail(&tj->loadimages, limg); } } } BKE_reports_init(&tj->reports, RPT_PRINT); /* setup job */ steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), filelist, "Thumbnails", 0); WM_jobs_customdata(steve, tj, thumbnails_free); WM_jobs_timer(steve, 0.5, NC_WINDOW, NC_WINDOW); WM_jobs_callbacks(steve, thumbnails_startjob, NULL, thumbnails_update, NULL); /* start the job */ WM_jobs_start(CTX_wm_manager(C), steve); } void thumbnails_stop(struct FileList* filelist, const struct bContext* C) { WM_jobs_kill(CTX_wm_manager(C), filelist, NULL); } int thumbnails_running(struct FileList* filelist, const struct bContext* C) { return WM_jobs_test(CTX_wm_manager(C), filelist); }