Blender V5.0
filelist_sort.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2007 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "AS_asset_catalog.hh"
10#include "AS_asset_library.hh"
12
13#include "BLI_listbase.h"
14#include "BLI_path_utils.hh"
15#include "BLI_string.h"
16
17#include "../filelist.hh"
18#include "filelist_intern.hh"
19
22};
23
24static int compare_apply_inverted(int val, const FileSortData *sort_data)
25{
26 return sort_data->inverted ? -val : val;
27}
28
44static int compare_tiebreaker(const FileListInternEntry *entry1, const FileListInternEntry *entry2)
45{
46 /* Case 1. */
47 {
48 const int order = BLI_strcasecmp_natural(entry1->name, entry2->name);
49 if (order) {
50 return order;
51 }
52 }
53
54 /* Case 2. */
55 if (entry1->local_data.id && entry2->local_data.id) {
56 if (entry1->blentype < entry2->blentype) {
57 return -1;
58 }
59 if (entry1->blentype > entry2->blentype) {
60 return 1;
61 }
62 }
63 /* Case 3. */
64 {
65 if (entry1->local_data.id && !entry2->local_data.id) {
66 return -1;
67 }
68 if (!entry1->local_data.id && entry2->local_data.id) {
69 return 1;
70 }
71 }
72
73 return 0;
74}
75
81 const FileListInternEntry *entry2)
82{
83 /* type is equal to stat.st_mode */
84
85 if (entry1->typeflag & FILE_TYPE_DIR) {
86 if (entry2->typeflag & FILE_TYPE_DIR) {
87 /* If both entries are tagged as dirs, we make a 'sub filter' that shows first the real dirs,
88 * then libraries (.blend files), then categories in libraries. */
89 if (entry1->typeflag & FILE_TYPE_BLENDERLIB) {
90 if (!(entry2->typeflag & FILE_TYPE_BLENDERLIB)) {
91 return 1;
92 }
93 }
94 else if (entry2->typeflag & FILE_TYPE_BLENDERLIB) {
95 return -1;
96 }
99 return 1;
100 }
101 }
102 else if (entry2->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) {
103 return -1;
104 }
105 }
106 else {
107 return -1;
108 }
109 }
110 else if (entry2->typeflag & FILE_TYPE_DIR) {
111 return 1;
112 }
113
114 /* make sure "." and ".." are always first */
115 if (FILENAME_IS_CURRENT(entry1->relpath)) {
116 return -1;
117 }
118 if (FILENAME_IS_CURRENT(entry2->relpath)) {
119 return 1;
120 }
121 if (FILENAME_IS_PARENT(entry1->relpath)) {
122 return -1;
123 }
124 if (FILENAME_IS_PARENT(entry2->relpath)) {
125 return 1;
126 }
127
128 return 0;
129}
130
131static int compare_name(void *user_data, const void *a1, const void *a2)
132{
133 const FileListInternEntry *entry1 = static_cast<const FileListInternEntry *>(a1);
134 const FileListInternEntry *entry2 = static_cast<const FileListInternEntry *>(a2);
135 const FileSortData *sort_data = static_cast<const FileSortData *>(user_data);
136
137 int ret;
138 if ((ret = compare_direntry_generic(entry1, entry2))) {
139 return ret;
140 }
141
142 return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
143}
144
145static int compare_date(void *user_data, const void *a1, const void *a2)
146{
147 const FileListInternEntry *entry1 = static_cast<const FileListInternEntry *>(a1);
148 const FileListInternEntry *entry2 = static_cast<const FileListInternEntry *>(a2);
149 const FileSortData *sort_data = static_cast<const FileSortData *>(user_data);
150 int64_t time1, time2;
151
152 int ret;
153 if ((ret = compare_direntry_generic(entry1, entry2))) {
154 return ret;
155 }
156
157 time1 = int64_t(entry1->st.st_mtime);
158 time2 = int64_t(entry2->st.st_mtime);
159 if (time1 < time2) {
160 return compare_apply_inverted(1, sort_data);
161 }
162 if (time1 > time2) {
163 return compare_apply_inverted(-1, sort_data);
164 }
165
166 return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
167}
168
169static int compare_size(void *user_data, const void *a1, const void *a2)
170{
171 const FileListInternEntry *entry1 = static_cast<const FileListInternEntry *>(a1);
172 const FileListInternEntry *entry2 = static_cast<const FileListInternEntry *>(a2);
173 const FileSortData *sort_data = static_cast<const FileSortData *>(user_data);
174 uint64_t size1, size2;
175 int ret;
176
177 if ((ret = compare_direntry_generic(entry1, entry2))) {
178 return ret;
179 }
180
181 size1 = entry1->st.st_size;
182 size2 = entry2->st.st_size;
183 if (size1 < size2) {
184 return compare_apply_inverted(1, sort_data);
185 }
186 if (size1 > size2) {
187 return compare_apply_inverted(-1, sort_data);
188 }
189
190 return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
191}
192
193static int compare_extension(void *user_data, const void *a1, const void *a2)
194{
195 const FileListInternEntry *entry1 = static_cast<const FileListInternEntry *>(a1);
196 const FileListInternEntry *entry2 = static_cast<const FileListInternEntry *>(a2);
197 const FileSortData *sort_data = static_cast<const FileSortData *>(user_data);
198 int ret;
199
200 if ((ret = compare_direntry_generic(entry1, entry2))) {
201 return ret;
202 }
203
204 if ((entry1->typeflag & FILE_TYPE_BLENDERLIB) && !(entry2->typeflag & FILE_TYPE_BLENDERLIB)) {
205 return -1;
206 }
207 if (!(entry1->typeflag & FILE_TYPE_BLENDERLIB) && (entry2->typeflag & FILE_TYPE_BLENDERLIB)) {
208 return 1;
209 }
210 if ((entry1->typeflag & FILE_TYPE_BLENDERLIB) && (entry2->typeflag & FILE_TYPE_BLENDERLIB)) {
211 if ((entry1->typeflag & FILE_TYPE_DIR) && !(entry2->typeflag & FILE_TYPE_DIR)) {
212 return 1;
213 }
214 if (!(entry1->typeflag & FILE_TYPE_DIR) && (entry2->typeflag & FILE_TYPE_DIR)) {
215 return -1;
216 }
217 if (entry1->blentype < entry2->blentype) {
218 return compare_apply_inverted(-1, sort_data);
219 }
220 if (entry1->blentype > entry2->blentype) {
221 return compare_apply_inverted(1, sort_data);
222 }
223 }
224 else {
225 const char *sufix1, *sufix2;
226
227 if (!(sufix1 = strstr(entry1->relpath, ".blend.gz"))) {
228 sufix1 = strrchr(entry1->relpath, '.');
229 }
230 if (!(sufix2 = strstr(entry2->relpath, ".blend.gz"))) {
231 sufix2 = strrchr(entry2->relpath, '.');
232 }
233 if (!sufix1) {
234 sufix1 = "";
235 }
236 if (!sufix2) {
237 sufix2 = "";
238 }
239
240 if ((ret = BLI_strcasecmp(sufix1, sufix2))) {
241 return compare_apply_inverted(ret, sort_data);
242 }
243 }
244
245 return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
246}
247
248static int compare_asset_catalog(void *user_data, const void *a1, const void *a2)
249{
250 using namespace blender;
251
252 const FileListInternEntry *entry1 = static_cast<const FileListInternEntry *>(a1);
253 const FileListInternEntry *entry2 = static_cast<const FileListInternEntry *>(a2);
254 const FileSortData *sort_data = static_cast<const FileSortData *>(user_data);
255 const asset_system::AssetRepresentation *asset1 = entry1->get_asset();
256 const asset_system::AssetRepresentation *asset2 = entry2->get_asset();
257
258 /* Order non-assets. */
259 if (asset1 && !asset2) {
260 return 1;
261 }
262 if (!asset1 && asset2) {
263 return -1;
264 }
265 if (!asset1 && !asset2) {
266 if (int order = compare_direntry_generic(entry1, entry2); order) {
267 return compare_apply_inverted(order, sort_data);
268 }
269
270 return compare_apply_inverted(compare_tiebreaker(entry1, entry2), sort_data);
271 }
272
273 const asset_system::AssetLibrary &asset_library1 = asset1->owner_asset_library();
274 const asset_system::AssetLibrary &asset_library2 = asset2->owner_asset_library();
275
276 const asset_system::AssetCatalog *catalog1 = asset_library1.catalog_service().find_catalog(
277 asset1->get_metadata().catalog_id);
278 const asset_system::AssetCatalog *catalog2 = asset_library2.catalog_service().find_catalog(
279 asset2->get_metadata().catalog_id);
280
281 /* Order by catalog. Always keep assets without catalog last. */
282 int order = 0;
283
284 if (catalog1 && !catalog2) {
285 order = 1;
286 }
287 else if (!catalog1 && catalog2) {
288 order = -1;
289 }
290 else if (catalog1 && catalog2) {
291 order = BLI_strcasecmp_natural(catalog1->path.c_str(), catalog2->path.c_str());
292 }
293
294 if (!order) {
295 /* Order by name. */
296 order = compare_tiebreaker(entry1, entry2);
297 if (!order) {
298 /* Order by library name. */
299 order = BLI_strcasecmp_natural(asset_library1.name().c_str(), asset_library2.name().c_str());
300 }
301 }
302
303 return compare_apply_inverted(order, sort_data);
304}
305
306void filelist_sort(FileList *filelist)
307{
308 if (filelist->flags & FL_NEED_SORTING) {
309 int (*sort_cb)(void *, const void *, const void *) = nullptr;
310
311 switch (filelist->sort) {
312 case FILE_SORT_ALPHA:
313 sort_cb = compare_name;
314 break;
315 case FILE_SORT_TIME:
316 sort_cb = compare_date;
317 break;
318 case FILE_SORT_SIZE:
319 sort_cb = compare_size;
320 break;
322 sort_cb = compare_extension;
323 break;
325 sort_cb = compare_asset_catalog;
326 break;
328 default:
329 BLI_assert(0);
330 break;
331 }
332
333 FileSortData sort_data{};
334 sort_data.inverted = (filelist->flags & FL_SORT_INVERT) != 0;
335 BLI_listbase_sort_r(&filelist->filelist_intern.entries, sort_cb, &sort_data);
336
338 filelist->flags &= ~FL_NEED_SORTING;
339 }
340}
341
342void filelist_setsorting(FileList *filelist, const short sort, bool invert_sort)
343{
344 const bool was_invert_sort = filelist->flags & FL_SORT_INVERT;
345
346 if ((filelist->sort != sort) || (was_invert_sort != invert_sort)) {
347 filelist->sort = sort;
348 filelist->flags |= FL_NEED_SORTING;
349 filelist->flags = invert_sort ? (filelist->flags | FL_SORT_INVERT) :
350 (filelist->flags & ~FL_SORT_INVERT);
351 }
352}
Main runtime representation of an asset.
#define BLI_assert(a)
Definition BLI_assert.h:46
void void void BLI_listbase_sort_r(ListBase *listbase, int(*cmp)(void *, const void *, const void *), void *thunk) ATTR_NONNULL(1
#define FILENAME_IS_CURRENT(_n)
#define FILENAME_IS_PARENT(_n)
int char char int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
int char char int int int BLI_strcasecmp_natural(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
@ FILE_SORT_ASSET_CATALOG
@ FILE_SORT_DEFAULT
@ FILE_SORT_ALPHA
@ FILE_SORT_TIME
@ FILE_SORT_EXTENSION
@ FILE_SORT_SIZE
@ FILE_TYPE_BLENDER
@ FILE_TYPE_BLENDER_BACKUP
@ FILE_TYPE_BLENDERLIB
@ FILE_TYPE_DIR
long long int int64_t
unsigned long long int uint64_t
static DBVT_INLINE btDbvtNode * sort(btDbvtNode *n, btDbvtNode *&r)
Definition btDbvt.cpp:418
constexpr const char * c_str() const
AssetCatalog * find_catalog(CatalogID catalog_id) const
AssetCatalogService & catalog_service() const
void filelist_tag_needs_filtering(FileList *filelist)
@ FL_NEED_SORTING
@ FL_SORT_INVERT
static int compare_apply_inverted(int val, const FileSortData *sort_data)
static int compare_tiebreaker(const FileListInternEntry *entry1, const FileListInternEntry *entry2)
static int compare_asset_catalog(void *user_data, const void *a1, const void *a2)
static int compare_extension(void *user_data, const void *a1, const void *a2)
static int compare_size(void *user_data, const void *a1, const void *a2)
void filelist_setsorting(FileList *filelist, const short sort, bool invert_sort)
static int compare_name(void *user_data, const void *a1, const void *a2)
static int compare_direntry_generic(const FileListInternEntry *entry1, const FileListInternEntry *entry2)
static int compare_date(void *user_data, const void *a1, const void *a2)
void filelist_sort(FileList *filelist)
return ret
struct bUUID catalog_id
struct FileListInternEntry::@364374371172256277004264162343271025307331240316 local_data
eFileSel_File_Types typeflag
blender::asset_system::AssetRepresentation * get_asset() const
FileListIntern filelist_intern