[Bf-blender-cvs] [950f2c8] master: SpaceFile: Refactor sorting and filtering of filelist.

Bastien Montagne noreply at git.blender.org
Thu Jan 1 11:24:53 CET 2015


Commit: 950f2c84a3fd946d42d305cfc40b6827fc572aab
Author: Bastien Montagne
Date:   Wed Dec 31 20:13:21 2014 +0100
Branches: master
https://developer.blender.org/rB950f2c84a3fd946d42d305cfc40b6827fc572aab

SpaceFile: Refactor sorting and filtering of filelist.

New code shall be more easy to maintain and extend.
Sorting is now handled quite the same as filtering, and all filtering parameters
are now packed into a sub-struct to help extending it later.

Also done some optimizations in filelist refresh, and sorting/filtering area.
Now we should avoid re-sorting and re-filtering too often, also removed
calls to those in read_xxx funcs.

Note thumbnail job is still started basically on each call to `file_refresh()`,
will be addressed in next commit.

===================================================================

M	source/blender/editors/space_file/filelist.c
M	source/blender/editors/space_file/filelist.h
M	source/blender/editors/space_file/space_file.c

===================================================================

diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index deececc..3609541 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -204,27 +204,38 @@ typedef struct FileImage {
 	ImBuf *img;
 } FileImage;
 
+typedef struct FileListFilter {
+	bool hide_dot;
+	bool hide_parent;
+	unsigned int filter;
+	char filter_glob[64];
+} FileListFilter;
+
 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;
+
+	bool changed;
+
+	short sort;
+	bool need_sorting;
+
+	FileListFilter filter_data;
+	int *fidx;  /* Also used to detect when we need to filter! */
+	int numfiltered;
 
 	struct BlendHandle *libfiledata;
-	short hide_parent;
 
 	void (*readf)(struct FileList *);
-	bool (*filterf)(struct direntry *file, const char *dir, unsigned int filter, short hide_dot);
-
+	bool (*filterf)(struct direntry *, const char *, FileListFilter *);
 } FileList;
 
+#define FILENAME_IS_BREADCRUMBS(_n) \
+	(((_n)[0] == '.' && (_n)[1] == '\0') || ((_n)[0] == '.' && (_n)[1] == '.' && (_n)[2] == '\0'))
+
 #define SPECIAL_IMG_SIZE 48
 #define SPECIAL_IMG_ROWS 4
 #define SPECIAL_IMG_COLS 4
@@ -253,6 +264,8 @@ static void filelist_read_main(struct FileList *filelist);
 static void filelist_read_library(struct FileList *filelist);
 static void filelist_read_dir(struct FileList *filelist);
 
+static void filelist_filter_clear(FileList *filelist);
+
 /* ********** Sort helpers ********** */
 
 static bool compare_is_directory(const struct direntry *entry)
@@ -399,39 +412,57 @@ static int compare_extension(const void *a1, const void *a2)
 	return (BLI_strcasecmp(sufix1, sufix2));
 }
 
-void filelist_sort(struct FileList *filelist, short sort)
+bool filelist_need_sorting(struct FileList *filelist)
 {
-	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);
-			break;
+	return filelist->need_sorting && (filelist->sort != FILE_SORT_NONE);
+}
+
+void filelist_sort(struct FileList *filelist)
+{
+	if (filelist_need_sorting(filelist)) {
+		filelist->need_sorting = false;
+
+		switch (filelist->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);
+				break;
+			case FILE_SORT_NONE:  /* Should never reach this point! */
+			default:
+				BLI_assert(0);
+				return;
+		}
+
+		filelist_filter_clear(filelist);
 	}
+}
 
-	filelist_filter(filelist);
+void filelist_setsorting(struct FileList *filelist, const short sort)
+{
+	if (filelist->sort != sort) {
+		filelist->sort = sort;
+		filelist->need_sorting = true;
+	}
 }
 
 /* ********** Filter helpers ********** */
 
-static bool is_hidden_file(const char *filename, short hide_dot)
+static bool is_hidden_file(const char *filename, FileListFilter *filter)
 {
 	bool is_hidden = false;
 
-	if (hide_dot) {
-		if (filename[0] == '.' && filename[1] != '.' && filename[1] != 0) {
+	if (filter->hide_dot) {
+		if (filename[0] == '.' && filename[1] != '.' && filename[1] != '\0') {
 			is_hidden = true; /* ignore .file */
 		}
-		else if (((filename[0] == '.') && (filename[1] == 0))) {
-			is_hidden = true; /* ignore . */
-		}
 		else {
 			int len = strlen(filename);
 			if ((len > 0) && (filename[len - 1] == '~')) {
@@ -439,96 +470,109 @@ static bool is_hidden_file(const char *filename, short hide_dot)
 			}
 		}
 	}
-	else {
-		if (((filename[0] == '.') && (filename[1] == 0))) {
-			is_hidden = true; /* ignore . */
+	if (!is_hidden && filter->hide_parent) {
+		if (filename[0] == '.' && filename[1] == '.' && filename[2] == '\0') {
+			is_hidden = true; /* ignore .. */
 		}
 	}
+	if (!is_hidden && ((filename[0] == '.') && (filename[1] == '\0'))) {
+		is_hidden = true; /* ignore . */
+	}
 	return is_hidden;
 }
 
-static bool is_filtered_file(struct direntry *file, const char *UNUSED(dir), unsigned int filter, short hide_dot)
+static bool is_filtered_file(struct direntry *file, const char *UNUSED(root), FileListFilter *filter)
 {
-	bool is_filtered = false;
-	if (filter) {
-		if (file->flags & filter) {
-			is_filtered = true;
+	bool is_filtered = !is_hidden_file(file->relname, filter);
+
+	if (is_filtered && filter->filter && !FILENAME_IS_BREADCRUMBS(file->relname)) {
+		if ((file->type & S_IFDIR) && !(filter->filter & FOLDERFILE)) {
+			is_filtered = false;
 		}
-		else if (file->type & S_IFDIR) {
-			if (filter & FOLDERFILE) {
-				is_filtered = true;
-			}
+		if (!(file->type & S_IFDIR) && !(file->flags & filter->filter)) {
+			is_filtered = false;
 		}
 	}
-	else {
-		is_filtered = true;
-	}
-	return is_filtered && !is_hidden_file(file->relname, hide_dot);
+
+	return is_filtered;
 }
 
-static bool is_filtered_lib(struct direntry *file, const char *dir, unsigned int filter, short hide_dot)
+static bool is_filtered_lib(struct direntry *file, const char *root, FileListFilter *filter)
 {
-	bool is_filtered = false;
-	char tdir[FILE_MAX], tgroup[BLO_GROUP_MAX];
-	if (BLO_is_a_library(dir, tdir, tgroup)) {
-		is_filtered = !is_hidden_file(file->relname, hide_dot);
+	bool is_filtered = !is_hidden_file(file->relname, filter);
+	char dir[FILE_MAXDIR], group[BLO_GROUP_MAX];
+
+	if (BLO_is_a_library(root, dir, group)) {
+		is_filtered = !is_hidden_file(file->relname, filter);
 	}
 	else {
-		is_filtered = is_filtered_file(file, dir, filter, hide_dot);
+		is_filtered = is_filtered_file(file, root, filter);
 	}
 
 	return is_filtered;
 }
 
-static bool is_filtered_main(struct direntry *file, const char *UNUSED(dir), unsigned int UNUSED(filter), short hide_dot)
+static bool is_filtered_main(struct direntry *file, const char *UNUSED(dir), FileListFilter *filter)
+{
+	return !is_hidden_file(file->relname, filter);
+}
+
+static void filelist_filter_clear(FileList *filelist)
 {
-	return !is_hidden_file(file->relname, hide_dot);
+	MEM_SAFE_FREE(filelist->fidx);
+	filelist->numfiltered = 0;
 }
 
 void filelist_filter(FileList *filelist)
 {
 	int num_filtered = 0;
-	int i, j;
+	int *fidx_tmp;
+	int i;
 
-	if (!filelist->filelist)
+	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;
+		/* Assume it has already been filtered, nothing else to do! */
+		return;
 	}
-	filelist->fidx = (int *)MEM_callocN(num_filtered * sizeof(int), "filteridx");
-	filelist->numfiltered = num_filtered;
 
-	for (i = 0, j = 0; i < filelist->numfiles; ++i) {
+	fidx_tmp = MEM_mallocN(sizeof(*fidx_tmp) * (size_t)filelist->numfiles, __func__);
+
+	/* Filter remap & count how many files are left after filter in a single loop. */
+	for (i = 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;
+
+		if (filelist->filterf(file, filelist->dir, &filelist->filter_data)) {
+			fidx_tmp[num_filtered++] = i;
 		}
 	}
-}
 
-void filelist_hidedot(struct FileList *filelist, short hide)
-{
-	filelist->hide_dot = hide;
-}
+	/* Note: maybe we could even accept filelist->fidx to be filelist->numfiles -len allocated? */
+	filelist->fidx = (int *)MEM_mallocN(sizeof(*filelist->fidx) * (size_t)num_filtered, __func__);
+	memcpy(filelist->fidx, fidx_tmp, sizeof(*filelist->fidx) * (size_t)num_filtered);
+	filelist->numfiltered = num_filtered;
 
-void filelist_setfilter(struct FileList *filelist, unsigned int filter)
-{
-	filelist->filter = filter;
+	MEM_freeN(fidx_tmp);
 }
 
-void filelist_setfilter_types(struct FileList *filelist, const char *filter_glob)
+void filelist_setfilter_options(FileList *filelist, const bool hide_dot, const bool hide_parent,
+                                const unsigned int filter, const char *filter_glob)
 {
-	BLI_strncpy(filelist->filter_glob, filter_glob, sizeof(filelist->filter_glob));
+	if ((filelist->filter_data.hide_dot != hide_dot) ||
+	    (filelist->filter_data.hide_parent != hide_parent) ||
+	    (filelist->filter_data.filter != filter) ||
+	    (!STREQ(filelist->filter_data.filter_glob, filter_glob)))
+	{
+		filelist->filter_data.hide_dot = hide_dot;
+		filelist->filter_data.hide_parent = hide_parent;
+
+		filelist->filter_data.filter = filter;
+		BLI_strncpy(filelist->filter_data.filter_glob, filter_glob, sizeof(filelist->filter_data.filter_glob));
+
+		filelist_filter_clear(filelist);
+	}
 }
 
 /* ********** Icon/image helpers ********** */
@@ -683,18 +727,16 @@ void filelist_free(struct FileList *filelist)
 		return;
 	}
 	
-	if (filelist->fidx) {
-		MEM_freeN(filelist->fidx);
-		filelist->fidx = NULL;
-	}
+	MEM_SAFE_FREE(filelist->fidx);
+	filelist->numfiltered = 0;
+	memset(&filelist->filter_data, 0, sizeof(filelist->filter_data));
+
+	filelist->need_sorting = false;
+	filelist->sort = FILE_SORT_NONE;
 
 	BLI_free_filelist(filelist->filelist, filelist->numfiles);
 	filelist->numfiles = 0;
 	filelist->filelist = NULL;
-	filelist->filter = 0;
-	filelist->filter_glob[0] = '\0';
-	filelist->numfiltered = 0;
-	filelist->h

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list