1
|
#include <CtrlLib/CtrlLib.h>
|
2
|
|
3
|
NAMESPACE_UPP
|
4
|
|
5
|
#ifdef GUI_WIN
|
6
|
void AvoidPaintingCheck__();
|
7
|
|
8
|
Image ProcessSHIcon(const SHFILEINFO& info)
|
9
|
{
|
10
|
AvoidPaintingCheck__();
|
11
|
Color c = White();
|
12
|
Image m[2];
|
13
|
for(int i = 0; i < 2; i++) {
|
14
|
ICONINFO iconinfo;
|
15
|
if(!info.hIcon || !GetIconInfo(info.hIcon, &iconinfo))
|
16
|
return Image();
|
17
|
BITMAP bm;
|
18
|
::GetObject((HGDIOBJ)iconinfo.hbmMask, sizeof(BITMAP), (LPVOID)&bm);
|
19
|
Size sz(bm.bmWidth, bm.bmHeight);
|
20
|
ImageDraw iw(sz);
|
21
|
iw.DrawRect(sz, c);
|
22
|
::DrawIconEx(iw.GetHandle(), 0, 0, info.hIcon, 0, 0, 0, NULL, DI_NORMAL|DI_COMPAT);
|
23
|
::DeleteObject(iconinfo.hbmColor);
|
24
|
::DeleteObject(iconinfo.hbmMask);
|
25
|
c = Black();
|
26
|
m[i] = iw;
|
27
|
}
|
28
|
::DestroyIcon(info.hIcon);
|
29
|
return RecreateAlpha(m[0], m[1]);
|
30
|
}
|
31
|
|
32
|
struct FileIconMaker : ImageMaker {
|
33
|
String file;
|
34
|
bool exe;
|
35
|
bool dir;
|
36
|
bool large;
|
37
|
|
38
|
virtual String Key() const {
|
39
|
return file + (exe ? "1" : "0") + (dir ? "1" : "0");
|
40
|
}
|
41
|
|
42
|
virtual Image Make() const {
|
43
|
SHFILEINFO info;
|
44
|
AvoidPaintingCheck__();
|
45
|
SHGetFileInfo(ToSystemCharset(file), dir ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL,
|
46
|
&info, sizeof(info),
|
47
|
SHGFI_ICON|(large ? SHGFI_LARGEICON : SHGFI_SMALLICON)|(exe ? 0 : SHGFI_USEFILEATTRIBUTES));
|
48
|
return ProcessSHIcon(info);
|
49
|
}
|
50
|
};
|
51
|
|
52
|
|
53
|
Image GetFileIcon(const char *path, bool dir, bool force, bool large, bool quick = false)
|
54
|
{
|
55
|
FileIconMaker m;
|
56
|
String ext = GetFileExt(path);
|
57
|
m.exe = false;
|
58
|
m.dir = false;
|
59
|
m.file = path;
|
60
|
m.large = large;
|
61
|
if(force)
|
62
|
m.exe = true;
|
63
|
else
|
64
|
if(dir) {
|
65
|
m.dir = true;
|
66
|
m.exe = true;
|
67
|
}
|
68
|
else
|
69
|
if(ext == ".exe")
|
70
|
m.exe = true;
|
71
|
else
|
72
|
m.file = "x." + ext;
|
73
|
if(quick) {
|
74
|
m.exe = false;
|
75
|
m.file = "x." + ext;
|
76
|
}
|
77
|
return MakeImage(m);
|
78
|
}
|
79
|
|
80
|
#define GETFILEICON_DEFINED
|
81
|
|
82
|
#endif
|
83
|
|
84
|
#if defined(PLATFORM_X11) && !defined(flagNOGTK)
|
85
|
|
86
|
Image GtkThemeIcon(const char *name, bool large);
|
87
|
|
88
|
Image GnomeImage(const char *s, bool large = false)
|
89
|
{
|
90
|
return GtkThemeIcon(String("gnome-") + s, large);
|
91
|
}
|
92
|
|
93
|
Image SystemImage(const char *s, bool large = false)
|
94
|
{
|
95
|
return GtkThemeIcon(s, large);
|
96
|
}
|
97
|
|
98
|
struct ExtToMime {
|
99
|
Index<String> major;
|
100
|
Index<String> minor;
|
101
|
VectorMap<String, dword> map;
|
102
|
|
103
|
void Load(const char *file);
|
104
|
void Refresh();
|
105
|
bool GetMime(const String& ext, String& maj, String& min);
|
106
|
};
|
107
|
|
108
|
void ExtToMime::Load(const char *fn)
|
109
|
{
|
110
|
FileIn in(fn);
|
111
|
if(in)
|
112
|
while(!in.IsEof()) {
|
113
|
String ln = TrimLeft(TrimRight(in.GetLine()));
|
114
|
if(ln[0] != '#') {
|
115
|
int q = ln.Find(':');
|
116
|
if(q >= 0) {
|
117
|
String h = ln.Mid(0, q);
|
118
|
int w = h.Find('/');
|
119
|
if(w >= 0) {
|
120
|
int x = ln.Find("*.", q);
|
121
|
if(x >= 0) {
|
122
|
String ext = ln.Mid(x + 2);
|
123
|
if(ext.GetCount() && map.Find(ext) < 0)
|
124
|
map.Add(ext, MAKELONG(minor.FindAdd(h.Mid(w + 1)), major.FindAdd(h.Mid(0, w))));
|
125
|
}
|
126
|
}
|
127
|
}
|
128
|
}
|
129
|
}
|
130
|
}
|
131
|
|
132
|
void ExtToMime::Refresh()
|
133
|
{
|
134
|
major.Clear();
|
135
|
minor.Clear();
|
136
|
map.Clear();
|
137
|
Load("/usr/local/share/mime/globs");
|
138
|
Load("/usr/share/mime/globs");
|
139
|
}
|
140
|
|
141
|
bool ExtToMime::GetMime(const String& ext, String& maj, String& min)
|
142
|
{
|
143
|
ONCELOCK {
|
144
|
Refresh();
|
145
|
}
|
146
|
int q = map.Find(ext);
|
147
|
if(q < 0)
|
148
|
return false;
|
149
|
dword x = map[q];
|
150
|
maj = major[HIWORD(x)];
|
151
|
min = minor[LOWORD(x)];
|
152
|
return true;
|
153
|
}
|
154
|
|
155
|
struct FileExtMaker : ImageMaker {
|
156
|
String ext;
|
157
|
bool large;
|
158
|
|
159
|
virtual String Key() const {
|
160
|
return ext;
|
161
|
}
|
162
|
|
163
|
virtual Image Make() const {
|
164
|
String major;
|
165
|
String minor;
|
166
|
if(!Single<ExtToMime>().GetMime(ext, major, minor))
|
167
|
return Null;
|
168
|
Image img = SystemImage(major + '-' + minor, large);
|
169
|
return IsNull(img) ? SystemImage(major) : img;
|
170
|
}
|
171
|
};
|
172
|
|
173
|
Image PosixGetDriveImage(String dir, bool large)
|
174
|
{
|
175
|
static bool init = false;
|
176
|
static Image cdrom;
|
177
|
static Image lcdrom;
|
178
|
static Image harddisk;
|
179
|
static Image lharddisk;
|
180
|
static Image floppy;
|
181
|
static Image lfloppy;
|
182
|
static Image computer;
|
183
|
static Image lcomputer;
|
184
|
|
185
|
if (!init) {
|
186
|
bool KDE = Environment().Get("KDE_FULL_SESSION", String()) == "true";
|
187
|
if (KDE) {
|
188
|
cdrom = SystemImage("media-optical");
|
189
|
lcdrom = SystemImage("media-optical", true);
|
190
|
harddisk = SystemImage("drive-harddisk");
|
191
|
lharddisk = SystemImage("drive-harddisk", true);
|
192
|
floppy = SystemImage("media-floppy");
|
193
|
lfloppy = SystemImage("media-floppy", true);
|
194
|
computer = SystemImage("computer");
|
195
|
lcomputer = SystemImage("computer", true);
|
196
|
}
|
197
|
else {
|
198
|
cdrom = GnomeImage("dev-cdrom");
|
199
|
lcdrom = GnomeImage("dev-cdrom", true);
|
200
|
harddisk = GnomeImage("dev-harddisk");
|
201
|
lharddisk = GnomeImage("dev-harddisk", true);
|
202
|
floppy = GnomeImage("dev-floppy");
|
203
|
lfloppy = GnomeImage("dev-floppy", true);
|
204
|
computer = GnomeImage("dev-computer");
|
205
|
lcomputer = GnomeImage("dev-computer", true);
|
206
|
}
|
207
|
|
208
|
init = true;
|
209
|
}
|
210
|
if(dir.GetCount() == 0 || dir == "/") {
|
211
|
Image m = large ? lcomputer : computer;
|
212
|
return IsNull(m) ? CtrlImg::Computer() : m;
|
213
|
}
|
214
|
if(dir.Find("cdrom") == 0 || dir.Find("cdrecorder") == 0) {
|
215
|
Image m = large ? lcdrom : cdrom;
|
216
|
return IsNull(m) ? CtrlImg::CdRom() : m;
|
217
|
}
|
218
|
if(dir.Find("floppy") == 0 || dir.Find("zip") == 0) {
|
219
|
Image m = large ? lfloppy : floppy;
|
220
|
return IsNull(m) ? CtrlImg::Diskette() : m;
|
221
|
}
|
222
|
Image m = large ? lharddisk : harddisk;
|
223
|
return IsNull(m) ? CtrlImg::Hd() : m;
|
224
|
}
|
225
|
|
226
|
Image GetFileIcon(const String& folder, const String& filename, bool isdir, bool isexe, bool large)
|
227
|
{
|
228
|
static bool init = false;
|
229
|
static bool KDE = Environment().Get("KDE_FULL_SESSION", String()) == "true";
|
230
|
|
231
|
static Image file;
|
232
|
static Image lfile;
|
233
|
static Image dir;
|
234
|
static Image ldir;
|
235
|
static Image exe;
|
236
|
static Image lexe;
|
237
|
static Image home;
|
238
|
static Image lhome;
|
239
|
static Image desktop;
|
240
|
static Image ldesktop;
|
241
|
static Image music;
|
242
|
static Image lmusic;
|
243
|
static Image pictures;
|
244
|
static Image lpictures;
|
245
|
static Image video;
|
246
|
static Image lvideo;
|
247
|
static Image documents;
|
248
|
static Image ldocuments;
|
249
|
static Image download;
|
250
|
static Image ldownload;
|
251
|
static Image help;
|
252
|
static Image lhelp;
|
253
|
static Image translation;
|
254
|
static Image ltranslation;
|
255
|
static Image layout;
|
256
|
static Image llayout;
|
257
|
|
258
|
static Image fileImage;
|
259
|
static Image fileMusic = SystemImage("audio-x-generic");
|
260
|
static Image fileScript = SystemImage("text-x-script");
|
261
|
|
262
|
if (!init) {
|
263
|
if (KDE) {
|
264
|
file = SystemImage("text-plain");
|
265
|
lfile = SystemImage("text-plain", true);
|
266
|
dir = SystemImage("folder");
|
267
|
ldir = SystemImage("folder", true);
|
268
|
exe = SystemImage("application-x-executable");
|
269
|
lexe = SystemImage("application-x-executable", true);
|
270
|
home = SystemImage("user-home");
|
271
|
lhome = SystemImage("user-home", true);
|
272
|
desktop = SystemImage("user-desktop");
|
273
|
ldesktop = SystemImage("user-desktop", true);
|
274
|
music = SystemImage("folder-sound");
|
275
|
lmusic = SystemImage("folder-sound", true);
|
276
|
pictures = SystemImage("folder-image");
|
277
|
lpictures = SystemImage("folder-image", true);
|
278
|
video = SystemImage("folder-video");
|
279
|
lvideo = SystemImage("folder-video", true);
|
280
|
documents = SystemImage("folder-documents");
|
281
|
ldocuments = SystemImage("folder-documents", true);
|
282
|
download = SystemImage("folder-downloads");
|
283
|
ldownload = SystemImage("folder-downloads", true);
|
284
|
help = SystemImage("help-contents");
|
285
|
lhelp = SystemImage("help-contents", true);
|
286
|
translation = SystemImage("applications-education-language");
|
287
|
ltranslation = SystemImage("applications-education-language", true);
|
288
|
layout = SystemImage("applications-development");
|
289
|
llayout = SystemImage("applications-development", true);
|
290
|
|
291
|
fileImage = SystemImage("application-x-egon");
|
292
|
}
|
293
|
else {
|
294
|
file = GnomeImage("fs-regular");
|
295
|
lfile = GnomeImage("fs-regular", true);
|
296
|
dir = GnomeImage("fs-directory");
|
297
|
ldir = GnomeImage("fs-directory", true);
|
298
|
exe = GnomeImage("fs-executable");
|
299
|
lexe = GnomeImage("fs-executable", true);
|
300
|
home = GnomeImage("fs-home");
|
301
|
lhome = GnomeImage("fs-home", true);
|
302
|
desktop = GnomeImage("fs-desktop");
|
303
|
ldesktop = GnomeImage("fs-desktop", true);
|
304
|
music = SystemImage("folder-music");
|
305
|
lmusic = SystemImage("folder-music", true);
|
306
|
pictures = SystemImage("folder-pictures");
|
307
|
lpictures = SystemImage("folder-pictures", true);
|
308
|
video = SystemImage("folder-video");
|
309
|
lvideo = SystemImage("folder-video", true);
|
310
|
documents = SystemImage("folder-documents");
|
311
|
ldocuments = SystemImage("folder-documents", true);
|
312
|
download = SystemImage("folder-downloads");
|
313
|
ldownload = SystemImage("folder-downloads", true);
|
314
|
help = SystemImage("help");
|
315
|
lhelp = SystemImage("help", true);
|
316
|
translation = SystemImage("preferences-desktop-locale");
|
317
|
ltranslation = SystemImage("preferences-desktop-locale", true);
|
318
|
layout = SystemImage("applications-development");
|
319
|
llayout = SystemImage("applications-development", true);
|
320
|
|
321
|
fileImage = SystemImage("image-x-generic");
|
322
|
}
|
323
|
|
324
|
init = true;
|
325
|
}
|
326
|
if (filename == "Help Topics")
|
327
|
return large ? lhelp : help;
|
328
|
if(isdir) {
|
329
|
Image img = dir;
|
330
|
if(AppendFileName(folder, filename) == GetHomeDirectory())
|
331
|
return large ? lhome : home;
|
332
|
else
|
333
|
if(AppendFileName(folder, filename) == GetDesktopFolder ())
|
334
|
return large ? ldesktop : desktop;
|
335
|
else
|
336
|
if(AppendFileName(folder, filename) == GetMusicFolder ())
|
337
|
return large ? lmusic : music;
|
338
|
else
|
339
|
if(AppendFileName(folder, filename) == GetPicturesFolder())
|
340
|
return large ? lpictures : pictures;
|
341
|
else
|
342
|
if(AppendFileName(folder, filename) == GetVideoFolder())
|
343
|
return large ? lvideo : video;
|
344
|
else
|
345
|
if(AppendFileName(folder, filename) == GetDocumentsFolder())
|
346
|
return large ? ldocuments : documents;
|
347
|
else
|
348
|
if(AppendFileName(folder, filename) == GetDownloadFolder())
|
349
|
return large ? ldownload : download;
|
350
|
else
|
351
|
if(folder == "/media" || filename.GetCount() == 0)
|
352
|
return PosixGetDriveImage(filename, large);
|
353
|
return dir;
|
354
|
}
|
355
|
FileExtMaker m;
|
356
|
m.ext = GetFileExt(filename);
|
357
|
for (int i = 1; i < m.ext.GetCount(); ++i)
|
358
|
m.ext.Set (i, ToLower(m.ext[i]));
|
359
|
|
360
|
|
361
|
if (m.ext == ".gz") m.ext = ".tar.gz";
|
362
|
|
363
|
|
364
|
if (m.ext == ".t" || m.ext == ".lng") return large ? ltranslation : translation;
|
365
|
if (m.ext == ".lay") return large ? llayout : layout;
|
366
|
if (m.ext == ".iml") return fileImage;
|
367
|
if (m.ext == ".usc") return fileScript;
|
368
|
|
369
|
|
370
|
if (KDE) {
|
371
|
if (m.ext == ".bmp" || m.ext == ".dib" ||
|
372
|
m.ext == ".gif" ||
|
373
|
m.ext == ".jpg" || m.ext == ".jpeg" || m.ext == ".jpe" ||
|
374
|
m.ext == ".png" ||
|
375
|
m.ext == ".tif" || m.ext == ".tiff" ||
|
376
|
m.ext == ".svg" ||
|
377
|
m.ext == ".ico" ||
|
378
|
m.ext == ".xcf")
|
379
|
return fileImage;
|
380
|
if (m.ext == ".aac" || m.ext == ".ogg" || m.ext == ".mp3") return fileMusic;
|
381
|
}
|
382
|
|
383
|
Image img;
|
384
|
if(m.ext.GetCount()) {
|
385
|
m.ext = m.ext.Mid(1);
|
386
|
m.large = large;
|
387
|
img = MakeImage(m);
|
388
|
isexe = false;
|
389
|
}
|
390
|
return IsNull(img) ? isexe ? (large ? lexe : exe) : (large ? lfile : file) : img;
|
391
|
}
|
392
|
|
393
|
#define GETFILEICON_DEFINED
|
394
|
|
395
|
#endif
|
396
|
|
397
|
#ifndef GETFILEICON_DEFINED
|
398
|
Image PosixGetDriveImage(String dir, bool)
|
399
|
{
|
400
|
if(dir.GetCount() == 0 || dir == "/")
|
401
|
return CtrlImg::Computer();
|
402
|
if(dir.Find("cdrom") == 0 || dir.Find("cdrecorder") == 0)
|
403
|
return CtrlImg::CdRom();
|
404
|
if(dir.Find("floppy") == 0 || dir.Find("zip") == 0)
|
405
|
return CtrlImg::Diskette();
|
406
|
return CtrlImg::Hd();
|
407
|
}
|
408
|
|
409
|
#ifdef PLATFORM_WIN32
|
410
|
Image GetFileIcon(const String& folder, bool, bool, bool, bool = false)
|
411
|
{
|
412
|
return CtrlImg::File();
|
413
|
}
|
414
|
#else
|
415
|
Image GetFileIcon(const String& folder, const String& filename, bool isdir, bool isexe, bool = false)
|
416
|
{
|
417
|
return isdir ? CtrlImg::Dir() : CtrlImg::File();
|
418
|
}
|
419
|
|
420
|
#endif
|
421
|
#endif
|
422
|
|
423
|
Image NativePathIcon0(const char *path, bool folder, bool large)
|
424
|
{
|
425
|
#if defined(PLATFORM_WIN32)
|
426
|
if (folder)
|
427
|
return GetFileIcon(path, true, true, large);
|
428
|
else
|
429
|
return GetFileIcon(path, false, false, large);
|
430
|
#endif
|
431
|
#ifdef PLATFORM_POSIX
|
432
|
String p = path;
|
433
|
bool isdrive = folder && ((p == "/media") || (p == "/mnt"));
|
434
|
FindFile ff(path);
|
435
|
return isdrive ? PosixGetDriveImage(GetFileName(path), large)
|
436
|
: GetFileIcon(path, GetFileName(path), folder, ff.GetMode() & 0111, large);
|
437
|
#endif
|
438
|
}
|
439
|
|
440
|
Image NativePathIcon(const char *path, bool folder)
|
441
|
{
|
442
|
return NativePathIcon0(path, folder, false);
|
443
|
}
|
444
|
|
445
|
Image NativePathIcon(const char *path)
|
446
|
{
|
447
|
FindFile ff(path);
|
448
|
return NativePathIcon(path, ff.IsFolder());
|
449
|
}
|
450
|
|
451
|
Image NativePathLargeIcon(const char *path, bool folder)
|
452
|
{
|
453
|
return NativePathIcon0(path, folder, true);
|
454
|
}
|
455
|
|
456
|
Image NativePathLargeIcon(const char *path)
|
457
|
{
|
458
|
FindFile ff(path);
|
459
|
return NativePathLargeIcon(path, ff.IsFolder());
|
460
|
}
|
461
|
|
462
|
bool MatchSearch(const String& filename, const String& search)
|
463
|
{
|
464
|
return search.GetCount() ? Filter(filename, CharFilterDefaultToUpperAscii).Find(search) >= 0 : true;
|
465
|
}
|
466
|
|
467
|
bool Load(FileList& list, const String& dir, const char *patterns, bool dirs,
|
468
|
Callback3<bool, const String&, Image&> WhenIcon, FileSystemInfo& filesystem,
|
469
|
const String& search, bool hidden, bool hiddenfiles, bool lazyicons)
|
470
|
{
|
471
|
if(dir.IsEmpty()) {
|
472
|
Array<FileSystemInfo::FileInfo> root = filesystem.Find(Null);
|
473
|
for(int i = 0; i < root.GetCount(); i++)
|
474
|
if(MatchSearch(root[i].filename, search))
|
475
|
list.Add(root[i].filename,
|
476
|
#ifdef PLATFORM_WIN32
|
477
|
GetFileIcon(root[i].filename, false, true, false),
|
478
|
#else
|
479
|
GetDriveImage(root[i].root_style),
|
480
|
#endif
|
481
|
StdFont().Bold(), SColorText, true, -1, Null, SColorDisabled,
|
482
|
#ifdef PLATFORM_WIN32
|
483
|
Nvl(root[i].root_desc, String(" ") + t_("Local Disk")),
|
484
|
#else
|
485
|
root[i].root_desc,
|
486
|
#endif
|
487
|
StdFont()
|
488
|
);
|
489
|
#ifdef PLATFORM_WIN32
|
490
|
list.Add(t_("Network"), CtrlImg::Network(), StdFont().Bold(), SColorText,
|
491
|
true, -1, Null, SColorDisabled, Null, StdFont());
|
492
|
#endif
|
493
|
}
|
494
|
else {
|
495
|
Array<FileSystemInfo::FileInfo> ffi =
|
496
|
filesystem.Find(AppendFileName(dir, filesystem.IsWin32() ? "*.*" : "*"));
|
497
|
if(ffi.IsEmpty())
|
498
|
return false;
|
499
|
#ifdef PLATFORM_POSIX
|
500
|
bool isdrive = dir == "/media" || dir == "/mnt";
|
501
|
#endif
|
502
|
for(int t = 0; t < ffi.GetCount(); t++) {
|
503
|
const FileSystemInfo::FileInfo& fi = ffi[t];
|
504
|
bool nd = dirs && !fi.is_directory;
|
505
|
bool show = hidden;
|
506
|
if(!show && filesystem.IsWin32() ? !fi.is_hidden : fi.filename[0] != '.')
|
507
|
show = true;
|
508
|
if(!show && hiddenfiles && fi.is_file)
|
509
|
show = true;
|
510
|
if(fi.filename != "." && fi.filename != ".." != 0 &&
|
511
|
(fi.is_directory || PatternMatchMulti(patterns, fi.filename)) &&
|
512
|
MatchSearch(fi.filename, search) && show) {
|
513
|
Image img;
|
514
|
#ifdef PLATFORM_X11
|
515
|
img = isdrive ? PosixGetDriveImage(fi.filename, false)
|
516
|
: GetFileIcon(dir, fi.filename, fi.is_directory, fi.unix_mode & 0111, false);
|
517
|
#endif
|
518
|
#ifdef GUI_WIN
|
519
|
img = GetFileIcon(AppendFileName(dir, fi.filename), fi.is_directory, false, false, lazyicons);
|
520
|
#endif
|
521
|
if(IsNull(img))
|
522
|
img = fi.is_directory ? CtrlImg::Dir() : CtrlImg::File();
|
523
|
WhenIcon(fi.is_directory, fi.filename, img);
|
524
|
list.Add(fi.filename, fi.is_hidden ? Contrast(img, 200) : img,
|
525
|
StdFont().Bold(fi.is_directory),
|
526
|
nd ? SColorDisabled : fi.is_hidden ? Blend(SColorText, Gray, 200) : SColorText, fi.is_directory,
|
527
|
fi.is_directory ? -1 : fi.length,
|
528
|
Null, nd ? SColorDisabled
|
529
|
: fi.is_directory ? SColorText
|
530
|
: fi.is_hidden ? Blend(SColorMark, Gray, 200)
|
531
|
: SColorMark,
|
532
|
Null, Null, Null, Null,
|
533
|
#ifdef PLATFORM_WIN32
|
534
|
false,
|
535
|
#else
|
536
|
fi.unix_mode & 0111,
|
537
|
#endif
|
538
|
fi.is_hidden
|
539
|
);
|
540
|
}
|
541
|
}
|
542
|
}
|
543
|
return true;
|
544
|
}
|
545
|
|
546
|
#ifdef GUI_WIN
|
547
|
static AuxMutex sExeMutex;
|
548
|
static char sExePath[1025];
|
549
|
static bool sExeRunning;
|
550
|
static SHFILEINFO sExeInfo;
|
551
|
|
552
|
static auxthread_t auxthread__ sExeIconThread(void *)
|
553
|
{
|
554
|
SHFILEINFO info;
|
555
|
char path[1025];
|
556
|
sExeMutex.Enter();
|
557
|
strncpy(path, sExePath, 1024);
|
558
|
sExeMutex.Leave();
|
559
|
AvoidPaintingCheck__();
|
560
|
SHGetFileInfo(sExePath, FILE_ATTRIBUTE_NORMAL, &info, sizeof(info), SHGFI_ICON|SHGFI_SMALLICON);
|
561
|
sExeMutex.Enter();
|
562
|
memcpy(&sExeInfo, &info, sizeof(info));
|
563
|
sExeRunning = false;
|
564
|
sExeMutex.Leave();
|
565
|
return 0;
|
566
|
}
|
567
|
|
568
|
void LazyFileIcons::Done(Image img)
|
569
|
{
|
570
|
if(pos >= ndx.GetCount())
|
571
|
return;
|
572
|
int ii = ndx[pos];
|
573
|
if(ii < 0 || ii >= list->GetCount())
|
574
|
return;
|
575
|
const FileList::File& f = list->Get(ii);
|
576
|
WhenIcon(false, f.name, img);
|
577
|
if(f.hidden)
|
578
|
img = Contrast(img, 200);
|
579
|
list->SetIcon(ii, img);
|
580
|
pos++;
|
581
|
}
|
582
|
|
583
|
String LazyFileIcons::Path()
|
584
|
{
|
585
|
if(pos >= ndx.GetCount())
|
586
|
return Null;
|
587
|
int ii = ndx[pos];
|
588
|
if(ii < 0 || ii >= list->GetCount())
|
589
|
return Null;
|
590
|
const FileList::File& f = list->Get(ii);
|
591
|
return ToSystemCharset(AppendFileName(dir, f.name));
|
592
|
}
|
593
|
|
594
|
void LazyFileIcons::Do()
|
595
|
{
|
596
|
int start = msecs();
|
597
|
for(;;) {
|
598
|
for(;;) {
|
599
|
SHFILEINFO info;
|
600
|
bool done = false;
|
601
|
String path = Path();
|
602
|
if(IsNull(path))
|
603
|
return;
|
604
|
sExeMutex.Enter();
|
605
|
bool running = sExeRunning;
|
606
|
if(!running) {
|
607
|
done = path == sExePath;
|
608
|
memcpy(&info, &sExeInfo, sizeof(info));
|
609
|
*sExePath = '\0';
|
610
|
memset(&sExeInfo, 0, sizeof(sExeInfo));
|
611
|
}
|
612
|
sExeMutex.Leave();
|
613
|
Image img = ProcessSHIcon(info);
|
614
|
if(done)
|
615
|
Done(img);
|
616
|
if(!running)
|
617
|
break;
|
618
|
Sleep(0);
|
619
|
if(msecs(start) > 10 || Ctrl::IsWaitingEvent()) {
|
620
|
Restart(0);
|
621
|
return;
|
622
|
}
|
623
|
}
|
624
|
|
625
|
String path = Path();
|
626
|
if(IsNull(path))
|
627
|
return;
|
628
|
sExeMutex.Enter();
|
629
|
strncpy(sExePath, ~path, 1024);
|
630
|
sExeRunning = true;
|
631
|
StartAuxThread(sExeIconThread, NULL);
|
632
|
sExeMutex.Leave();
|
633
|
}
|
634
|
}
|
635
|
|
636
|
void LazyFileIcons::ReOrder()
|
637
|
{
|
638
|
ndx.Clear();
|
639
|
Vector<int> len;
|
640
|
for(int i = 0; i < list->GetCount(); i++) {
|
641
|
const FileList::File& f = list->Get(i);
|
642
|
if(ToLower(GetFileExt(f.name)) == ".exe" && !f.isdir) {
|
643
|
ndx.Add(i);
|
644
|
len.Add((int)min((int64)INT_MAX, f.length));
|
645
|
}
|
646
|
}
|
647
|
IndexSort(len, ndx);
|
648
|
Restart(0);
|
649
|
}
|
650
|
|
651
|
void LazyFileIcons::Start(FileList& list_, const String& dir_, Callback3<bool, const String&, Image&> WhenIcon_)
|
652
|
{
|
653
|
list = &list_;
|
654
|
dir = dir_;
|
655
|
WhenIcon = WhenIcon_;
|
656
|
pos = 0;
|
657
|
ReOrder();
|
658
|
}
|
659
|
#endif
|
660
|
|
661
|
class FileListSortName : public FileList::Order {
|
662
|
public:
|
663
|
virtual bool operator()(const FileList::File& a, const FileList::File& b) const {
|
664
|
if(a.isdir != b.isdir)
|
665
|
return a.isdir;
|
666
|
if(a.name == "..")
|
667
|
return b.name != "..";
|
668
|
if(b.name == "..")
|
669
|
return false;
|
670
|
return stricmp(a.name, b.name) < 0;
|
671
|
}
|
672
|
};
|
673
|
|
674
|
void SortByName(FileList& list)
|
675
|
{
|
676
|
list.Sort(FileListSortName());
|
677
|
}
|
678
|
|
679
|
class FileListSortExt : public FileList::Order {
|
680
|
public:
|
681
|
virtual bool operator()(const FileList::File& a, const FileList::File& b) const {
|
682
|
if(a.isdir != b.isdir)
|
683
|
return a.isdir;
|
684
|
if(a.name == "..")
|
685
|
return b.name != "..";
|
686
|
if(b.name == "..")
|
687
|
return false;
|
688
|
const char *ae = strrchr(a.name, '.');
|
689
|
const char *be = strrchr(b.name, '.');
|
690
|
int q;
|
691
|
if(ae == NULL || be == NULL) {
|
692
|
if(ae) return false;
|
693
|
if(be) return true;
|
694
|
q = 0;
|
695
|
}
|
696
|
else
|
697
|
q = stricmp(ae, be);
|
698
|
return (q ? q : stricmp(a.name, b.name)) < 0;
|
699
|
}
|
700
|
};
|
701
|
|
702
|
void SortByExt(FileList& list)
|
703
|
{
|
704
|
list.Sort(FileListSortExt());
|
705
|
}
|
706
|
|
707
|
String FileSel::GetDir() {
|
708
|
String s = ~dir;
|
709
|
if(s.IsEmpty()) return basedir;
|
710
|
if(basedir.IsEmpty()) return s;
|
711
|
return AppendFileName(basedir, s);
|
712
|
}
|
713
|
|
714
|
void FileSel::SetDir(const String& _dir) {
|
715
|
#ifdef PLATFORM_WIN32
|
716
|
netstack.Clear();
|
717
|
netnode.Clear();
|
718
|
#endif
|
719
|
dir <<= _dir;
|
720
|
Load();
|
721
|
Update();
|
722
|
}
|
723
|
|
724
|
String FileSel::FilePath(const String& fn) {
|
725
|
return AppendFileName(GetDir(), fn);
|
726
|
}
|
727
|
|
728
|
Image GetDriveImage(char drive_style)
|
729
|
{
|
730
|
switch(drive_style)
|
731
|
{
|
732
|
case FileSystemInfo::ROOT_NO_ROOT_DIR: return Null;
|
733
|
case FileSystemInfo::ROOT_COMPUTER: return CtrlImg::Computer();
|
734
|
case FileSystemInfo::ROOT_REMOVABLE: return CtrlImg::Diskette();
|
735
|
case FileSystemInfo::ROOT_CDROM: return CtrlImg::CdRom();
|
736
|
default: return CtrlImg::Hd();
|
737
|
}
|
738
|
}
|
739
|
|
740
|
String FileSel::GetMask()
|
741
|
{
|
742
|
String emask = "*";
|
743
|
if(!IsNull(type)) {
|
744
|
if(IsString(~type))
|
745
|
emask = ~type;
|
746
|
else {
|
747
|
int q = ~type;
|
748
|
if(q >= 0 && q < mask.GetCount())
|
749
|
emask = mask[q];
|
750
|
}
|
751
|
}
|
752
|
return emask;
|
753
|
}
|
754
|
|
755
|
void FileSel::Load()
|
756
|
{
|
757
|
search <<= Null;
|
758
|
SearchLoad();
|
759
|
}
|
760
|
|
761
|
void FileSel::LoadNet()
|
762
|
{
|
763
|
#ifdef PLATFORM_WIN32
|
764
|
list.Clear();
|
765
|
for(int i = 0; i < netnode.GetCount(); i++) {
|
766
|
Image m = CtrlImg::Group();
|
767
|
switch(netnode[i].GetDisplayType()) {
|
768
|
case NetNode::NETWORK:
|
769
|
m = CtrlImg::Network();
|
770
|
break;
|
771
|
case NetNode::SHARE:
|
772
|
m = CtrlImg::Share();
|
773
|
break;
|
774
|
case NetNode::SERVER:
|
775
|
m = CtrlImg::Computer();
|
776
|
break;
|
777
|
}
|
778
|
list.Add(netnode[i].GetName(), m);
|
779
|
}
|
780
|
places.FindSetCursor("\\");
|
781
|
#endif
|
782
|
}
|
783
|
|
784
|
void FileSel::SelectNet()
|
785
|
{
|
786
|
#ifdef PLATFORM_WIN32
|
787
|
int q = list.GetCursor();
|
788
|
if(q >= 0 && q < netnode.GetCount()) {
|
789
|
NetNode& n = netnode[q];
|
790
|
String p = n.GetPath();
|
791
|
if(p.GetCount())
|
792
|
SetDir(p);
|
793
|
else {
|
794
|
netstack.Add() = netnode[q];
|
795
|
netnode = netstack.Top().Enum();
|
796
|
LoadNet();
|
797
|
}
|
798
|
}
|
799
|
#endif
|
800
|
}
|
801
|
|
802
|
void FileSel::SearchLoad()
|
803
|
{
|
804
|
list.EndEdit();
|
805
|
list.Clear();
|
806
|
String d = GetDir();
|
807
|
#ifdef PLATFORM_WIN32
|
808
|
if(d == "\\") {
|
809
|
netnode = NetNode::EnumRoot();
|
810
|
netnode.Append(NetNode::EnumRemembered());
|
811
|
LoadNet();
|
812
|
return;
|
813
|
}
|
814
|
#endif
|
815
|
String emask = GetMask();
|
816
|
if(!UPP::Load(list, d, emask, mode == SELECTDIR, WhenIcon, *filesystem, ~search, ~hidden, ~hiddenfiles, true)) {
|
817
|
Exclamation(t_("[A3* Unable to read the directory !]&&") + DeQtf((String)~dir) + "&&" +
|
818
|
GetErrorMessage(GetLastError()));
|
819
|
if(!basedir.IsEmpty() && String(~dir).IsEmpty()) {
|
820
|
Break(IDCANCEL);
|
821
|
return;
|
822
|
}
|
823
|
dir <<= olddir;
|
824
|
olddir = Null;
|
825
|
SearchLoad();
|
826
|
}
|
827
|
|
828
|
places.KillCursor();
|
829
|
if(d.GetCount())
|
830
|
places.FindSetCursor(d);
|
831
|
hiddenfiles.Enable(!hidden);
|
832
|
if(d.IsEmpty()) {
|
833
|
if(filesystem->IsWin32()) {
|
834
|
mkdir.Disable();
|
835
|
plus.Disable();
|
836
|
minus.Disable();
|
837
|
toggle.Disable();
|
838
|
list.Renaming(false);
|
839
|
}
|
840
|
dir <<= d;
|
841
|
dirup.Disable();
|
842
|
}
|
843
|
else {
|
844
|
dirup.Enable();
|
845
|
mkdir.Enable();
|
846
|
plus.Enable();
|
847
|
minus.Enable();
|
848
|
toggle.Enable();
|
849
|
list.Renaming(true);
|
850
|
}
|
851
|
if(filesystem->IsPosix())
|
852
|
if(d == "/" || !IsEmpty(basedir) && String(~dir).IsEmpty())
|
853
|
dirup.Disable();
|
854
|
if(filesystem->IsWin32())
|
855
|
if(!IsEmpty(basedir) && String(~dir).IsEmpty())
|
856
|
dirup.Disable();
|
857
|
olddir = ~dir;
|
858
|
if(olddir.GetCount() || basedir.GetCount())
|
859
|
if(sortext && mode != SELECTDIR)
|
860
|
SortByExt(list);
|
861
|
else
|
862
|
SortByName(list);
|
863
|
Update();
|
864
|
#ifdef GUI_WIN
|
865
|
lazyicons.Start(list, d, WhenIcon);
|
866
|
#endif
|
867
|
}
|
868
|
|
869
|
String TrimDot(String f) {
|
870
|
int i = f.Find('.');
|
871
|
if(i >= 0 && i == f.GetLength() - 1)
|
872
|
f.Trim(i);
|
873
|
return f;
|
874
|
}
|
875
|
|
876
|
void FileSel::AddName(Vector<String>& fn, String& f) {
|
877
|
if(!f.IsEmpty()) {
|
878
|
if(f.Find('.') < 0) {
|
879
|
String t = GetMask();
|
880
|
int q = t.Find('.');
|
881
|
if(q >= 0 && IsAlNum(t[q + 1])) {
|
882
|
int w = q + 2;
|
883
|
while(IsAlNum(t[w]))
|
884
|
w++;
|
885
|
f << t.Mid(q, w - q);
|
886
|
}
|
887
|
else
|
888
|
if(defext.GetCount())
|
889
|
f << '.' << defext;
|
890
|
}
|
891
|
f = TrimDot(f);
|
892
|
if(f[0] == '\"' && f.GetCount() > 2)
|
893
|
fn.Add(f.Mid(1, f.GetCount() - 2));
|
894
|
else
|
895
|
fn.Add(f);
|
896
|
}
|
897
|
f.Clear();
|
898
|
}
|
899
|
|
900
|
void FileSel::Finish() {
|
901
|
if(filesystem->IsWin32())
|
902
|
if(GetDir().IsEmpty()) {
|
903
|
file.Clear();
|
904
|
return;
|
905
|
}
|
906
|
fn.Clear();
|
907
|
if(mode == SELECTDIR) {
|
908
|
String p = GetDir();
|
909
|
if(list.IsSelection() && multi) {
|
910
|
for(int i = 0; i < list.GetCount(); i++)
|
911
|
if(list.IsSelected(i)) {
|
912
|
const FileList::File& m = list[i];
|
913
|
if(m.isdir)
|
914
|
fn.Add(AppendFileName(p, m.name));
|
915
|
}
|
916
|
}
|
917
|
else {
|
918
|
String p = GetDir();
|
919
|
if(list.GetCursor() >= 0) {
|
920
|
const FileList::File& m = list[list.GetCursor()];
|
921
|
if(m.isdir)
|
922
|
p = AppendFileName(p, m.name);
|
923
|
}
|
924
|
fn.Add(p);
|
925
|
}
|
926
|
Break(IDOK);
|
927
|
return;
|
928
|
}
|
929
|
String f = file.GetText().ToString();
|
930
|
if(f.IsEmpty()) return;
|
931
|
String o;
|
932
|
if(mode == OPEN && IsMulti()) {
|
933
|
for(const char *s = f; *s; s++) {
|
934
|
if(*s == ' ')
|
935
|
AddName(fn, o);
|
936
|
else
|
937
|
if(*s == '\"') {
|
938
|
AddName(fn, o);
|
939
|
s++;
|
940
|
for(;;) {
|
941
|
if(*s == '\0')
|
942
|
AddName(fn, o);
|
943
|
else
|
944
|
if(*s == '\"') {
|
945
|
AddName(fn, o);
|
946
|
break;
|
947
|
}
|
948
|
o.Cat(*s++);
|
949
|
}
|
950
|
}
|
951
|
else
|
952
|
o.Cat(*s);
|
953
|
}
|
954
|
AddName(fn, o);
|
955
|
}
|
956
|
else {
|
957
|
o = f;
|
958
|
AddName(fn, o);
|
959
|
}
|
960
|
if(!IsMulti() && fn.GetCount())
|
961
|
fn.SetCount(1);
|
962
|
String d = GetDir();
|
963
|
String nonexist;
|
964
|
int ne = 0;
|
965
|
for(int i = 0; i < fn.GetCount(); i++) {
|
966
|
String p = fn[i];
|
967
|
if(!IsFullPath(p))
|
968
|
p = NormalizePath(AppendFileName(d, fn[i]));
|
969
|
Array<FileSystemInfo::FileInfo> ff = filesystem->Find(p, 1);
|
970
|
p = DeQtf(p);
|
971
|
if(!ff.IsEmpty() && ff[0].is_directory) {
|
972
|
Exclamation(p + t_(" is directory."));
|
973
|
return;
|
974
|
}
|
975
|
if(asking)
|
976
|
if(mode == SAVEAS) {
|
977
|
if(!ff.IsEmpty() && !PromptOKCancel(p + t_(" already exists.&Do you want to continue ?")))
|
978
|
return;
|
979
|
}
|
980
|
else
|
981
|
if(ff.IsEmpty()) {
|
982
|
if(ne) nonexist << '&';
|
983
|
nonexist << p;
|
984
|
ne++;
|
985
|
}
|
986
|
}
|
987
|
if(ne) {
|
988
|
nonexist << (ne == 1 ? t_(" does not exist.") : t_("&do not exist."));
|
989
|
if(!PromptOKCancel(nonexist + t_("&Do you want to continue ?")))
|
990
|
return;
|
991
|
}
|
992
|
Break(IDOK);
|
993
|
}
|
994
|
|
995
|
bool FileSel::OpenItem() {
|
996
|
if(list.IsCursor()) {
|
997
|
#ifdef PLATFORM_WIN32
|
998
|
if(netnode.GetCount()) {
|
999
|
SelectNet();
|
1000
|
return true;
|
1001
|
}
|
1002
|
#endif
|
1003
|
const FileList::File& m = list.Get(list.GetCursor());
|
1004
|
#ifdef PLATFORM_WIN32
|
1005
|
if(IsNull(dir) && m.name == t_("Network")) {
|
1006
|
netnode = NetNode::EnumRoot();
|
1007
|
netnode.Append(NetNode::EnumRemembered());
|
1008
|
LoadNet();
|
1009
|
return true;
|
1010
|
}
|
1011
|
#endif
|
1012
|
if(m.isdir) {
|
1013
|
SetDir(AppendFileName(~dir, m.name));
|
1014
|
return true;
|
1015
|
}
|
1016
|
}
|
1017
|
if(mode != SELECTDIR)
|
1018
|
Finish();
|
1019
|
return false;
|
1020
|
}
|
1021
|
|
1022
|
void FileSel::Open() {
|
1023
|
if(mode == SELECTDIR) {
|
1024
|
#ifdef PLATFORM_WIN32
|
1025
|
if(netnode.GetCount())
|
1026
|
return;
|
1027
|
#endif
|
1028
|
Finish();
|
1029
|
return;
|
1030
|
}
|
1031
|
if(list.HasFocus() || type.HasFocus()) {
|
1032
|
if(OpenItem()) list.SetCursor(0);
|
1033
|
}
|
1034
|
else
|
1035
|
if(list.IsSelection())
|
1036
|
for(int i = 0; i < list.GetCount(); i++) {
|
1037
|
const FileList::File& m = list[i];
|
1038
|
if(!m.isdir) Finish();
|
1039
|
}
|
1040
|
else
|
1041
|
if(file.HasFocus()) {
|
1042
|
String fn = file.GetText().ToString();
|
1043
|
#ifdef PLATFORM_WIN32
|
1044
|
if(fn[0] == '\\' && fn[1] == '\\') {
|
1045
|
FindFile ff(AppendFileName(fn, "*.*"));
|
1046
|
if(ff)
|
1047
|
SetDir(TrimDot(fn));
|
1048
|
return;
|
1049
|
}
|
1050
|
#endif
|
1051
|
if(fn == "." || fn == "..") {
|
1052
|
DirUp();
|
1053
|
return;
|
1054
|
}
|
1055
|
if(HasWildcards(fn)) {
|
1056
|
file.Clear();
|
1057
|
int q = FindIndex(mask, fn);
|
1058
|
if(q >= 0)
|
1059
|
type.SetIndex(q);
|
1060
|
else {
|
1061
|
type.Add(fn, t_("Custom file type (") + fn + ')');
|
1062
|
type.SetIndex(type.GetCount() - 1);
|
1063
|
}
|
1064
|
Load();
|
1065
|
return;
|
1066
|
}
|
1067
|
if(fn.Find('\"') < 0) {
|
1068
|
if(filesystem->IsWin32())
|
1069
|
{
|
1070
|
if(fn.GetLength() >= 2 && fn[1] == ':' && fn.GetLength() <= 3) {
|
1071
|
fn.Set(0, ToUpper(fn[0]));
|
1072
|
if(fn.GetLength() == 2)
|
1073
|
fn.Cat('\\');
|
1074
|
SetDir(fn);
|
1075
|
return;
|
1076
|
}
|
1077
|
}
|
1078
|
if(!IsFullPath(fn))
|
1079
|
fn = AppendFileName(~dir, fn);
|
1080
|
if(filesystem->IsWin32() && (!fn.IsEmpty() && (*fn.Last() == '\\' || *fn.Last() == '/'))
|
1081
|
|| filesystem->IsPosix() && (fn != "/" && (*fn.Last() == '\\' || *fn.Last() == '/')))
|
1082
|
{
|
1083
|
fn.Trim(fn.GetLength() - 1);
|
1084
|
SetDir(TrimDot(fn));
|
1085
|
return;
|
1086
|
}
|
1087
|
Array<FileSystemInfo::FileInfo> ff = filesystem->Find(fn, 1);
|
1088
|
if(!ff.IsEmpty()) {
|
1089
|
if(ff[0].is_directory) {
|
1090
|
SetDir(TrimDot(fn));
|
1091
|
return;
|
1092
|
}
|
1093
|
else {
|
1094
|
SetDir(TrimDot(GetFileFolder(fn)));
|
1095
|
file.SetText(GetFileName(fn).ToWString());
|
1096
|
}
|
1097
|
}
|
1098
|
}
|
1099
|
if(mode != SELECTDIR) Finish();
|
1100
|
}
|
1101
|
}
|
1102
|
|
1103
|
String DirectoryUp(String& dir, bool basedir)
|
1104
|
{
|
1105
|
while(*dir.Last() == '\\' || *dir.Last() == '/')
|
1106
|
dir.Trim(dir.GetCount() - 1);
|
1107
|
String s = dir;
|
1108
|
String name;
|
1109
|
#ifdef PLATFORM_WIN32
|
1110
|
if(s.GetLength() < 3 || s.GetLength() == 3 && s[1] == ':') {
|
1111
|
dir.Clear();
|
1112
|
name = s;
|
1113
|
}
|
1114
|
else
|
1115
|
#endif
|
1116
|
#ifdef PLATFORM_POSIX
|
1117
|
if(s != "/")
|
1118
|
#endif
|
1119
|
{
|
1120
|
#ifdef PLATFORM_WIN32
|
1121
|
int i = max(s.ReverseFind('/'), s.ReverseFind('\\'));
|
1122
|
#endif
|
1123
|
#ifdef PLATFORM_POSIX
|
1124
|
int i = s.ReverseFind('/');
|
1125
|
#endif
|
1126
|
if(basedir)
|
1127
|
if(i < 0)
|
1128
|
dir.Clear();
|
1129
|
else {
|
1130
|
dir = s.Mid(0, i);
|
1131
|
name = s.Mid(i + 1);
|
1132
|
}
|
1133
|
else {
|
1134
|
#ifdef PLATFORM_WIN32
|
1135
|
if(s.GetLength() && s[1] == ':')
|
1136
|
if(i > 3) {
|
1137
|
dir = s.Mid(0, i);
|
1138
|
name = s.Mid(i + 1);
|
1139
|
}
|
1140
|
else {
|
1141
|
dir = s.Mid(0, 3);
|
1142
|
name = s.Mid(3);
|
1143
|
}
|
1144
|
if(s.GetLength() && s[0] == DIR_SEP && s[1] == DIR_SEP)
|
1145
|
if(i > 2) {
|
1146
|
dir = s.Mid(0, i);
|
1147
|
name = s.Mid(i + 1);
|
1148
|
}
|
1149
|
else {
|
1150
|
dir.Clear();
|
1151
|
name = s;
|
1152
|
}
|
1153
|
#endif
|
1154
|
#ifdef PLATFORM_POSIX
|
1155
|
if(i == 0 && s.GetLength() > 1) {
|
1156
|
dir = "/";
|
1157
|
name = s.Mid(1);
|
1158
|
}
|
1159
|
else
|
1160
|
if(s.GetLength() && s[0] == '/' && s[1] != '/') {
|
1161
|
dir = s.Mid(0, i);
|
1162
|
name = s.Mid(i + 1);
|
1163
|
}
|
1164
|
#endif
|
1165
|
}
|
1166
|
}
|
1167
|
return name;
|
1168
|
}
|
1169
|
|
1170
|
void FileSel::DirUp() {
|
1171
|
#ifdef PLATFORM_WIN32
|
1172
|
if(netstack.GetCount()) {
|
1173
|
netstack.Drop();
|
1174
|
if(netstack.GetCount()) {
|
1175
|
netnode = netstack.Top().Enum();
|
1176
|
LoadNet();
|
1177
|
}
|
1178
|
netnode = NetNode::EnumRoot();
|
1179
|
return;
|
1180
|
}
|
1181
|
if(netnode.GetCount()) {
|
1182
|
netnode.Clear();
|
1183
|
SetDir("");
|
1184
|
return;
|
1185
|
}
|
1186
|
#endif
|
1187
|
String s = ~dir;
|
1188
|
String name = DirectoryUp(s, !basedir.IsEmpty());
|
1189
|
#ifdef PLATFORM_WIN32
|
1190
|
if(s[0] == '\\' && s[1] == '\\' && s.Find('\\', 2) < 0) {
|
1191
|
s.Clear();
|
1192
|
name.Clear();
|
1193
|
}
|
1194
|
#endif
|
1195
|
SetDir(s);
|
1196
|
if(list.HasFocus())
|
1197
|
list.FindSetCursor(name);
|
1198
|
}
|
1199
|
|
1200
|
void FileSel::MkDir() {
|
1201
|
if(String(~dir).IsEmpty() && basedir.IsEmpty()) return;
|
1202
|
String name, error;
|
1203
|
if(EditText(name, t_("New directory"), t_("Name")) && !name.IsEmpty())
|
1204
|
if(filesystem->CreateFolder(FilePath(name), error))
|
1205
|
{
|
1206
|
Load();
|
1207
|
list.FindSetCursor(name);
|
1208
|
}
|
1209
|
else
|
1210
|
Exclamation(t_("[A3* Creating directory failed !&&]") + error);
|
1211
|
}
|
1212
|
|
1213
|
void FileSel::PlusMinus(const char *title, bool sel) {
|
1214
|
String pattern;
|
1215
|
if(EditText(pattern, title, t_("Mask")) && !pattern.IsEmpty())
|
1216
|
for(int i = 0; i < list.GetCount(); i++)
|
1217
|
if(!list.Get(i).isdir)
|
1218
|
if(PatternMatchMulti(pattern, list.Get(i).name))
|
1219
|
list.SelectOne(i, sel);
|
1220
|
}
|
1221
|
|
1222
|
void FileSel::Plus() {
|
1223
|
PlusMinus(t_("Add to selection"), true);
|
1224
|
}
|
1225
|
|
1226
|
void FileSel::Minus() {
|
1227
|
PlusMinus(t_("Remove from selection"), false);
|
1228
|
}
|
1229
|
|
1230
|
void FileSel::Toggle() {
|
1231
|
for(int i = 0; i < list.GetCount(); i++)
|
1232
|
if(!list.Get(i).isdir)
|
1233
|
list.SelectOne(i, !list.IsSelected(i));
|
1234
|
}
|
1235
|
|
1236
|
bool FileSel::Key(dword key, int count) {
|
1237
|
switch(key) {
|
1238
|
case '.':
|
1239
|
case K_CTRL_UP:
|
1240
|
list.SetFocus();
|
1241
|
dirup.PseudoPush();
|
1242
|
return true;
|
1243
|
case '+':
|
1244
|
plus.PseudoPush();
|
1245
|
return true;
|
1246
|
case '-':
|
1247
|
minus.PseudoPush();
|
1248
|
return true;
|
1249
|
case '*':
|
1250
|
toggle.PseudoPush();
|
1251
|
return true;
|
1252
|
case K_F6:
|
1253
|
list.StartEdit();
|
1254
|
return true;
|
1255
|
case K_F7:
|
1256
|
mkdir.PseudoPush();
|
1257
|
return true;
|
1258
|
case K_ENTER:
|
1259
|
if(mode == SELECTDIR && OpenItem())
|
1260
|
return true;
|
1261
|
break;
|
1262
|
case K_UP:
|
1263
|
case K_DOWN:
|
1264
|
case K_PAGEUP:
|
1265
|
case K_PAGEDOWN:
|
1266
|
list.SetFocus();
|
1267
|
return list.Key(key, count);
|
1268
|
}
|
1269
|
if(CharFilterDefaultToUpperAscii(key) || key == K_BACKSPACE)
|
1270
|
return search.Key(key, count);
|
1271
|
return TopWindow::Key(key, count);
|
1272
|
}
|
1273
|
|
1274
|
void Catq(String& s, const String& fn) {
|
1275
|
if(!s.IsEmpty())
|
1276
|
s << ' ';
|
1277
|
if(fn.Find(' ') >= 0)
|
1278
|
s << '"' << fn << '"';
|
1279
|
else
|
1280
|
s << fn;
|
1281
|
}
|
1282
|
|
1283
|
String FormatFileSize(int64 n)
|
1284
|
{
|
1285
|
if(n < 10000)
|
1286
|
return Format("%d B ", n);
|
1287
|
else
|
1288
|
if(n < 10000 * 1024)
|
1289
|
return Format("%d.%d K ", n >> 10, (n & 1023) / 103);
|
1290
|
else
|
1291
|
if(n < I64(10000000) * 1024)
|
1292
|
return Format("%d.%d M ", n >> 20, (n & 1023) / 103);
|
1293
|
else
|
1294
|
return Format("%d.%d G ", n >> 30, (n & 1023) / 103);
|
1295
|
}
|
1296
|
|
1297
|
void FileSel::Update() {
|
1298
|
String fn;
|
1299
|
if(list.IsSelection()) {
|
1300
|
for(int i = 0; i < list.GetCount(); i++)
|
1301
|
if(list.IsSelected(i))
|
1302
|
Catq(fn, list[i].name);
|
1303
|
}
|
1304
|
else
|
1305
|
if(list.IsCursor()) {
|
1306
|
const FileList::File& m = list[list.GetCursor()];
|
1307
|
if(!m.isdir)
|
1308
|
Catq(fn, m.name);
|
1309
|
}
|
1310
|
if(mode == OPEN)
|
1311
|
file <<= fn;
|
1312
|
filename = String();
|
1313
|
filesize = String();
|
1314
|
filetime = String();
|
1315
|
if(preview)
|
1316
|
*preview <<= Null;
|
1317
|
if(list.IsCursor()) {
|
1318
|
fn = list[list.GetCursor()].name;
|
1319
|
if(fn[1] == ':' && fn.GetLength() <= 3)
|
1320
|
filename = t_(" Drive");
|
1321
|
else {
|
1322
|
String path = FilePath(fn);
|
1323
|
Array<FileSystemInfo::FileInfo> ff = filesystem->Find(path, 1);
|
1324
|
if(!ff.IsEmpty()) {
|
1325
|
filename = " " + fn;
|
1326
|
if(ff[0].is_directory)
|
1327
|
filesize = t_("Directory ");
|
1328
|
else {
|
1329
|
if(mode == SAVEAS)
|
1330
|
file <<= fn;
|
1331
|
filesize = FormatFileSize(ff[0].length);
|
1332
|
if(preview)
|
1333
|
*preview <<= path;
|
1334
|
}
|
1335
|
Time tm = ff[0].last_write_time;
|
1336
|
filetime = " " + Format(tm);
|
1337
|
}
|
1338
|
}
|
1339
|
}
|
1340
|
else {
|
1341
|
int drives = 0;
|
1342
|
int dirs = 0;
|
1343
|
int files = 0;
|
1344
|
int64 length = 0;
|
1345
|
for(int i = 0; i < list.GetCount(); i++)
|
1346
|
if(!list.IsSelection() || list.IsSelected(i)) {
|
1347
|
const FileList::File& f = list[i];
|
1348
|
if(f.isdir)
|
1349
|
#ifdef PLATFORM_WIN32
|
1350
|
(*f.name.Last() == ':' ? drives : dirs)++;
|
1351
|
#else
|
1352
|
dirs++;
|
1353
|
#endif
|
1354
|
else {
|
1355
|
files++;
|
1356
|
length += f.length;
|
1357
|
}
|
1358
|
}
|
1359
|
String s;
|
1360
|
if(drives)
|
1361
|
s << drives << t_(" drive(s)");
|
1362
|
else {
|
1363
|
if(dirs)
|
1364
|
s << dirs << t_(" folder(s)");
|
1365
|
if(files) {
|
1366
|
if(s.GetCount())
|
1367
|
s << ", ";
|
1368
|
s << files << t_(" file(s)");
|
1369
|
}
|
1370
|
}
|
1371
|
filename = " " + s;
|
1372
|
if(length >= 0)
|
1373
|
filesize = FormatFileSize(length);
|
1374
|
}
|
1375
|
FileUpdate();
|
1376
|
}
|
1377
|
|
1378
|
void FileSel::FileUpdate() {
|
1379
|
if(mode == SELECTDIR) {
|
1380
|
ok.Enable(!IsNull(~dir));
|
1381
|
return;
|
1382
|
}
|
1383
|
bool b = list.IsCursor() || !String(file).IsEmpty();
|
1384
|
ok.Enable(b);
|
1385
|
if(mode != SAVEAS || list.IsCursor() && list[list.GetCursor()].isdir)
|
1386
|
ok.SetLabel(t_("Open"));
|
1387
|
else
|
1388
|
ok.SetLabel(t_("Save"));
|
1389
|
}
|
1390
|
|
1391
|
void FileSel::Rename(const String& on, const String& nn) {
|
1392
|
#ifdef PLATFORM_WIN32
|
1393
|
if(FileMove(FilePath(on), FilePath(nn)))
|
1394
|
#else
|
1395
|
if(rename(FilePath(on), FilePath(nn)) == 0)
|
1396
|
#endif
|
1397
|
{
|
1398
|
Load();
|
1399
|
list.FindSetCursor(nn);
|
1400
|
}
|
1401
|
else
|
1402
|
Exclamation(t_("[A3* Renaming of file failed !&&]") + GetErrorMessage(GetLastError()));
|
1403
|
}
|
1404
|
|
1405
|
void FileSel::Choice() {
|
1406
|
Load();
|
1407
|
}
|
1408
|
|
1409
|
FileSel& FileSel::Type(const char *name, const char *ext) {
|
1410
|
type.Add(type.GetCount(), name);
|
1411
|
mask.Add(ext);
|
1412
|
if(IsNull(type))
|
1413
|
type.SetIndex(0);
|
1414
|
return *this;
|
1415
|
}
|
1416
|
|
1417
|
FileSel& FileSel::Types(const char *d) {
|
1418
|
Vector<String> s = Split(d, '\n');
|
1419
|
for(int i = 0; i < s.GetCount(); i++) {
|
1420
|
Vector<String> h = Split(s[i], '\t');
|
1421
|
if(h.GetCount() == 2)
|
1422
|
Type(h[0], h[1]);
|
1423
|
if(h.GetCount() == 1)
|
1424
|
Type(h[0], h[0]);
|
1425
|
}
|
1426
|
return *this;
|
1427
|
}
|
1428
|
|
1429
|
FileSel& FileSel::ClearTypes()
|
1430
|
{
|
1431
|
type.Clear();
|
1432
|
mask.Clear();
|
1433
|
return *this;
|
1434
|
}
|
1435
|
|
1436
|
FileSel& FileSel::ActiveType(int i)
|
1437
|
{
|
1438
|
activetype.Clear();
|
1439
|
if(i >= 0 && i < type.GetCount())
|
1440
|
activetype = type.GetValue(i);
|
1441
|
return *this;
|
1442
|
}
|
1443
|
|
1444
|
FileSel& FileSel::AllFilesType() {
|
1445
|
return Type(t_("All files"), "*.*");
|
1446
|
}
|
1447
|
|
1448
|
struct FolderDisplay : public Display {
|
1449
|
virtual void Paint(Draw& w, const Rect& r, const Value& q,
|
1450
|
Color ink, Color paper, dword style) const;
|
1451
|
};
|
1452
|
|
1453
|
Image GetDirIcon(const String& s)
|
1454
|
{
|
1455
|
Image img;
|
1456
|
#ifdef PLATFORM_X11
|
1457
|
img = GetFileIcon(GetFileFolder(s), GetFileName(s), true, false, false);
|
1458
|
#endif
|
1459
|
#ifdef GUI_WIN
|
1460
|
if((byte)*s.Last() == 255)
|
1461
|
img = CtrlImg::Network();
|
1462
|
else
|
1463
|
img = s.GetCount() ? GetFileIcon(s, false, true, false) : CtrlImg::Computer();
|
1464
|
#endif
|
1465
|
if(IsNull(img))
|
1466
|
img = CtrlImg::Dir();
|
1467
|
return img;
|
1468
|
}
|
1469
|
|
1470
|
void FolderDisplay::Paint(Draw& w, const Rect& r, const Value& q,
|
1471
|
Color ink, Color paper, dword style) const
|
1472
|
{
|
1473
|
String s = q;
|
1474
|
w.DrawRect(r, paper);
|
1475
|
Image img = GetDirIcon(s);
|
1476
|
w.DrawImage(r.left, r.top + (r.Height() - img.GetSize().cx) / 2, img);
|
1477
|
w.DrawText(r.left + 20,
|
1478
|
r.top + (r.Height() - StdFont().Bold().Info().GetHeight()) / 2,
|
1479
|
~s, StdFont().Bold(), ink);
|
1480
|
}
|
1481
|
|
1482
|
struct HomeDisplay : public Display {
|
1483
|
virtual void Paint(Draw& w, const Rect& r, const Value& q,
|
1484
|
Color ink, Color paper, dword style) const {
|
1485
|
w.DrawRect(r, paper);
|
1486
|
w.DrawImage(r.left, r.top + (r.Height() - CtrlImg::Home().GetSize().cx) / 2,
|
1487
|
CtrlImg::Home());
|
1488
|
w.DrawText(r.left + 20,
|
1489
|
r.top + (r.Height() - StdFont().Bold().Info().GetHeight()) / 2,
|
1490
|
String(q), StdFont().Bold(), ink);
|
1491
|
}
|
1492
|
};
|
1493
|
|
1494
|
void FileSel::Set(const String& s)
|
1495
|
{
|
1496
|
fn.Clear();
|
1497
|
if(IsFullPath(s)) {
|
1498
|
ActiveDir(GetFileFolder(s));
|
1499
|
fn.Add(GetFileName(s));
|
1500
|
}
|
1501
|
else
|
1502
|
fn.Add(s);
|
1503
|
bidname = true;
|
1504
|
}
|
1505
|
|
1506
|
void FileSel::GoToPlace()
|
1507
|
{
|
1508
|
if(places.IsCursor()) {
|
1509
|
dir <<= places.GetKey();
|
1510
|
Load();
|
1511
|
}
|
1512
|
}
|
1513
|
|
1514
|
bool FileSel::Execute(int _mode) {
|
1515
|
mode = _mode;
|
1516
|
|
1517
|
int system_row = -1;
|
1518
|
for(int i = places.GetCount() - 1; i >= 0; i--) {
|
1519
|
if(places.Get(i, 3) == "PLACES:SYSTEM") {
|
1520
|
system_row = i;
|
1521
|
places.Remove(i);
|
1522
|
}
|
1523
|
}
|
1524
|
AddSystemPlaces(system_row);
|
1525
|
|
1526
|
if(mode == SELECTDIR) {
|
1527
|
if(!fn.IsEmpty())
|
1528
|
dir <<= NormalizePath(fn[0]);
|
1529
|
type.Hide();
|
1530
|
type_lbl.Hide();
|
1531
|
file.Hide();
|
1532
|
file_lbl.Hide();
|
1533
|
sortext.Hide();
|
1534
|
sort_lbl.Hide();
|
1535
|
ok.SetLabel(t_("&Select"));
|
1536
|
Logc p = filename.GetPos().y;
|
1537
|
int q = ok.GetPos().y.GetA() + ok.GetPos().y.GetB() + 8;
|
1538
|
p.SetA(q);
|
1539
|
filename.SetPosY(p);
|
1540
|
filesize.SetPosY(p);
|
1541
|
filetime.SetPosY(p);
|
1542
|
p = splitter.Ctrl::GetPos().y;
|
1543
|
p.SetB(q + 20);
|
1544
|
splitter.SetPosY(p);
|
1545
|
LogPos ps = search.GetPos();
|
1546
|
LogPos pl = sort_lbl.GetPos();
|
1547
|
pl.x.SetB(ps.x.GetB());
|
1548
|
pl.y.SetA(ok.GetPos().y.GetA());
|
1549
|
pl.y.SetB(ps.y.GetB());
|
1550
|
search.SetPos(pl);
|
1551
|
bidname = false;
|
1552
|
}
|
1553
|
else {
|
1554
|
for(Ctrl *q = GetFirstChild(); q; q = q->GetNext())
|
1555
|
if(q != &mkdir)
|
1556
|
q->Show();
|
1557
|
Rect r = GetRect();
|
1558
|
CtrlLayout(*this);
|
1559
|
ArrangeOKCancel(ok, cancel);
|
1560
|
SetRect(r);
|
1561
|
}
|
1562
|
readonly.Show(rdonly && mode == OPEN);
|
1563
|
list.Multi(multi && (mode == OPEN || mode == SELECTDIR));
|
1564
|
list.SelectDir(multi && mode == SELECTDIR);
|
1565
|
dir.ClearList();
|
1566
|
file <<= Null;
|
1567
|
if(basedir.IsEmpty()) {
|
1568
|
dir.Add(GetHomeDirectory());
|
1569
|
#ifdef PLATFORM_POSIX
|
1570
|
Array<FileSystemInfo::FileInfo> root = filesystem->Find("/media/*");
|
1571
|
dir.Add(GetDesktopFolder());
|
1572
|
dir.Add("/");
|
1573
|
for(int i = 0; i < root.GetCount(); i++) {
|
1574
|
String ugly = root[i].filename;
|
1575
|
if(ugly[0] != '.') {
|
1576
|
dir.Add("/media/" + root[i].filename);
|
1577
|
}
|
1578
|
}
|
1579
|
#else
|
1580
|
dir.Add(GetDesktopFolder());
|
1581
|
Array<FileSystemInfo::FileInfo> root = filesystem->Find(Null);
|
1582
|
for(int i = 0; i < root.GetCount(); i++) {
|
1583
|
String ugly = root[i].filename;
|
1584
|
if(ugly != "A:\\" && ugly != "B:\\") {
|
1585
|
ugly.Cat('\0');
|
1586
|
ugly.Cat(root[i].root_style);
|
1587
|
dir.Add(root[i].filename, ugly);
|
1588
|
}
|
1589
|
}
|
1590
|
if(filesystem == &StdFileSystemInfo())
|
1591
|
dir.Add("\\", String(t_("Network")) + String(0, 1) + "\xff");
|
1592
|
#endif
|
1593
|
if(filesystem->IsPosix() && String(~dir).IsEmpty())
|
1594
|
dir <<= GetHomeDirectory();
|
1595
|
if(lru.GetCount())
|
1596
|
dir.AddSeparator();
|
1597
|
for(int i = 0; i < lru.GetCount(); i++)
|
1598
|
if(IsFullPath(lru[i]) && filesystem->FolderExists(lru[i]))
|
1599
|
dir.Add(lru[i]);
|
1600
|
dir.SetDisplay(Single<FolderDisplay>(), max(16, Draw::GetStdFontCy()));
|
1601
|
}
|
1602
|
else {
|
1603
|
dir.SetDisplay(Single<HomeDisplay>(), max(16, Draw::GetStdFontCy()));
|
1604
|
if(filesystem->IsPosix()) {
|
1605
|
if(String(~dir)[0] == '/')
|
1606
|
dir <<= "";
|
1607
|
}
|
1608
|
}
|
1609
|
Rect lr = splitter.GetRect();
|
1610
|
Rect dr = dir.GetRect();
|
1611
|
int dp = max(20, dir.Ctrl::GetPos().y.GetB());
|
1612
|
int px = GetSize().cx - lr.right;
|
1613
|
|
1614
|
|
1615
|
|
1616
|
|
1617
|
|
1618
|
|
1619
|
|
1620
|
|
1621
|
|
1622
|
|
1623
|
toggle.Hide();
|
1624
|
minus.Hide();
|
1625
|
plus.Hide();
|
1626
|
|
1627
|
if(mkdir.IsShown()) {
|
1628
|
mkdir.RightPos(px, dp).TopPos(dr.top, dp);
|
1629
|
dirup.RightPos(px + dp, dp).TopPos(dr.top, dp);
|
1630
|
px += 2 * dp;
|
1631
|
}
|
1632
|
else {
|
1633
|
dirup.RightPos(px, dp).TopPos(dr.top, dp);
|
1634
|
px += dp;
|
1635
|
}
|
1636
|
dir.HSizePos(dr.left, px + 4);
|
1637
|
int q = type.FindValue(activetype);
|
1638
|
if(q >= 0)
|
1639
|
type <<= q;
|
1640
|
else
|
1641
|
if(type.GetCount())
|
1642
|
type.SetIndex(0);
|
1643
|
int dlc = type.GetCount();
|
1644
|
Load();
|
1645
|
ActiveFocus(file.IsEditable() ? (Ctrl&)file : (Ctrl&)list);
|
1646
|
if(bidname) {
|
1647
|
String s;
|
1648
|
for(int i = 0; i < fn.GetCount(); i++)
|
1649
|
Catq(s, fn[i]);
|
1650
|
file <<= s;
|
1651
|
ActiveFocus(file);
|
1652
|
bidname = false;
|
1653
|
}
|
1654
|
list.SetSbPos(lastsby);
|
1655
|
if(preselect.GetCount()) {
|
1656
|
for(int i = 0; i < list.GetCount(); i++)
|
1657
|
if(list[i].name == preselect) {
|
1658
|
list.SetCursor(i);
|
1659
|
ActiveFocus(list);
|
1660
|
break;
|
1661
|
}
|
1662
|
preselect.Clear();
|
1663
|
}
|
1664
|
FileUpdate();
|
1665
|
Update();
|
1666
|
int c = TopWindow::Run(appmodal);
|
1667
|
TopWindow::Close();
|
1668
|
lastsby = list.GetSbPos();
|
1669
|
if(IsNumber(~type)) {
|
1670
|
int ti = ~type;
|
1671
|
type.Trim(dlc);
|
1672
|
if(ti >= 0 && ti < type.GetCount())
|
1673
|
activetype = type.GetValue(ti);
|
1674
|
}
|
1675
|
else
|
1676
|
type.Trim(dlc);
|
1677
|
if(c == IDOK) {
|
1678
|
String d = ~dir;
|
1679
|
if(filesystem->IsWin32())
|
1680
|
if(d.GetLength() == 3 && d[1] == ':') return true;
|
1681
|
if(filesystem->IsPosix())
|
1682
|
if(d == "/") return true;
|
1683
|
if(!IsFullPath(d)) return true;
|
1684
|
LruAdd(lru, d, 8);
|
1685
|
return true;
|
1686
|
}
|
1687
|
return false;
|
1688
|
}
|
1689
|
|
1690
|
bool FileSel::ExecuteOpen(const char *title) {
|
1691
|
Title(title ? title : t_("Open"));
|
1692
|
return Execute(OPEN);
|
1693
|
}
|
1694
|
|
1695
|
bool FileSel::ExecuteSaveAs(const char *title) {
|
1696
|
Title(title ? title : t_("Save as"));
|
1697
|
ok.SetLabel(t_("Save"));
|
1698
|
return Execute(SAVEAS);
|
1699
|
}
|
1700
|
|
1701
|
bool FileSel::ExecuteSelectDir(const char *title)
|
1702
|
{
|
1703
|
Title(title ? title : t_("Select directory"));
|
1704
|
return Execute(SELECTDIR);
|
1705
|
}
|
1706
|
|
1707
|
void FileSel::Serialize(Stream& s) {
|
1708
|
#ifdef PLATFORM_WIN32
|
1709
|
if(s.IsLoading()) {
|
1710
|
netnode.Clear();
|
1711
|
netstack.Clear();
|
1712
|
}
|
1713
|
#endif
|
1714
|
int version = 10;
|
1715
|
s / version;
|
1716
|
String ad = ~dir;
|
1717
|
int dummy = 0;
|
1718
|
if(version < 10)
|
1719
|
s / dummy;
|
1720
|
else
|
1721
|
s % activetype;
|
1722
|
s % ad;
|
1723
|
dir <<= ad;
|
1724
|
if(version < 1) {
|
1725
|
String n = fn.At(0);
|
1726
|
s % n;
|
1727
|
fn.At(0) = n;
|
1728
|
}
|
1729
|
else {
|
1730
|
if(version < 4)
|
1731
|
s % fn;
|
1732
|
else {
|
1733
|
Vector<String> __;
|
1734
|
s % __;
|
1735
|
}
|
1736
|
}
|
1737
|
if(version >= 2) {
|
1738
|
SerializePlacement(s);
|
1739
|
list.SerializeSettings(s);
|
1740
|
}
|
1741
|
if(version >= 3) {
|
1742
|
s % lastsby;
|
1743
|
}
|
1744
|
if(version >= 4) {
|
1745
|
s % lru;
|
1746
|
}
|
1747
|
if(version >= 5) {
|
1748
|
s % sortext;
|
1749
|
}
|
1750
|
if(version >= 6) {
|
1751
|
if(version >= 9)
|
1752
|
s % splitter;
|
1753
|
else {
|
1754
|
Splitter dummy;
|
1755
|
s % dummy;
|
1756
|
}
|
1757
|
}
|
1758
|
if(version >= 7) {
|
1759
|
s % hidden;
|
1760
|
}
|
1761
|
if(version >= 8) {
|
1762
|
s % hiddenfiles;
|
1763
|
}
|
1764
|
}
|
1765
|
|
1766
|
String FileSel::GetFile(int i) const {
|
1767
|
String p;
|
1768
|
if(i >= 0 && i < fn.GetCount()) {
|
1769
|
p = fn[i];
|
1770
|
if(!IsFullPath(p))
|
1771
|
p = AppendFileName(dir.GetData(), p);
|
1772
|
}
|
1773
|
return p;
|
1774
|
}
|
1775
|
|
1776
|
void FileSel::SyncSplitter()
|
1777
|
{
|
1778
|
splitter.Clear();
|
1779
|
if(places.GetCount() && basedir.IsEmpty())
|
1780
|
splitter.Add(places);
|
1781
|
splitter.Add(list);
|
1782
|
if(preview)
|
1783
|
splitter.Add(*preview);
|
1784
|
}
|
1785
|
|
1786
|
FileSel& FileSel::PreSelect(const String& path)
|
1787
|
{
|
1788
|
ActiveDir(GetFileFolder(path));
|
1789
|
preselect = GetFileName(path);
|
1790
|
return *this;
|
1791
|
}
|
1792
|
|
1793
|
void FileSel::InitSplitter()
|
1794
|
{
|
1795
|
int n = splitter.GetCount();
|
1796
|
int i = 0;
|
1797
|
if(places.GetCount())
|
1798
|
splitter.SetPos(2000, i++);
|
1799
|
splitter.SetPos(10000 - 2000 * (n - 1), i);
|
1800
|
}
|
1801
|
|
1802
|
FileSel& FileSel::Preview(Ctrl& ctrl)
|
1803
|
{
|
1804
|
if(!preview) {
|
1805
|
Size sz = GetRect().GetSize();
|
1806
|
sz.cx = 5 * sz.cx / 3;
|
1807
|
SetRect(sz);
|
1808
|
}
|
1809
|
preview = &ctrl;
|
1810
|
SyncSplitter();
|
1811
|
InitSplitter();
|
1812
|
return *this;
|
1813
|
}
|
1814
|
|
1815
|
FileSel& FileSel::Preview(const Display& d)
|
1816
|
{
|
1817
|
preview_display.SetDisplay(d);
|
1818
|
return Preview(preview_display);
|
1819
|
}
|
1820
|
|
1821
|
void FileSel::AddPlaceRaw(const String& path, const Image& m, const String& name, const char* group, int row)
|
1822
|
{
|
1823
|
if(path.GetCount()) {
|
1824
|
row = row < 0 ? places.GetCount() : row;
|
1825
|
places.Insert(row);
|
1826
|
places.Set(row, 0, path);
|
1827
|
places.Set(row, 1, m);
|
1828
|
places.Set(row, 2, name);
|
1829
|
places.Set(row, 3, group);
|
1830
|
places.SetLineCy(row, max(m.GetSize().cy + 4, GetStdFontCy() + 4));
|
1831
|
SyncSplitter();
|
1832
|
InitSplitter();
|
1833
|
}
|
1834
|
}
|
1835
|
|
1836
|
FileSel& FileSel::AddPlace(const String& path, const Image& m, const String& name, const char* group, int row)
|
1837
|
{
|
1838
|
if(path.GetCount())
|
1839
|
AddPlaceRaw(NormalizePath(path), m, name, group, row);
|
1840
|
return *this;
|
1841
|
}
|
1842
|
|
1843
|
FileSel& FileSel::AddPlace(const String& path, const String& name, const char* group, int row)
|
1844
|
{
|
1845
|
return AddPlace(path, GetDirIcon(NormalizePath(path)), name, group, row);
|
1846
|
}
|
1847
|
|
1848
|
FileSel& FileSel::AddPlace(const String& path, const char* group, int row)
|
1849
|
{
|
1850
|
return AddPlace(path, GetFileTitle(path), group, row);
|
1851
|
}
|
1852
|
|
1853
|
FileSel& FileSel::AddPlaceSeparator()
|
1854
|
{
|
1855
|
places.AddSeparator();
|
1856
|
SyncSplitter();
|
1857
|
InitSplitter();
|
1858
|
return *this;
|
1859
|
}
|
1860
|
|
1861
|
FileSel& FileSel::ClearPlaces()
|
1862
|
{
|
1863
|
places.Clear();
|
1864
|
SyncSplitter();
|
1865
|
return *this;
|
1866
|
}
|
1867
|
|
1868
|
void FileSel::AddSystemPlaces(int row)
|
1869
|
{
|
1870
|
row = row < 0 ? places.GetCount() : row;
|
1871
|
Array<FileSystemInfo::FileInfo> root;
|
1872
|
#if defined(PLATFORM_WIN32) || defined(PLATFORM_WINCE)
|
1873
|
root = filesystem->Find(Null);
|
1874
|
for(int i = 0; i < root.GetCount(); i++) {
|
1875
|
String desc = root[i].root_desc;
|
1876
|
String n = root[i].filename;
|
1877
|
if(n != "A:\\" && n != "B:\\") {
|
1878
|
#ifdef PLATFORM_WIN32
|
1879
|
if(*n.Last() == '\\')
|
1880
|
n.Trim(n.GetCount() - 1);
|
1881
|
#endif
|
1882
|
if(desc.GetCount() == 0)
|
1883
|
desc << " " << t_("Local Disk");
|
1884
|
desc << " (" << n << ")";
|
1885
|
AddPlace(root[i].filename, desc, "PLACES:SYSTEM", row++);
|
1886
|
}
|
1887
|
}
|
1888
|
#endif
|
1889
|
|
1890
|
#ifdef PLATFORM_WIN32
|
1891
|
if(GetSystemMetrics(SM_REMOTESESSION))
|
1892
|
for(int drive = 'A'; drive < 'Z'; drive++) {
|
1893
|
String path = Format("\\\\tsclient\\%c", drive);
|
1894
|
if(FindFile(path + "\\*.*"))
|
1895
|
AddPlace(path, Format(t_("%c on client"), drive), "PLACES:SYSTEM", row++);
|
1896
|
}
|
1897
|
#endif
|
1898
|
|
1899
|
#ifdef PLATFORM_POSIX
|
1900
|
root = filesystem->Find("/media/*");
|
1901
|
for(int i = 0; i < root.GetCount(); i++) {
|
1902
|
String fn = root[i].filename;
|
1903
|
if(*fn != '.' && fn.Find("floppy") < 0)
|
1904
|
AddPlace("/media/" + fn, fn, "PLACES:SYSTEM", row++);
|
1905
|
}
|
1906
|
#endif
|
1907
|
}
|
1908
|
|
1909
|
FileSel& FileSel::AddStandardPlaces()
|
1910
|
{
|
1911
|
AddPlace(GetHomeDirectory(), t_("Home"), "PLACES:FOLDER");
|
1912
|
AddPlace(GetDesktopFolder(), t_("Desktop"), "PLACES:FOLDER");
|
1913
|
AddPlace(GetMusicFolder(), t_("Music"), "PLACES:FOLDER");
|
1914
|
AddPlace(GetPicturesFolder(), t_("Pictures"), "PLACES:FOLDER");
|
1915
|
AddPlace(GetVideoFolder(), t_("Videos"), "PLACES:FOLDER");
|
1916
|
AddPlace(GetDocumentsFolder(), t_("Documents"), "PLACES:FOLDER");
|
1917
|
AddPlace(GetDownloadFolder(), t_("Downloads"), "PLACES:FOLDER");
|
1918
|
AddPlaceSeparator();
|
1919
|
AddSystemPlaces();
|
1920
|
#ifdef PLATFORM_WIN32
|
1921
|
AddPlaceSeparator();
|
1922
|
AddPlaceRaw("\\", CtrlImg::Network(), t_("Network"), "PLACES:NETWORK");
|
1923
|
#endif
|
1924
|
return *this;
|
1925
|
}
|
1926
|
|
1927
|
struct DisplayPlace : Display {
|
1928
|
virtual void Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper,
|
1929
|
dword style) const
|
1930
|
{
|
1931
|
w.DrawRect(r, paper);
|
1932
|
ValueArray va = q;
|
1933
|
Image m = va[0];
|
1934
|
String txt = va[1];
|
1935
|
Size isz = m.GetSize();
|
1936
|
w.DrawImage(r.left, r.top + (r.Height() - isz.cy) / 2, m);
|
1937
|
w.DrawText(r.left + isz.cx + 2, r.top + (r.Height() - GetStdFontCy()) / 2, txt,
|
1938
|
StdFont(), ink);
|
1939
|
}
|
1940
|
virtual Size GetStdSize(const Value& q) const {
|
1941
|
ValueArray va = q;
|
1942
|
Image m = va[0];
|
1943
|
String txt = va[1];
|
1944
|
Size isz = m.GetSize();
|
1945
|
return Size(isz.cx + GetTextSize(txt, StdFont()).cx + 2, max(isz.cy, GetStdFontCy()));
|
1946
|
}
|
1947
|
};
|
1948
|
|
1949
|
FileSel::FileSel() {
|
1950
|
filesystem = &StdFileSystemInfo();
|
1951
|
CtrlLayout(*this);
|
1952
|
ArrangeOKCancel(ok, cancel);
|
1953
|
Acceptor(ok, IDOK); ok.Ok();
|
1954
|
Rejector(cancel, IDCANCEL); cancel.Cancel();
|
1955
|
list.IconWidth(16).Renaming().Columns(3).ClickKill();
|
1956
|
list.WhenLeftDouble = THISBACK(OpenItem2);
|
1957
|
dirup <<= THISBACK(DirUp);
|
1958
|
Add(dirup);
|
1959
|
sortext <<= THISBACK(SearchLoad);
|
1960
|
Add(sortext);
|
1961
|
hidden <<= THISBACK(SearchLoad);
|
1962
|
Add(hidden);
|
1963
|
hiddenfiles <<= THISBACK(SearchLoad);
|
1964
|
Add(hiddenfiles);
|
1965
|
mkdir <<= THISBACK(MkDir);
|
1966
|
Add(mkdir);
|
1967
|
plus <<= THISBACK(Plus);
|
1968
|
Add(plus);
|
1969
|
minus <<= THISBACK(Minus);
|
1970
|
Add(minus);
|
1971
|
toggle <<= THISBACK(Toggle);
|
1972
|
Add(toggle);
|
1973
|
|
1974
|
ok <<= THISBACK(Open);
|
1975
|
list <<= THISBACK(Update);
|
1976
|
file <<= THISBACK(FileUpdate);
|
1977
|
list.WhenRename = THISBACK(Rename);
|
1978
|
Sizeable();
|
1979
|
dirup.SetImage(CtrlImg::DirUp()).NoWantFocus();
|
1980
|
dirup.Tip(t_("Dir up") + String(" (Ctrl+Up)"));
|
1981
|
mkdir.SetImage(CtrlImg::MkDir()).NoWantFocus();
|
1982
|
mkdir.Tip(t_("Create directory") + String(" (F7)"));
|
1983
|
plus.SetImage(CtrlImg::Plus()).NoWantFocus();
|
1984
|
plus.Tip(t_("Select files"));
|
1985
|
minus.SetImage(CtrlImg::Minus()).NoWantFocus();
|
1986
|
minus.Tip(t_("Unselect files"));
|
1987
|
toggle.SetImage(CtrlImg::Toggle()).NoWantFocus();
|
1988
|
toggle.Tip(t_("Toggle files"));
|
1989
|
type <<= THISBACK(Load);
|
1990
|
sortext <<= 0;
|
1991
|
|
1992
|
search.NullText(t_("Search"), StdFont().Italic(), SColorDisabled());
|
1993
|
search.SetFilter(CharFilterDefaultToUpperAscii);
|
1994
|
search <<= THISBACK(SearchLoad);
|
1995
|
|
1996
|
filename.SetFont(StdFont());
|
1997
|
filename.SetFrame(ThinInsetFrame());
|
1998
|
filesize.SetFont(StdFont()).SetAlign(ALIGN_RIGHT);
|
1999
|
filesize.SetFrame(ThinInsetFrame());
|
2000
|
filetime.SetFont(StdFont());
|
2001
|
filetime.SetFrame(ThinInsetFrame());
|
2002
|
|
2003
|
dir <<= THISBACK(Choice);
|
2004
|
dir.DisplayAll();
|
2005
|
dir.SetDropLines(24);
|
2006
|
|
2007
|
readonly.Hide();
|
2008
|
|
2009
|
lastsby = 0;
|
2010
|
|
2011
|
asking = true;
|
2012
|
rdonly = false;
|
2013
|
multi = false;
|
2014
|
bidname = false;
|
2015
|
appmodal = true;
|
2016
|
|
2017
|
AddChildBefore(GetFirstChild(), &sizegrip);
|
2018
|
|
2019
|
preview = NULL;
|
2020
|
preview_display.SetFrame(FieldFrame());
|
2021
|
|
2022
|
SyncSplitter();
|
2023
|
|
2024
|
BackPaintHint();
|
2025
|
|
2026
|
places.AddKey();
|
2027
|
places.AddColumn().AddIndex().SetDisplay(Single<DisplayPlace>());
|
2028
|
places.AddIndex();
|
2029
|
places.NoHeader().NoGrid();
|
2030
|
places.WhenLeftClick = THISBACK(GoToPlace);
|
2031
|
places.NoWantFocus();
|
2032
|
|
2033
|
#ifdef PLATFORM_WIN32
|
2034
|
list.IconWidth(GetFileIcon(GetHomeDirectory(), true, false, false).GetSize().cx);
|
2035
|
#endif
|
2036
|
|
2037
|
AddStandardPlaces();
|
2038
|
list.AutoHideSb();
|
2039
|
list.NoRoundSize();
|
2040
|
places.AutoHideSb();
|
2041
|
}
|
2042
|
|
2043
|
FileSel::~FileSel() {}
|
2044
|
|
2045
|
END_UPP_NAMESPACE
|