Skip to content

Commit 5ac3ec2

Browse files
committed
ScriptAPI: FillDirList can sort files by name or time
1 parent eb472e1 commit 5ac3ec2

File tree

8 files changed

+287
-43
lines changed

8 files changed

+287
-43
lines changed

Common/core/assetmanager.cpp

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
#include "core/assetmanager.h"
1515
#include <algorithm>
1616
#include <regex>
17-
#include "util/directory.h"
1817
#include "util/file.h"
1918
#include "util/multifilelib.h"
2019
#include "util/path.h"
@@ -235,6 +234,58 @@ void AssetManager::FindAssets(std::vector<String> &assets, const String &wildcar
235234
assets.erase(std::unique(assets.begin(), assets.end(), StrEqNoCase()), assets.end());
236235
}
237236

237+
void AssetManager::FindAssets(std::vector<FileEntry> &assets, const String &wildcard,
238+
const String &filter) const
239+
{
240+
// TODO: consider refactoring and merging this with FindAssets(std::vector<String> &assets);
241+
// there are two separate methods now, because retrieving filename only is faster than
242+
// full FileEntry (may require extra system calls on certain platforms).
243+
244+
String pattern = StrUtil::WildcardToRegex(wildcard);
245+
const std::regex regex(pattern.GetCStr(), std::regex_constants::icase);
246+
std::cmatch mr;
247+
248+
std::vector<FileEntry> lib_fileents;
249+
for (const auto *lib : _activeLibs)
250+
{
251+
if (!lib->TestFilter(filter)) continue; // filter does not match
252+
253+
lib_fileents.clear();
254+
if (IsAssetLibDir(lib))
255+
{
256+
// FIXME: do basedir/getparent(wildcard), getfilename(wildcard) instead?
257+
// because FindFile does not support subdirs in wildcard!!
258+
for (FindFile ff = FindFile::OpenFiles(lib->BaseDir, wildcard);
259+
!ff.AtEnd(); ff.Next())
260+
lib_fileents.push_back(ff.GetEntry());
261+
}
262+
else
263+
{
264+
time_t lib_time = File::GetFileTime(lib->RealLibFiles[0]);
265+
for (const auto &a : lib->AssetInfos)
266+
{
267+
if (std::regex_match(a.FileName.GetCStr(), mr, regex))
268+
lib_fileents.push_back(FileEntry(a.FileName, true, false, lib_time));
269+
}
270+
}
271+
272+
// We have to filter out matching entries and keep only ones that were found first by lib priority
273+
if (assets.empty())
274+
{
275+
assets = std::move(lib_fileents);
276+
}
277+
else
278+
{
279+
for (const auto &fe : lib_fileents)
280+
{
281+
auto it_place = std::upper_bound(assets.begin(), assets.end(), fe, FileEntryCmpByNameCI());
282+
if (it_place != assets.begin() && (it_place - 1)->Name.CompareNoCase(fe.Name) != 0)
283+
assets.insert(it_place, fe);
284+
}
285+
}
286+
}
287+
}
288+
238289
AssetError AssetManager::RegisterAssetLib(const String &path, AssetLibEx *&out_lib)
239290
{
240291
// Test for a directory

Common/core/assetmanager.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include <memory>
4141
#include <unordered_map>
4242
#include "core/asset.h"
43+
#include "util/directory.h"
4344
#include "util/stream.h"
4445
#include "util/string_types.h"
4546

@@ -131,6 +132,11 @@ class AssetManager
131132
// TODO: variant accepting std::regex instead of wildcard, and replace uses where convenient
132133
void FindAssets(std::vector<String> &assets, const String &wildcard,
133134
const String &filter = "") const;
135+
// Searches in all the registered locations and collects a list of
136+
// FileEntry objects corresponding to assets, using given wildcard pattern.
137+
// NOTE: lib file assets will have their time property equal to lib's time.
138+
void FindAssets(std::vector<FileEntry> &assets, const String &wildcard,
139+
const String &filter = "") const;
134140
// Open asset stream in the given work mode; returns null if asset is not found or cannot be opened
135141
// This method only searches in libraries that do not have any defined filters
136142
std::unique_ptr<Stream> OpenAsset(const String &asset_name) const;

Common/util/directory.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,12 @@ void GetFiles(const String &dir_path, std::vector<String> &files, const String &
135135
files.push_back(ff.Current());
136136
}
137137

138+
void GetFiles(const String &dir_path, std::vector<FileEntry> &files, const String &wildcard)
139+
{
140+
for (FindFile ff = FindFile::OpenFiles(dir_path, wildcard); !ff.AtEnd(); ff.Next())
141+
files.push_back(ff.GetEntry());
142+
}
143+
138144
bool HasAnyFiles(const String &dir_path)
139145
{
140146
return !FindFile::OpenFiles(dir_path).AtEnd();

Common/util/directory.h

Lines changed: 86 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,22 @@ namespace AGS
3131
namespace Common
3232
{
3333

34+
// FileEntry describes a single entry in the filesystem.
35+
struct FileEntry
36+
{
37+
String Name;
38+
// TODO: make flags instead?
39+
bool IsFile = false;
40+
bool IsDir = false;
41+
time_t Time{};
42+
43+
FileEntry() = default;
44+
FileEntry(const String &name, bool is_file, bool is_dir, const time_t &time)
45+
: Name(name), IsFile(is_file), IsDir(is_dir), Time(time) {}
46+
47+
operator bool() const { return !Name.IsEmpty(); }
48+
};
49+
3450
namespace Directory
3551
{
3652
// Creates new directory (if it does not exist)
@@ -49,27 +65,13 @@ namespace Directory
4965
void GetFiles(const String &dir_path, std::vector<String> &files);
5066
// Get list of files found in the given directory using wildcard pattern
5167
void GetFiles(const String &dir_path, std::vector<String> &files, const String &wildcard);
68+
// Get list of file entries in the given directory using wildcard pattern
69+
void GetFiles(const String &dir_path, std::vector<FileEntry> &files, const String &wildcard);
5270
// Tells whether there are any files in the given directory
5371
bool HasAnyFiles(const String &dir_path);
5472
} // namespace Directory
5573

5674

57-
// FileEntry describes a single entry in the filesystem.
58-
struct FileEntry
59-
{
60-
String Name;
61-
// TODO: make flags instead?
62-
bool IsFile = false;
63-
bool IsDir = false;
64-
time_t Time{};
65-
66-
FileEntry() = default;
67-
FileEntry(const String &name, bool is_file, bool is_dir, const time_t &time)
68-
: Name(name), IsFile(is_file), IsDir(is_dir), Time(time) {}
69-
70-
operator bool() const { return !Name.IsEmpty(); }
71-
};
72-
7375
//
7476
// DirectoryIterator iterates entries in the directory.
7577
// The order of iteration is undefined.
@@ -206,6 +208,74 @@ class FindFile
206208
bool _doDirs = false;
207209
};
208210

211+
212+
//
213+
// FileEntry comparators
214+
//
215+
struct FileEntryEqByName
216+
{
217+
bool operator()(const FileEntry &fe1, const FileEntry &fe2) const
218+
{
219+
return fe1.Name == fe2.Name;
220+
}
221+
};
222+
223+
struct FileEntryEqByNameCI
224+
{
225+
bool operator()(const FileEntry &fe1, const FileEntry &fe2) const
226+
{
227+
return fe1.Name.CompareNoCase(fe2.Name) == 0;
228+
}
229+
};
230+
231+
struct FileEntryCmpByName
232+
{
233+
bool operator()(const FileEntry &fe1, const FileEntry &fe2) const
234+
{
235+
return fe1.Name.Compare(fe2.Name) < 0;
236+
}
237+
};
238+
239+
struct FileEntryCmpByNameDsc
240+
{
241+
bool operator()(const FileEntry &fe1, const FileEntry &fe2) const
242+
{
243+
return fe2.Name.Compare(fe1.Name) < 0;
244+
}
245+
};
246+
247+
struct FileEntryCmpByNameCI
248+
{
249+
bool operator()(const FileEntry &fe1, const FileEntry &fe2) const
250+
{
251+
return fe1.Name.CompareNoCase(fe2.Name) < 0;
252+
}
253+
};
254+
255+
struct FileEntryCmpByNameDscCI
256+
{
257+
bool operator()(const FileEntry &fe1, const FileEntry &fe2) const
258+
{
259+
return fe2.Name.CompareNoCase(fe1.Name) < 0;
260+
}
261+
};
262+
263+
struct FileEntryCmpByTime
264+
{
265+
bool operator()(const FileEntry &fe1, const FileEntry &fe2) const
266+
{
267+
return fe1.Time < fe2.Time;
268+
}
269+
};
270+
271+
struct FileEntryCmpByTimeDsc
272+
{
273+
bool operator()(const FileEntry &fe1, const FileEntry &fe2) const
274+
{
275+
return fe2.Time < fe1.Time;
276+
}
277+
};
278+
209279
} // namespace Common
210280
} // namespace AGS
211281

Common/util/string_types.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,15 @@ namespace Common
7070
// Various comparison functors
7171
//
7272

73+
// Test case-sensitive String equality
74+
struct StrEq
75+
{
76+
bool operator()(const String &s1, const String &s2) const
77+
{
78+
return s1 == s2;
79+
}
80+
};
81+
7382
// Test case-insensitive String equality
7483
struct StrEqNoCase
7584
{

Editor/AGS.Editor/Resources/agsdefns.sh

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,20 @@ enum RenderLayer
515515
eRenderLayerRoom = 0x00000008,
516516
eRenderLayerAll = 0xFFFFFFFF
517517
};
518+
519+
enum FileSortStyle
520+
{
521+
eFileSort_None = 0,
522+
eFileSort_Name = 1,
523+
eFileSort_Time = 2
524+
};
525+
526+
enum SortDirection
527+
{
528+
eSortNoDirection = 0,
529+
eSortAscending = 1,
530+
eSortDescending = 2
531+
};
518532
#endif
519533
520534
@@ -1925,7 +1939,7 @@ builtin managed struct ListBox extends GUIControl {
19251939
/// Removes all the items from the list.
19261940
import void Clear();
19271941
/// Fills the list box with all the filenames that match the specified file mask.
1928-
import void FillDirList(const string fileMask);
1942+
import void FillDirList(const string fileMask, FileSortStyle fileSortStyle = eFileSort_Name, SortDirection sortDirection = eSortAscending);
19291943
/// Fills the list box with the current user's saved games in the given range of slots.
19301944
import int FillSaveGameList(int min_slot = 1, int max_slot = 50);
19311945
/// Gets the item index at the specified screen co-ordinates, if they lie within the list box.

0 commit comments

Comments
 (0)