This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/editors/space_file/filelist.c

1343 lines
35 KiB
C

/*
* $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 <stdlib.h>
#include <math.h>
#include <string.h>
#ifndef WIN32
#include <unistd.h>
#else
#include <io.h>
#include <direct.h>
#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; y<SPECIAL_IMG_ROWS; y++) {
for (x=0; x<SPECIAL_IMG_COLS; x++) {
int tile = SPECIAL_IMG_COLS*y + x;
if (tile < SPECIAL_IMG_MAX) {
ibuf = IMB_allocImBuf(SPECIAL_IMG_SIZE, SPECIAL_IMG_SIZE, 32, IB_rect);
for (k=0; k<SPECIAL_IMG_SIZE; k++) {
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));
}
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(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(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; num<filelist->numfiles; 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; num<filelist->numfiles; 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; i<nnames; i++, l= l->next) {
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; i<nnames; i++, l= l->next) {
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; a<filelist->numfiles; 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);
}