1 #include <CtrlLib/CtrlLib.h>
2
3 namespace Upp {
4
5 #ifdef GUI_WIN
6 void AvoidPaintingCheck__();
7
ProcessSHIcon(HICON hIcon)8 Image ProcessSHIcon(HICON hIcon)
9 {
10 AvoidPaintingCheck__();
11 Color c = White();
12 Image m[2];
13 for(int i = 0; i < 2; i++) {
14 ICONINFO iconinfo;
15 if(!hIcon || !GetIconInfo(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, 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(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
KeyUpp::FileIconMaker38 virtual String Key() const {
39 return file + (exe ? "1" : "0") + (dir ? "1" : "0");
40 }
41
MakeUpp::FileIconMaker42 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.hIcon);
49 }
50 };
51
52
GetFileIcon(const char * path,bool dir,bool force,bool large,bool quick=false)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(findarg(ext, ".exe", ".lnk") >= 0)
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(GUI_GTK)
85
86 Image GtkThemeIcon(const char *name, int sz);
87
GnomeImage(const char * s,bool large=false)88 Image GnomeImage(const char *s, bool large = false)
89 {
90 return GtkThemeIcon(String("gnome-") + s, DPI(large ? 48 : 16));
91 }
92
SystemImage(const char * s,bool large=false)93 Image SystemImage(const char *s, bool large = false)
94 {
95 return GtkThemeIcon(s, DPI(large ? 48 : 16));
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
Load(const char * fn)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
Refresh()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
GetMime(const String & ext,String & maj,String & min)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
KeyUpp::FileExtMaker159 virtual String Key() const {
160 return ext;
161 }
162
MakeUpp::FileExtMaker163 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
PosixGetDriveImage(String dir,bool large)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
GetFileIcon(const String & folder,const String & filename,bool isdir,bool isexe,bool large)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 // Fixing format problems
361 if (m.ext == ".gz") m.ext = ".tar.gz";
362
363 // Ultimate++ - files extensions
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 // Binary - files extensions (It seems that KDE has problem with multimedia MIME icons handling)
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 #ifdef PLATFORM_COCOA
398 struct FileIconMaker : ImageMaker {
399 String file;
400 bool exe;
401 bool dir;
402 bool large;
403
KeyUpp::FileIconMaker404 virtual String Key() const {
405 return file + (exe ? "1" : "0") + (dir ? "1" : "0");
406 }
407
MakeUpp::FileIconMaker408 virtual Image Make() const {
409 return GetIconForFile(file);
410 }
411 };
412
413 #define GETFILEICON_DEFINED
414
GetFileIcon(const char * path,bool dir,bool exe,bool large,bool quick=false)415 Image GetFileIcon(const char *path, bool dir, bool exe, bool large, bool quick = false)
416 {
417 FileIconMaker m;
418 m.exe = exe;
419 m.dir = dir;
420 m.file = path;
421 m.large = large;
422 return MakeImage(m);
423 }
424 #endif
425
426 #ifndef GETFILEICON_DEFINED
PosixGetDriveImage(String dir,bool)427 Image PosixGetDriveImage(String dir, bool)
428 {
429 if(dir.GetCount() == 0 || dir == "/")
430 return CtrlImg::Computer();
431 if(dir.Find("cdrom") == 0 || dir.Find("cdrecorder") == 0)
432 return CtrlImg::CdRom();
433 if(dir.Find("floppy") == 0 || dir.Find("zip") == 0)
434 return CtrlImg::Diskette();
435 return CtrlImg::Hd();
436 }
437
438 #ifdef PLATFORM_WIN32
GetFileIcon(const String & folder,bool,bool,bool,bool=false)439 Image GetFileIcon(const String& folder, bool, bool, bool, bool = false)
440 {
441 return CtrlImg::File();
442 }
443 #else
GetFileIcon(const String & folder,const String & filename,bool isdir,bool isexe,bool=false)444 Image GetFileIcon(const String& folder, const String& filename, bool isdir, bool isexe, bool = false)
445 {
446 return isdir ? CtrlImg::Dir() : CtrlImg::File();
447 }
448
449 #endif
450 #endif
451
NativePathIcon0(const char * path,bool folder,bool large)452 Image NativePathIcon0(const char *path, bool folder, bool large)
453 {
454 #if defined(PLATFORM_WIN32)
455 if (folder)
456 return GetFileIcon(path, true, true, large);
457 else
458 return GetFileIcon(path, false, false, large);
459 #endif
460 #ifdef PLATFORM_POSIX
461 String p = path;
462 FindFile ff(path);
463 #ifdef PLATFORM_COCOA
464 return GetFileIcon(path, folder, ff.GetMode() & 0111, large);
465 #else
466 bool isdrive = folder && ((p == "/media") || (p == "/mnt"));
467 return isdrive ? PosixGetDriveImage(GetFileName(path), large)
468 : GetFileIcon(path, GetFileName(path), folder, ff.GetMode() & 0111, large);
469 #endif
470 #endif
471 }
472
NativePathIcon(const char * path,bool folder)473 Image NativePathIcon(const char *path, bool folder)
474 {
475 return NativePathIcon0(path, folder, false);
476 }
477
NativePathIcon(const char * path)478 Image NativePathIcon(const char *path)
479 {
480 FindFile ff(path);
481 return NativePathIcon(path, ff.IsFolder());
482 }
483
NativePathLargeIcon(const char * path,bool folder)484 Image NativePathLargeIcon(const char *path, bool folder)
485 {
486 return NativePathIcon0(path, folder, true);
487 }
488
NativePathLargeIcon(const char * path)489 Image NativePathLargeIcon(const char *path)
490 {
491 FindFile ff(path);
492 return NativePathLargeIcon(path, ff.IsFolder());
493 }
494
MatchSearch(const String & filename,const String & search)495 bool MatchSearch(const String& filename, const String& search)
496 {
497 return search.GetCount() ? Filter(filename, CharFilterDefaultToUpperAscii).Find(search) >= 0 : true;
498 }
499
Load(FileList & list,const String & dir,const char * patterns,bool dirs,Event<bool,const String &,Image &> WhenIcon,FileSystemInfo & filesystem,const String & search,bool hidden,bool hiddenfiles,bool lazyicons)500 bool Load(FileList& list, const String& dir, const char *patterns, bool dirs,
501 Event<bool, const String&, Image&> WhenIcon, FileSystemInfo& filesystem,
502 const String& search, bool hidden, bool hiddenfiles, bool lazyicons)
503 {
504 if(dir.IsEmpty()) {
505 Array<FileSystemInfo::FileInfo> root = filesystem.Find(Null);
506 for(int i = 0; i < root.GetCount(); i++)
507 if(MatchSearch(root[i].filename, search))
508 list.Add(root[i].filename,
509 GetDriveImage(root[i].root_style),
510 StdFont().Bold(), SColorText, true, -1, Null, SColorDisabled,
511 #ifdef PLATFORM_WIN32
512 Nvl(root[i].root_desc, String(" ") + t_("Local Disk")),
513 #else
514 root[i].root_desc,
515 #endif
516 StdFont()
517 );
518 #ifdef PLATFORM_WIN32
519 list.Add(t_("Network"), CtrlImg::Network(), StdFont().Bold(), SColorText,
520 true, -1, Null, SColorDisabled, Null, StdFont());
521 #endif
522 }
523 else {
524 Array<FileSystemInfo::FileInfo> ffi =
525 filesystem.Find(AppendFileName(dir, filesystem.IsWin32() ? "*.*" : "*"));
526 if(ffi.IsEmpty())
527 return false;
528 #if defined(PLATFORM_POSIX) && !defined(PLATFORM_COCOA)
529 bool isdrive = dir == "/media" || dir == "/mnt";
530 #endif
531 for(int t = 0; t < ffi.GetCount(); t++) {
532 const FileSystemInfo::FileInfo& fi = ffi[t];
533 bool nd = dirs && !fi.is_directory;
534 bool show = hidden;
535 if(!show && filesystem.IsWin32() ? !fi.is_hidden : fi.filename[0] != '.')
536 show = true;
537 if(!show && hiddenfiles && fi.is_file)
538 show = true;
539 if(fi.filename != "." && fi.filename != ".." &&
540 #ifdef PLATFORM_WIN32
541 (fi.is_directory || FileSel::IsLnkFile(fi.filename) || PatternMatchMulti(patterns, fi.filename)) &&
542 #else
543 (fi.is_directory || PatternMatchMulti(patterns, fi.filename)) &&
544 #endif
545 MatchSearch(fi.filename, search) && show) {
546 Image img;
547 #ifdef PLATFORM_POSIX
548 #ifdef PLATFORM_COCOA
549 img = GetFileIcon(AppendFileName(dir, fi.filename), fi.is_directory, fi.unix_mode & 0111, false, lazyicons);
550 #else
551 img = isdrive ? PosixGetDriveImage(fi.filename, false)
552 : GetFileIcon(dir, fi.filename, fi.is_directory, fi.unix_mode & 0111, false);
553 #endif
554 #endif
555 #ifdef GUI_WIN
556 img = GetFileIcon(AppendFileName(dir, fi.filename), fi.is_directory, false, false, lazyicons);
557 #endif
558 if(IsNull(img))
559 img = fi.is_directory ? CtrlImg::Dir() : CtrlImg::File();
560 WhenIcon(fi.is_directory, fi.filename, img);
561 list.Add(fi.filename, fi.is_hidden ? Contrast(img, 200) : img,
562 StdFont().Bold(fi.is_directory),
563 nd ? SColorDisabled : fi.is_hidden ? Blend(SColorText, Gray, 200) : SColorText, fi.is_directory,
564 fi.is_directory ? -1 : fi.length,
565 fi.last_write_time,
566 nd ? SColorDisabled
567 : fi.is_directory ? SColorText
568 : fi.is_hidden ? Blend(SColorMark, Gray, 200)
569 : SColorMark,
570 Null, Null, Null, Null,
571 #ifdef PLATFORM_WIN32
572 false,
573 #else
574 fi.unix_mode & 0111,
575 #endif
576 fi.is_hidden
577 );
578 }
579 }
580 }
581 return true;
582 }
583
584 #ifdef GUI_WIN
585 static Mutex sExeMutex;
586 static wchar sExePath[1025];
587 static bool sExeRunning;
588 static SHFILEINFOW sExeInfo;
589
sExeIconThread(void *)590 static auxthread_t auxthread__ sExeIconThread(void *)
591 {
592 SHFILEINFOW info;
593 wchar path[1025];
594 CoInitialize(NULL);
595 sExeMutex.Enter();
596 wcscpy(path, sExePath);
597 sExeMutex.Leave();
598 AvoidPaintingCheck__();
599 SHGetFileInfoW(path, FILE_ATTRIBUTE_NORMAL, &info, sizeof(info), SHGFI_ICON|SHGFI_SMALLICON);
600 sExeMutex.Enter();
601 memcpy(&sExeInfo, &info, sizeof(info));
602 sExeRunning = false;
603 sExeMutex.Leave();
604 return 0;
605 }
606
Done(Image img)607 void LazyExeFileIcons::Done(Image img)
608 {
609 if(pos >= ndx.GetCount())
610 return;
611 int ii = ndx[pos];
612 if(ii < 0 || ii >= list->GetCount())
613 return;
614 const FileList::File& f = list->Get(ii);
615 WhenIcon(false, f.name, img);
616 if(!IsNull(img)) {
617 if(f.hidden)
618 img = Contrast(img, 200);
619 list->SetIcon(ii, img);
620 }
621 pos++;
622 }
623
Path()624 WString LazyExeFileIcons::Path()
625 {
626 if(pos >= ndx.GetCount())
627 return Null;
628 int ii = ndx[pos];
629 if(ii < 0 || ii >= list->GetCount())
630 return Null;
631 const FileList::File& f = list->Get(ii);
632 return NormalizePath(AppendFileName(dir, f.name)).ToWString();
633 }
634
Do()635 void LazyExeFileIcons::Do()
636 {
637 int start = msecs();
638 for(;;) {
639 for(;;) {
640 SHFILEINFOW info;
641 bool done = false;
642 WString path = Path();
643 if(IsNull(path))
644 return;
645 sExeMutex.Enter();
646 bool running = sExeRunning;
647 if(!running) {
648 done = path == sExePath;
649 memcpy(&info, &sExeInfo, sizeof(info));
650 *sExePath = '\0';
651 memset(&sExeInfo, 0, sizeof(sExeInfo));
652 }
653 sExeMutex.Leave();
654 Image img = ProcessSHIcon(info.hIcon);
655 if(done)
656 Done(img);
657 if(!running)
658 break;
659 Sleep(0);
660 if(msecs(start) > 10 || Ctrl::IsWaitingEvent()) {
661 Restart(0);
662 return;
663 }
664 }
665
666 WString path = Path();
667 if(IsNull(path))
668 return;
669 sExeMutex.Enter();
670 memcpy(sExePath, ~path, 2 * min(1024, path.GetCount() + 1));
671 sExeRunning = true;
672 StartAuxThread(sExeIconThread, NULL);
673 sExeMutex.Leave();
674 }
675 }
676
ReOrder()677 void LazyExeFileIcons::ReOrder()
678 { // gather .exe and .lnk files; sort based on length so that small .exe get resolved first
679 ndx.Clear();
680 Vector<int> len;
681 for(int i = 0; i < list->GetCount(); i++) {
682 const FileList::File& f = list->Get(i);
683 if(findarg(ToLower(GetFileExt(f.name)), ".exe", ".lnk") >= 0 && !f.isdir) {
684 ndx.Add(i);
685 len.Add((int)min((int64)INT_MAX, f.length));
686 }
687 }
688 IndexSort(len, ndx);
689 Restart(0);
690 }
691
Start(FileList & list_,const String & dir_,Event<bool,const String &,Image &> WhenIcon_)692 void LazyExeFileIcons::Start(FileList& list_, const String& dir_, Event<bool, const String&, Image&> WhenIcon_)
693 {
694 list = &list_;
695 dir = dir_;
696 WhenIcon = WhenIcon_;
697 pos = 0;
698 ReOrder();
699 }
700 #endif
701
GetDir() const702 String FileSel::GetDir() const
703 {
704 String s = ~dir;
705 if(s.IsEmpty()) return basedir;
706 if(basedir.IsEmpty()) return s;
707 return AppendFileName(basedir, s);
708 }
709
SetDir(const String & _dir)710 void FileSel::SetDir(const String& _dir) {
711 #ifdef PLATFORM_WIN32
712 netstack.Clear();
713 netnode.Clear();
714 #endif
715 dir <<= _dir;
716 Load();
717 Update();
718 }
719
FilePath(const String & fn)720 String FileSel::FilePath(const String& fn) {
721 return AppendFileName(GetDir(), fn);
722 }
723
GetDriveImage(char drive_style)724 Image GetDriveImage(char drive_style)
725 {
726 switch(drive_style)
727 {
728 case FileSystemInfo::ROOT_NO_ROOT_DIR: return Null;
729 case FileSystemInfo::ROOT_REMOTE:
730 case FileSystemInfo::ROOT_NETWORK: return CtrlImg::Share();
731 case FileSystemInfo::ROOT_COMPUTER: return CtrlImg::Computer();
732 case FileSystemInfo::ROOT_REMOVABLE: return CtrlImg::Flash();
733 case FileSystemInfo::ROOT_CDROM: return CtrlImg::CdRom();
734 default: return CtrlImg::Hd();
735 }
736 }
737
GetMask()738 String FileSel::GetMask()
739 {
740 String emask = "*";
741 if(!IsNull(type)) {
742 if(IsString(~type))
743 emask = ~type;
744 else {
745 int q = ~type;
746 if(q >= 0 && q < mask.GetCount())
747 emask = mask[q];
748 }
749 }
750 return emask;
751 }
752
Load()753 void FileSel::Load()
754 {
755 search <<= Null;
756 SearchLoad();
757 }
758
LoadNet()759 void FileSel::LoadNet()
760 {
761 #ifdef PLATFORM_WIN32
762 list.Clear();
763 for(int i = 0; i < netnode.GetCount(); i++) {
764 Image m = CtrlImg::Group();
765 switch(netnode[i].GetDisplayType()) {
766 case NetNode::NETWORK:
767 m = CtrlImg::Network();
768 break;
769 case NetNode::SHARE:
770 m = CtrlImg::Share();
771 break;
772 case NetNode::SERVER:
773 m = CtrlImg::Computer();
774 break;
775 }
776 list.Add(netnode[i].GetName(), m);
777 }
778 places.FindSetCursor("\\");
779 #endif
780 }
781
SelectNet()782 void FileSel::SelectNet()
783 {
784 #ifdef PLATFORM_WIN32
785 int q = list.GetCursor();
786 if(q >= 0 && q < netnode.GetCount()) {
787 NetNode& n = netnode[q];
788 String p = n.GetPath();
789 if(p.GetCount())
790 SetDir(p);
791 else {
792 netstack.Add() = netnode[q];
793 netnode = netstack.Top().Enum();
794 LoadNet();
795 }
796 }
797 #endif
798 }
799
SearchLoad()800 void FileSel::SearchLoad()
801 {
802 loaded = true;
803 list.EndEdit();
804 list.Clear();
805 String d = GetDir();
806 #ifdef PLATFORM_WIN32
807 if(d == "\\") {
808 netnode = NetNode::EnumRoot();
809 netnode.Append(NetNode::EnumRemembered());
810 LoadNet();
811 return;
812 }
813 #endif
814 String emask = GetMask();
815 if(!UPP::Load(list, d, emask, mode == SELECTDIR, WhenIcon, *filesystem, ~search, ~hidden, ~hiddenfiles, true)) {
816 loaded = false;
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 SortBy(list, ~sortby);
860 Update();
861 #ifdef GUI_WIN
862 lazyicons.Start(list, d, WhenIcon);
863 #endif
864 StartLI();
865 }
866
867 StaticMutex FileSel::li_mutex;
868 void (*FileSel::li_current)(const String& path, Image& result);
869 String FileSel::li_path;
870 Image FileSel::li_result;
871 bool FileSel::li_running;
872 int FileSel::li_pos;
873
LIThread()874 void FileSel::LIThread()
875 {
876 String path;
877 void (*li)(const String& path, Image& result);
878 {
879 Mutex::Lock __(li_mutex);
880 path = li_path;
881 li = li_current;
882 }
883 Image result;
884 if(path.GetCount())
885 li(path, result);
886 if(!IsNull(result) && max(result.GetWidth(), result.GetHeight()) > DPI(16))
887 result = Rescale(result, DPI(16), DPI(16));
888 {
889 Mutex::Lock __(li_mutex);
890 li_result = result;
891 li_running = false;
892 }
893 }
894
LIPath()895 String FileSel::LIPath()
896 {
897 return li_pos >= 0 && li_pos < list.GetCount() ? FilePath(list.Get(li_pos).name) : Null;
898 }
899
DoLI()900 void FileSel::DoLI()
901 {
902 int start = msecs();
903 for(;;) {
904 for(;;) {
905 bool done = false;
906 String path = LIPath();
907 if(IsNull(path))
908 return;
909 bool running;
910 Image img;
911 {
912 Mutex::Lock __(li_mutex);
913 running = li_running;
914 if(!running) {
915 done = li_path == path && li_current == WhenIconLazy;
916 img = li_result;
917 }
918 }
919 if(done) {
920 if(li_pos < 0 || li_pos >= list.GetCount())
921 return;
922 if(!IsNull(img)) {
923 const FileList::File& f = list.Get(li_pos);
924 WhenIcon(f.isdir, f.name, img);
925 if(f.hidden)
926 img = Contrast(img, 200);
927 list.SetIcon(li_pos, img);
928 }
929 li_pos++;
930 }
931 if(!running)
932 break;
933 Sleep(0);
934 if(msecs(start) > 10 || Ctrl::IsWaitingEvent()) {
935 ScheduleLI();
936 return;
937 }
938 }
939
940 String path = LIPath();
941 if(IsNull(path))
942 return;
943 {
944 Mutex::Lock __(li_mutex);
945 if(!li_running) {
946 li_current = WhenIconLazy;
947 li_path = path;
948 li_running = true;
949 Thread::Start(callback(LIThread));
950 }
951 }
952 }
953 }
954
StartLI()955 void FileSel::StartLI()
956 {
957 if(WhenIconLazy) {
958 li_pos = 0;
959 ScheduleLI();
960 }
961 }
962
TrimDot(String f)963 String TrimDot(String f) {
964 int i = f.Find('.');
965 if(i >= 0 && i == f.GetLength() - 1)
966 f.Trim(i);
967 return f;
968 }
969
AddName(Vector<String> & fn,String & f)970 void FileSel::AddName(Vector<String>& fn, String& f) {
971 if(!f.IsEmpty()) {
972 f = TrimDot(f);
973 if(f[0] == '\"' && f.GetCount() > 2)
974 f = f.Mid(1, f.GetCount() - 2);
975 if(f.Find('.') < 0) {
976 String t = GetMask();
977 int q = t.Find('.');
978 if(q >= 0 && IsAlNum(t[q + 1])) {
979 int w = q + 2;
980 while(IsAlNum(t[w]))
981 w++;
982 f << t.Mid(q, w - q);
983 }
984 else
985 if(defext.GetCount())
986 f << '.' << defext;
987 }
988 fn.Add(f);
989 }
990 f.Clear();
991 }
992
IsLnkFile(const String & p)993 bool FileSel::IsLnkFile(const String& p)
994 {
995 int l = p.GetLength() - 4;
996 return l >= 0 && p[l] == '.' && ToLower(p[l + 1]) == 'l' && ToLower(p[l + 2]) == 'n' && ToLower(p[l + 3]) == 'k';
997 }
998
ResolveLnk(const String & name) const999 String FileSel::ResolveLnk(const String& name) const
1000 {
1001 #ifdef PLATFORM_WIN32
1002 if(IsLnkFile(name))
1003 return GetSymLinkPath(AppendFileName(GetDir(), name));
1004 #endif
1005 return Null;
1006 }
1007
ResolveLnkDir(const String & name) const1008 String FileSel::ResolveLnkDir(const String& name) const
1009 {
1010 #ifdef PLATFORM_WIN32
1011 String p = ResolveLnk(name);
1012 if(p.GetCount() && DirectoryExists(p))
1013 return p;
1014 #endif
1015 return Null;
1016 }
1017
ResolveLnkFile(const String & name) const1018 String FileSel::ResolveLnkFile(const String& name) const
1019 {
1020 #ifdef PLATFORM_WIN32
1021 String p = ResolveLnk(name);
1022 if(p.GetCount() && FileExists(p))
1023 return p;
1024 #endif
1025 return Null;
1026 }
1027
Finish()1028 void FileSel::Finish() {
1029 if(filesystem->IsWin32())
1030 if(GetDir().IsEmpty()) {
1031 file.Clear();
1032 return;
1033 }
1034 fn.Clear();
1035 if(mode == SELECTDIR) {
1036 String p = GetDir();
1037 if(list.IsSelection() && multi) {
1038 for(int i = 0; i < list.GetCount(); i++)
1039 if(list.IsSelected(i)) {
1040 const FileList::File& m = list[i];
1041 if(m.isdir)
1042 fn.Add(AppendFileName(p, m.name));
1043 #ifdef PLATFORM_WIN32
1044 else {
1045 String p = ResolveLnkDir(m.name);
1046 if(p.GetCount())
1047 fn.Add(p);
1048 }
1049 #endif
1050 }
1051 }
1052 else {
1053 String p = GetDir();
1054 if(list.GetCursor() >= 0) {
1055 const FileList::File& m = list[list.GetCursor()];
1056 if(m.isdir)
1057 p = AppendFileName(p, m.name);
1058 #ifdef PLATFORM_WIN32
1059 else {
1060 String pp = ResolveLnkDir(m.name);
1061 if(p.GetCount())
1062 p = pp;
1063 }
1064 #endif
1065 }
1066 fn.Add(p);
1067 }
1068 Break(IDOK);
1069 return;
1070 }
1071 String f = file.GetText().ToString();
1072 if(f.IsEmpty()) return;
1073 String o;
1074 if(mode == OPEN && IsMulti()) {
1075 for(const char *s = f; *s; s++) {
1076 if(*s == ' ')
1077 AddName(fn, o);
1078 else
1079 if(*s == '\"') {
1080 AddName(fn, o);
1081 s++;
1082 for(;;) {
1083 if(*s == '\0' || *s == '\"') {
1084 AddName(fn, o);
1085 break;
1086 }
1087 o.Cat(*s++);
1088 }
1089 }
1090 else
1091 o.Cat(*s);
1092 }
1093 AddName(fn, o);
1094 }
1095 else {
1096 o = f;
1097 AddName(fn, o);
1098 }
1099 if(!IsMulti() && fn.GetCount())
1100 fn.SetCount(1);
1101 String d = GetDir();
1102 String nonexist;
1103 int ne = 0;
1104 for(int i = 0; i < fn.GetCount(); i++) {
1105 String p = fn[i];
1106 if(!IsFullPath(p))
1107 p = NormalizePath(AppendFileName(d, fn[i]));
1108 Array<FileSystemInfo::FileInfo> ff = filesystem->Find(p, 1);
1109 p = DeQtf(p);
1110 if(!ff.IsEmpty() && ff[0].is_directory) {
1111 Exclamation(p + t_(" is directory."));
1112 return;
1113 }
1114 if(asking) {
1115 if(mode == SAVEAS) {
1116 if(!ff.IsEmpty() && !PromptOKCancel(p + t_(" already exists.&Do you want to continue ?")))
1117 return;
1118 }
1119 else
1120 if(ff.IsEmpty()) {
1121 if(ne) nonexist << '&';
1122 nonexist << p;
1123 ne++;
1124 }
1125 }
1126 }
1127 if(ne) {
1128 nonexist << (ne == 1 ? t_(" does not exist.") : t_("&do not exist."));
1129 if(!PromptOKCancel(nonexist + t_("&Do you want to continue ?")))
1130 return;
1131 }
1132 Break(IDOK);
1133 }
1134
OpenItem()1135 bool FileSel::OpenItem() {
1136 if(list.IsCursor()) {
1137 #ifdef PLATFORM_WIN32
1138 if(netnode.GetCount()) {
1139 SelectNet();
1140 return true;
1141 }
1142 #endif
1143 const FileList::File& m = list.Get(list.GetCursor());
1144 String path = AppendFileName(~dir, m.name);
1145 #ifdef PLATFORM_WIN32
1146 if(IsNull(dir) && m.name == t_("Network")) {
1147 netnode = NetNode::EnumRoot();
1148 netnode.Append(NetNode::EnumRemembered());
1149 LoadNet();
1150 return true;
1151 }
1152 String p = ResolveLnkDir(m.name);
1153 if(p.GetCount()) {
1154 SetDir(p);
1155 return true;
1156 }
1157 #endif
1158 if(m.isdir) {
1159 SetDir(path);
1160 return true;
1161 }
1162 }
1163 if(mode != SELECTDIR)
1164 Finish();
1165 return false;
1166 }
1167
Open()1168 void FileSel::Open() {
1169 if(mode == SELECTDIR) {
1170 #ifdef PLATFORM_WIN32
1171 if(netnode.GetCount())
1172 return;
1173 #endif
1174 Finish();
1175 return;
1176 }
1177 if(list.HasFocus() || type.HasFocus()) {
1178 if(OpenItem()) list.SetCursor(0);
1179 }
1180 else
1181 if(list.IsSelection())
1182 for(int i = 0; i < list.GetCount(); i++) {
1183 const FileList::File& m = list[i];
1184 if(!m.isdir) Finish();
1185 }
1186 else
1187 if(file.HasFocus()) {
1188 String fn = file.GetText().ToString();
1189 #ifdef PLATFORM_WIN32
1190 if(fn[0] == '\\' && fn[1] == '\\') {
1191 FindFile ff(AppendFileName(fn, "*.*"));
1192 if(ff)
1193 SetDir(TrimDot(fn));
1194 return;
1195 }
1196 #endif
1197 if(fn == "." || fn == "..") {
1198 DirUp();
1199 return;
1200 }
1201 if(HasWildcards(fn)) {
1202 file.Clear();
1203 int q = FindIndex(mask, fn);
1204 if(q >= 0)
1205 type.SetIndex(q);
1206 else {
1207 type.Add(fn, t_("Custom file type (") + fn + ')');
1208 type.SetIndex(type.GetCount() - 1);
1209 }
1210 Load();
1211 return;
1212 }
1213 if(fn.Find('\"') < 0) {
1214 if(filesystem->IsWin32())
1215 {
1216 if(fn.GetLength() >= 2 && fn[1] == ':' && fn.GetLength() <= 3) {
1217 fn.Set(0, ToUpper(fn[0]));
1218 if(fn.GetLength() == 2)
1219 fn.Cat('\\');
1220 SetDir(fn);
1221 return;
1222 }
1223 }
1224 if(!IsFullPath(fn))
1225 fn = AppendFileName(~dir, fn);
1226 if(filesystem->IsWin32() && (!fn.IsEmpty() && (*fn.Last() == '\\' || *fn.Last() == '/'))
1227 || filesystem->IsPosix() && (fn != "/" && (*fn.Last() == '\\' || *fn.Last() == '/')))
1228 {
1229 fn.Trim(fn.GetLength() - 1);
1230 SetDir(TrimDot(fn));
1231 return;
1232 }
1233 Array<FileSystemInfo::FileInfo> ff = filesystem->Find(fn, 1);
1234 if(!ff.IsEmpty()) {
1235 if(ff[0].is_directory) {
1236 SetDir(TrimDot(fn));
1237 return;
1238 }
1239 else {
1240 SetDir(TrimDot(GetFileFolder(fn)));
1241 file.SetText(GetFileName(fn).ToWString());
1242 }
1243 }
1244 }
1245 if(mode != SELECTDIR) Finish();
1246 }
1247 }
1248
DirectoryUp(String & dir,bool basedir)1249 String DirectoryUp(String& dir, bool basedir)
1250 {
1251 while(*dir.Last() == '\\' || *dir.Last() == '/')
1252 dir.Trim(dir.GetCount() - 1);
1253 String s = dir;
1254 String name;
1255 #ifdef PLATFORM_WIN32
1256 if(s.GetLength() < 3 || s.GetLength() == 3 && s[1] == ':') {
1257 dir.Clear();
1258 name = s;
1259 }
1260 else
1261 #endif
1262 #ifdef PLATFORM_POSIX
1263 if(s != "/")
1264 #endif
1265 {
1266 #ifdef PLATFORM_WIN32
1267 int i = max(s.ReverseFind('/'), s.ReverseFind('\\'));
1268 #endif
1269 #ifdef PLATFORM_POSIX
1270 int i = s.ReverseFind('/');
1271 #endif
1272 if(basedir)
1273 if(i < 0)
1274 dir.Clear();
1275 else {
1276 dir = s.Mid(0, i);
1277 name = s.Mid(i + 1);
1278 }
1279 else {
1280 #ifdef PLATFORM_WIN32
1281 if(s.GetLength() && s[1] == ':') {
1282 if(i > 3) {
1283 dir = s.Mid(0, i);
1284 name = s.Mid(i + 1);
1285 }
1286 else {
1287 dir = s.Mid(0, 3);
1288 name = s.Mid(3);
1289 }
1290 }
1291 if(s.GetLength() && s[0] == DIR_SEP && s[1] == DIR_SEP) {
1292 if(i > 2) {
1293 dir = s.Mid(0, i);
1294 name = s.Mid(i + 1);
1295 }
1296 else {
1297 dir.Clear();
1298 name = s;
1299 }
1300 }
1301 #endif
1302 #ifdef PLATFORM_POSIX
1303 if(i == 0 && s.GetLength() > 1) {
1304 dir = "/";
1305 name = s.Mid(1);
1306 }
1307 else
1308 if(s.GetLength() && s[0] == '/' && s[1] != '/') {
1309 dir = s.Mid(0, i);
1310 name = s.Mid(i + 1);
1311 }
1312 #endif
1313 }
1314 }
1315 return name;
1316 }
1317
DirUp()1318 void FileSel::DirUp() {
1319 #ifdef PLATFORM_WIN32
1320 if(netstack.GetCount()) {
1321 netstack.Drop();
1322 if(netstack.GetCount()) {
1323 netnode = netstack.Top().Enum();
1324 LoadNet();
1325 }
1326 netnode = NetNode::EnumRoot();
1327 return;
1328 }
1329 if(netnode.GetCount()) {
1330 netnode.Clear();
1331 SetDir("");
1332 return;
1333 }
1334 #endif
1335 String s = ~dir;
1336 String name = DirectoryUp(s, !basedir.IsEmpty());
1337 #ifdef PLATFORM_WIN32
1338 if(s[0] == '\\' && s[1] == '\\' && s.Find('\\', 2) < 0) {
1339 s.Clear();
1340 name.Clear();
1341 }
1342 #endif
1343 SetDir(s);
1344 if(list.HasFocus())
1345 list.FindSetCursor(name);
1346 }
1347
MkDir()1348 void FileSel::MkDir() {
1349 if(String(~dir).IsEmpty() && basedir.IsEmpty()) return;
1350 String name, error;
1351 if(EditText(name, t_("New directory"), t_("Name")) && !name.IsEmpty()) {
1352 if(filesystem->CreateFolder(FilePath(name), error)) {
1353 Load();
1354 list.FindSetCursor(name);
1355 }
1356 else
1357 Exclamation(t_("[A3* Creating directory failed !&&]") + error);
1358 }
1359 }
1360
PlusMinus(const char * title,bool sel)1361 void FileSel::PlusMinus(const char *title, bool sel) {
1362 String pattern;
1363 if(EditText(pattern, title, t_("Mask")) && !pattern.IsEmpty())
1364 for(int i = 0; i < list.GetCount(); i++)
1365 if(!list.Get(i).isdir)
1366 if(PatternMatchMulti(pattern, list.Get(i).name))
1367 list.SelectOne(i, sel);
1368 }
1369
Plus()1370 void FileSel::Plus() {
1371 PlusMinus(t_("Add to selection"), true);
1372 }
1373
Minus()1374 void FileSel::Minus() {
1375 PlusMinus(t_("Remove from selection"), false);
1376 }
1377
Toggle()1378 void FileSel::Toggle() {
1379 for(int i = 0; i < list.GetCount(); i++)
1380 if(!list.Get(i).isdir)
1381 list.SelectOne(i, !list.IsSelected(i));
1382 }
1383
Reload()1384 void FileSel::Reload()
1385 {
1386 String fn = list.GetCurrentName();
1387 int a = list.GetScroll();
1388 SearchLoad();
1389 list.ScrollTo(a);
1390 list.FindSetCursor(fn);
1391 }
1392
Activate()1393 void FileSel::Activate()
1394 {
1395 if(loaded)
1396 Reload();
1397 TopWindow::Activate();
1398 }
1399
Key(dword key,int count)1400 bool FileSel::Key(dword key, int count) {
1401 switch(key) {
1402 case '.':
1403 case K_CTRL_UP:
1404 list.SetFocus();
1405 dirup.PseudoPush();
1406 return true;
1407 case '+':
1408 plus.PseudoPush();
1409 return true;
1410 case '-':
1411 minus.PseudoPush();
1412 return true;
1413 case '*':
1414 toggle.PseudoPush();
1415 return true;
1416 case K_F5:
1417 Reload();
1418 return true;
1419 case K_F6:
1420 list.StartEdit();
1421 return true;
1422 case K_F7:
1423 mkdir.PseudoPush();
1424 return true;
1425 case K_ENTER:
1426 if(mode == SELECTDIR && OpenItem())
1427 return true;
1428 break;
1429 case K_UP:
1430 case K_DOWN:
1431 case K_PAGEUP:
1432 case K_PAGEDOWN:
1433 list.SetFocus();
1434 return list.Key(key, count);
1435 }
1436 if(CharFilterDefaultToUpperAscii(key) || key == K_BACKSPACE)
1437 return search.Key(key, count);
1438 return TopWindow::Key(key, count);
1439 }
1440
Catq(String & s,const String & fn)1441 void Catq(String& s, const String& fn) {
1442 if(!s.IsEmpty())
1443 s << ' ';
1444 if(fn.Find(' ') >= 0)
1445 s << '"' << fn << '"';
1446 else
1447 s << fn;
1448 }
1449
FormatFileSize(int64 n)1450 String FormatFileSize(int64 n)
1451 {
1452 if(n < 10000)
1453 return Format("%d B ", n);
1454 else
1455 if(n < 10000 * 1024)
1456 return Format("%d.%d K ", n >> 10, (n & 1023) / 103);
1457 else
1458 if(n < I64(10000000) * 1024)
1459 return Format("%d.%d M ", n >> 20, (n & 1023) / 103);
1460 else
1461 return Format("%d.%d G ", n >> 30, (n & 1023) / 103);
1462 }
1463
Update()1464 void FileSel::Update() {
1465 String fn;
1466 if(list.IsSelection()) {
1467 for(int i = 0; i < list.GetCount(); i++)
1468 if(list.IsSelected(i))
1469 Catq(fn, list[i].name);
1470 }
1471 else
1472 if(list.IsCursor()) {
1473 const FileList::File& m = list[list.GetCursor()];
1474 if(!m.isdir)
1475 Catq(fn, m.name);
1476 }
1477 if(mode == OPEN)
1478 file <<= fn;
1479 filename = String();
1480 filesize = String();
1481 filetime = String();
1482 if(preview)
1483 *preview <<= Null;
1484 if(list.IsCursor()) {
1485 fn = list[list.GetCursor()].name;
1486 if(fn[1] == ':' && fn.GetLength() <= 3)
1487 filename = t_(" Drive");
1488 else {
1489 String path = FilePath(fn);
1490 Array<FileSystemInfo::FileInfo> ff = filesystem->Find(path, 1);
1491 if(!ff.IsEmpty()) {
1492 filename = " " + fn;
1493 if(ff[0].is_directory)
1494 filesize = t_("Directory ");
1495 else {
1496 if(mode == SAVEAS)
1497 file <<= fn;
1498 filesize = FormatFileSize(ff[0].length);
1499 if(preview)
1500 *preview <<= path;
1501 }
1502 Time tm = ff[0].last_write_time;
1503 filetime = " " + Format(tm);
1504 }
1505 }
1506 }
1507 else {
1508 int drives = 0;
1509 int dirs = 0;
1510 int files = 0;
1511 int64 length = 0;
1512 for(int i = 0; i < list.GetCount(); i++)
1513 if(!list.IsSelection() || list.IsSelected(i)) {
1514 const FileList::File& f = list[i];
1515 if(f.isdir)
1516 #ifdef PLATFORM_WIN32
1517 (*f.name.Last() == ':' ? drives : dirs)++;
1518 #else
1519 dirs++;
1520 #endif
1521 else {
1522 files++;
1523 length += f.length;
1524 }
1525 }
1526 String s;
1527 if(drives)
1528 s << drives << t_(" drive(s)");
1529 else {
1530 if(dirs)
1531 s << dirs << t_(" folder(s)");
1532 if(files) {
1533 if(s.GetCount())
1534 s << ", ";
1535 s << files << t_(" file(s)");
1536 }
1537 }
1538 filename = " " + s;
1539 if(length >= 0)
1540 filesize = FormatFileSize(length);
1541 }
1542 FileUpdate();
1543 }
1544
FileUpdate()1545 void FileSel::FileUpdate() {
1546 if(mode == SELECTDIR) {
1547 ok.Enable(!IsNull(~dir));
1548 return;
1549 }
1550 bool b = list.IsCursor() || !String(~file).IsEmpty();
1551 ok.Enable(b);
1552 if(mode != SAVEAS || list.IsCursor() && list[list.GetCursor()].isdir)
1553 ok.SetLabel(t_("Open"));
1554 else
1555 ok.SetLabel(t_("Save"));
1556 }
1557
Rename(const String & on,const String & nn)1558 void FileSel::Rename(const String& on, const String& nn) {
1559 if(on == nn) return;
1560 #ifdef PLATFORM_WIN32
1561 if(FileMove(FilePath(on), FilePath(nn)))
1562 #else
1563 if(rename(FilePath(on), FilePath(nn)) == 0)
1564 #endif
1565 {
1566 Load();
1567 list.FindSetCursor(nn);
1568 }
1569 else
1570 Exclamation(t_("[A3* Renaming of file failed !&&]") + GetErrorMessage(GetLastError()));
1571 }
1572
Choice()1573 void FileSel::Choice() {
1574 Load();
1575 }
1576
Type(const char * name,const char * ext)1577 FileSel& FileSel::Type(const char *name, const char *ext) {
1578 type.Add(type.GetCount(), name);
1579 mask.Add(ext);
1580 if(IsNull(type))
1581 type.SetIndex(0);
1582 return *this;
1583 }
1584
Types(const char * d)1585 FileSel& FileSel::Types(const char *d) {
1586 Vector<String> s = Split(d, '\n');
1587 for(int i = 0; i < s.GetCount(); i++) {
1588 Vector<String> h = Split(s[i], '\t');
1589 if(h.GetCount() == 2)
1590 Type(h[0], h[1]);
1591 if(h.GetCount() == 1)
1592 Type(h[0], h[0]);
1593 }
1594 return *this;
1595 }
1596
ClearTypes()1597 FileSel& FileSel::ClearTypes()
1598 {
1599 type.Clear();
1600 mask.Clear();
1601 return *this;
1602 }
1603
ActiveType(int i)1604 FileSel& FileSel::ActiveType(int i)
1605 {
1606 activetype.Clear();
1607 if(i >= 0 && i < type.GetCount())
1608 activetype = type.GetValue(i);
1609 return *this;
1610 }
1611
AllFilesType()1612 FileSel& FileSel::AllFilesType() {
1613 return Type(t_("All files"), "*.*");
1614 }
1615
1616 struct FolderDisplay : public Display {
1617 virtual void Paint(Draw& w, const Rect& r, const Value& q,
1618 Color ink, Color paper, dword style) const;
1619 };
1620
GetDirIcon(const String & s)1621 Image GetDirIcon(const String& s)
1622 {
1623 Image img;
1624 #ifdef PLATFORM_X11
1625 img = GetFileIcon(GetFileFolder(s), GetFileName(s), true, false, false);
1626 #endif
1627 #ifdef PLATFORM_WIN32
1628 if((byte)*s.Last() == 255)
1629 img = CtrlImg::Network();
1630 else {
1631 int q = s.Find(0);
1632 if(q >= 0 && q + 1 < s.GetCount())
1633 img = GetDriveImage(s[q + 1]);
1634 else
1635 img = s.GetCount() ? GetFileIcon(s, false, true, false) : CtrlImg::Computer();
1636 }
1637 #endif
1638 if(IsNull(img))
1639 img = CtrlImg::Dir();
1640 return DPI(img);
1641 }
1642
Paint(Draw & w,const Rect & r,const Value & q,Color ink,Color paper,dword style) const1643 void FolderDisplay::Paint(Draw& w, const Rect& r, const Value& q,
1644 Color ink, Color paper, dword style) const
1645 {
1646 String s = q;
1647 w.DrawRect(r, paper);
1648 Image img = GetDirIcon(s);
1649 w.DrawImage(r.left, r.top + (r.Height() - img.GetSize().cx) / 2, img);
1650 w.DrawText(r.left + Zx(20),
1651 r.top + (r.Height() - StdFont().Bold().Info().GetHeight()) / 2,
1652 ~s, StdFont().Bold(), ink);
1653 }
1654
1655 struct HomeDisplay : public Display {
PaintUpp::HomeDisplay1656 virtual void Paint(Draw& w, const Rect& r, const Value& q,
1657 Color ink, Color paper, dword style) const {
1658 w.DrawRect(r, paper);
1659 Image img = CtrlImg::Home();
1660 w.DrawImage(r.left, r.top + (r.Height() - img.GetSize().cx) / 2,
1661 CtrlImg::Home());
1662 w.DrawText(r.left + Zx(20),
1663 r.top + (r.Height() - StdFont().Bold().Info().GetHeight()) / 2,
1664 String(q), StdFont().Bold(), ink);
1665 }
1666 };
1667
Set(const String & s)1668 void FileSel::Set(const String& s)
1669 {
1670 fn.Clear();
1671 if(IsFullPath(s)) {
1672 ActiveDir(GetFileFolder(s));
1673 fn.Add(GetFileName(s));
1674 }
1675 else
1676 fn.Add(s);
1677 bidname = true;
1678 }
1679
GoToPlace()1680 void FileSel::GoToPlace()
1681 {
1682 if(places.IsCursor()) {
1683 #ifdef PLATFORM_WIN32
1684 netnode.Clear();
1685 #endif
1686 dir <<= places.GetKey();
1687 Load();
1688 }
1689 }
1690
Execute(int _mode)1691 bool FileSel::Execute(int _mode) {
1692 mode = _mode;
1693
1694 int system_row = -1;
1695 for(int i = places.GetCount() - 1; i >= 0; i--) {
1696 if(places.Get(i, 3) == "PLACES:SYSTEM") {
1697 system_row = i;
1698 places.Remove(i);
1699 }
1700 }
1701 AddSystemPlaces(system_row);
1702
1703 if(mode == SELECTDIR) {
1704 if(!fn.IsEmpty()) {
1705 String h = ~dir;
1706 dir <<= NormalizePath(fn[0]);
1707 if(!DirectoryExists(~~dir))
1708 dir <<= h;
1709 }
1710 type.Hide();
1711 type_lbl.Hide();
1712 file.Hide();
1713 file_lbl.Hide();
1714 sortby.Hide();
1715 sort_lbl.Hide();
1716 ok.SetLabel(t_("&Select"));
1717 Logc p = filename.GetPos().y;
1718 int q = ok.GetPos().y.GetA() + ok.GetPos().y.GetB() + Zy(16);
1719 p.SetA(q);
1720 filename.SetPosY(p);
1721 filesize.SetPosY(p);
1722 filetime.SetPosY(p);
1723 p = splitter.Ctrl::GetPos().y;
1724 p.SetB(q + Zy(28));
1725 splitter.SetPosY(p);
1726 LogPos ps = search.GetPos();
1727 LogPos pl = sort_lbl.GetPos();
1728 pl.x.SetB(ps.x.GetB());
1729 pl.y.SetA(ok.GetPos().y.GetA());
1730 pl.y.SetB(ps.y.GetB());
1731 search.SetPos(pl);
1732 bidname = false;
1733 }
1734 else {
1735 for(Ctrl *q = GetFirstChild(); q; q = q->GetNext())
1736 if(q != &mkdir)
1737 q->Show();
1738 Rect r = GetRect();
1739 CtrlLayout(*this);
1740 ArrangeOKCancel(ok, cancel);
1741 SetRect(r);
1742 }
1743
1744 if(file_ctrl) {
1745 LogPos sp = search.GetPos();
1746 LogPos fp = file.GetPos();
1747 file.HSizePos(fp.x.GetA(), 2 * sp.x.GetA() + file_ctrl_cx);
1748 AddChild(file_ctrl, &file);
1749 file_ctrl->BottomPos(fp.y.GetA(), fp.y.GetB()).RightPos(sp.x.GetA(), file_ctrl_cx);
1750 }
1751
1752 readonly.Show(rdonly && mode == OPEN);
1753 list.Multi(multi && (mode == OPEN || mode == SELECTDIR));
1754 list.SelectDir(multi && mode == SELECTDIR);
1755 dir.ClearList();
1756 file <<= Null;
1757 if(basedir.IsEmpty()) {
1758 dir.Add(GetHomeDirectory());
1759 #ifdef PLATFORM_POSIX
1760 Array<FileSystemInfo::FileInfo> root = filesystem->Find("/media/*");
1761 dir.Add(GetDesktopFolder());
1762 dir.Add("/");
1763 for(int i = 0; i < root.GetCount(); i++) {
1764 String ugly = root[i].filename;
1765 if(ugly[0] != '.') {
1766 dir.Add("/media/" + root[i].filename);
1767 }
1768 }
1769 #else
1770 dir.Add(GetDesktopFolder());
1771 Array<FileSystemInfo::FileInfo> root = filesystem->Find(Null);
1772 for(int i = 0; i < root.GetCount(); i++) {
1773 String ugly = root[i].filename;
1774 if(ugly != "A:\\" && ugly != "B:\\") {
1775 ugly.Cat('\0');
1776 ugly.Cat(root[i].root_style);
1777 dir.Add(root[i].filename, ugly);
1778 }
1779 }
1780 if(filesystem == &StdFileSystemInfo())
1781 dir.Add("\\", String(t_("Network")) + String(0, 1) + "\xff");
1782 #endif
1783 if(filesystem->IsPosix() && String(~dir).IsEmpty())
1784 dir <<= GetHomeDirectory();
1785 if(lru.GetCount())
1786 dir.AddSeparator();
1787 for(int i = 0; i < lru.GetCount(); i++)
1788 if(IsFullPath(lru[i]) && filesystem->FolderExists(lru[i]))
1789 dir.Add(lru[i]);
1790 dir.SetDisplay(Single<FolderDisplay>(), max(16, Draw::GetStdFontCy()));
1791 }
1792 else {
1793 dir.SetDisplay(Single<HomeDisplay>(), max(16, Draw::GetStdFontCy()));
1794 if(filesystem->IsPosix()) {
1795 if(String(~dir)[0] == '/')
1796 dir <<= "";
1797 }
1798 }
1799 Rect lr = splitter.GetRect();
1800 Rect dr = dir.GetRect();
1801 int dp = max(20, dir.Ctrl::GetPos().y.GetB());
1802 int px = GetSize().cx - lr.right;
1803 /* if(IsMulti()) { // Cxl: Have we ever used these?!
1804 toggle.RightPos(px, dp).TopPos(dr.top, dp);
1805 minus.RightPos(px + 2 * dp, dp).TopPos(dr.top, dp);
1806 plus.RightPos(px + 3 * dp, dp).TopPos(dr.top, dp);
1807 px += 3 * dp;
1808 toggle.Show();
1809 minus.Show();
1810 plus.Show();
1811 }
1812 else {*/
1813 toggle.Hide();
1814 minus.Hide();
1815 plus.Hide();
1816 // }
1817 if(mkdir.IsShown()) {
1818 mkdir.RightPos(px, dp).TopPos(dr.top, dp);
1819 dirup.RightPos(px + dp, dp).TopPos(dr.top, dp);
1820 px += 2 * dp;
1821 }
1822 else {
1823 dirup.RightPos(px, dp).TopPos(dr.top, dp);
1824 px += dp;
1825 }
1826 dir.HSizePos(dr.left, px + 4);
1827 if(preselect.GetCount()) {
1828 for(int i = 0; i < mask.GetCount(); i++) {
1829 if(PatternMatchMulti(mask[i], preselect)) {
1830 ActiveType(i);
1831 break;
1832 }
1833 }
1834 }
1835 int q = type.FindValue(activetype);
1836 if(q >= 0)
1837 type <<= q;
1838 else
1839 if(type.GetCount())
1840 type.SetIndex(0);
1841 int dlc = type.GetCount();
1842 Load();
1843 ActiveFocus(file.IsEditable() ? (Ctrl&)file : (Ctrl&)list);
1844 if(bidname) {
1845 String s;
1846 for(int i = 0; i < fn.GetCount(); i++)
1847 Catq(s, fn[i]);
1848 file <<= s;
1849 ActiveFocus(file);
1850 bidname = false;
1851 }
1852 list.SetSbPos(lastsby);
1853 if(preselect.GetCount()) {
1854 if(mode == SAVEAS)
1855 file <<= preselect;
1856 else
1857 for(int i = 0; i < list.GetCount(); i++)
1858 if(list[i].name == preselect) {
1859 list.SetCursor(i);
1860 ActiveFocus(list);
1861 break;
1862 }
1863 preselect.Clear();
1864 }
1865 FileUpdate();
1866 Update();
1867 int c = TopWindow::Run(appmodal);
1868 TopWindow::Close();
1869 lastsby = list.GetSbPos();
1870 if(IsNumber(~type)) {
1871 int ti = ~type;
1872 type.Trim(dlc);
1873 if(ti >= 0 && ti < type.GetCount())
1874 activetype = type.GetValue(ti);
1875 }
1876 else
1877 type.Trim(dlc);
1878 if(c == IDOK) {
1879 String d = ~dir;
1880 if(filesystem->IsWin32())
1881 if(d.GetLength() == 3 && d[1] == ':') return true;
1882 if(filesystem->IsPosix())
1883 if(d == "/") return true;
1884 if(!IsFullPath(d)) return true;
1885 LruAdd(lru, d, 8);
1886 return true;
1887 }
1888 return false;
1889 }
1890
ExecuteOpen(const char * title)1891 bool FileSel::ExecuteOpen(const char *title) {
1892 Title(title ? title : t_("Open"));
1893 return Execute(OPEN);
1894 }
1895
ExecuteSaveAs(const char * title)1896 bool FileSel::ExecuteSaveAs(const char *title) {
1897 Title(title ? title : t_("Save as"));
1898 ok.SetLabel(t_("Save"));
1899 return Execute(SAVEAS);
1900 }
1901
ExecuteSelectDir(const char * title)1902 bool FileSel::ExecuteSelectDir(const char *title)
1903 {
1904 Title(title ? title : t_("Select directory"));
1905 return Execute(SELECTDIR);
1906 }
1907
Serialize(Stream & s)1908 void FileSel::Serialize(Stream& s) {
1909 #ifdef PLATFORM_WIN32
1910 if(s.IsLoading()) {
1911 netnode.Clear();
1912 netstack.Clear();
1913 }
1914 #endif
1915 int version = 10;
1916 s / version;
1917 String ad = ~dir;
1918 int dummy = 0;
1919 if(version < 10)
1920 s / dummy;
1921 else
1922 s % activetype;
1923 s % ad;
1924 dir <<= ad;
1925 if(version < 1) {
1926 String n = fn.At(0);
1927 s % n;
1928 fn.At(0) = n;
1929 }
1930 else {
1931 if(version < 4)
1932 s % fn;
1933 else {
1934 Vector<String> __;
1935 s % __;
1936 }
1937 }
1938 if(version >= 2) {
1939 SerializePlacement(s);
1940 list.SerializeSettings(s);
1941 }
1942 if(version >= 3) {
1943 s % lastsby;
1944 }
1945 if(version >= 4) {
1946 s % lru;
1947 }
1948 if(version >= 5) {
1949 s % sortby;
1950 }
1951 if(version >= 6) {
1952 if(version >= 9)
1953 s % splitter;
1954 else {
1955 Splitter dummy;
1956 s % dummy;
1957 }
1958 }
1959 if(version >= 7) {
1960 s % hidden;
1961 }
1962 if(version >= 8) {
1963 s % hiddenfiles;
1964 }
1965 }
1966
GetFile(int i) const1967 String FileSel::GetFile(int i) const {
1968 String p;
1969 if(i >= 0 && i < fn.GetCount()) {
1970 p = fn[i];
1971 if(!IsFullPath(p))
1972 p = AppendFileName(dir.GetData(), p);
1973 }
1974 #ifdef PLATFORM_WIN32
1975 if(IsLnkFile(p))
1976 p = Nvl(GetSymLinkPath(p), p);
1977 #endif
1978 return p;
1979 }
1980
SyncSplitter()1981 void FileSel::SyncSplitter()
1982 {
1983 splitter.Clear();
1984 if(places.GetCount() && basedir.IsEmpty())
1985 splitter.Add(places);
1986 splitter.Add(list);
1987 if(preview)
1988 splitter.Add(*preview);
1989 }
1990
PreSelect(const String & path)1991 FileSel& FileSel::PreSelect(const String& path)
1992 {
1993 ActiveDir(GetFileFolder(path));
1994 preselect = GetFileName(path);
1995 return *this;
1996 }
1997
InitSplitter()1998 void FileSel::InitSplitter()
1999 {
2000 int n = splitter.GetCount();
2001 int i = 0;
2002 if(places.GetCount())
2003 splitter.SetPos(2000, i++);
2004 splitter.SetPos(10000 - 2000 * (n - 1), i);
2005 }
2006
Preview(Ctrl & ctrl)2007 FileSel& FileSel::Preview(Ctrl& ctrl)
2008 {
2009 if(!preview) {
2010 Size sz = GetRect().GetSize();
2011 sz.cx = 5 * sz.cx / 3;
2012 SetRect(sz);
2013 }
2014 preview = &ctrl;
2015 SyncSplitter();
2016 InitSplitter();
2017 return *this;
2018 }
2019
Preview(const Display & d)2020 FileSel& FileSel::Preview(const Display& d)
2021 {
2022 preview_display.SetDisplay(d);
2023 return Preview(preview_display);
2024 }
2025
AddPlaceRaw(const String & path,const Image & m,const String & name,const char * group,int row)2026 void FileSel::AddPlaceRaw(const String& path, const Image& m, const String& name, const char* group, int row)
2027 {
2028 if(path.GetCount()) {
2029 row = row < 0 ? places.GetCount() : row;
2030 places.Insert(row);
2031 places.Set(row, 0, path);
2032 places.Set(row, 1, DPI(m));
2033 places.Set(row, 2, name);
2034 places.Set(row, 3, group);
2035 places.SetLineCy(row, max(m.GetSize().cy + 4, GetStdFontCy() + 4));
2036 SyncSplitter();
2037 InitSplitter();
2038 }
2039 }
2040
AddPlace(const String & path,const Image & m,const String & name,const char * group,int row)2041 FileSel& FileSel::AddPlace(const String& path, const Image& m, const String& name, const char* group, int row)
2042 {
2043 if(path.GetCount())
2044 AddPlaceRaw(NormalizePath(path), DPI(m), name, group, row);
2045 return *this;
2046 }
2047
AddPlace(const String & path,const String & name,const char * group,int row)2048 FileSel& FileSel::AddPlace(const String& path, const String& name, const char* group, int row)
2049 {
2050 #ifdef PLATFORM_COCOA
2051 return AddPlace(path, GetFileIcon(NormalizePath(path), true, false, false), name, group, row);
2052 #else
2053 return AddPlace(path, GetDirIcon(NormalizePath(path)), name, group, row);
2054 #endif
2055 }
2056
AddPlace(const String & path,const char * group,int row)2057 FileSel& FileSel::AddPlace(const String& path, const char* group, int row)
2058 {
2059 return AddPlace(path, GetFileTitle(path), group, row);
2060 }
2061
AddPlaceSeparator()2062 FileSel& FileSel::AddPlaceSeparator()
2063 {
2064 places.AddSeparator();
2065 SyncSplitter();
2066 InitSplitter();
2067 return *this;
2068 }
2069
ClearPlaces()2070 FileSel& FileSel::ClearPlaces()
2071 {
2072 places.Clear();
2073 SyncSplitter();
2074 return *this;
2075 }
2076
AddSystemPlaces(int row)2077 void FileSel::AddSystemPlaces(int row)
2078 {
2079 row = row < 0 ? places.GetCount() : row;
2080 Array<FileSystemInfo::FileInfo> root;
2081 #ifdef PLATFORM_WIN32
2082 root = filesystem->Find(Null);
2083 for(int i = 0; i < root.GetCount(); i++) {
2084 String desc = root[i].root_desc;
2085 String n = root[i].filename;
2086 if(n != "A:\\" && n != "B:\\") {
2087 #ifdef PLATFORM_WIN32
2088 if(*n.Last() == '\\')
2089 n.Trim(n.GetCount() - 1);
2090 #endif
2091 if(desc.GetCount() == 0)
2092 desc << " " << t_("Local Disk");
2093 desc << " (" << n << ")";
2094 AddPlace(root[i].filename, GetDriveImage(root[i].root_style), desc, "PLACES:SYSTEM", row++);
2095 }
2096 }
2097
2098 if(GetSystemMetrics(SM_REMOTESESSION))
2099 for(int drive = 'A'; drive < 'Z'; drive++) {
2100 String path = Format("\\\\tsclient\\%c", drive);
2101 if(FindFile(path + "\\*.*"))
2102 AddPlace(path, Format(t_("%c on client"), drive), "PLACES:SYSTEM", row++);
2103 }
2104 #endif
2105
2106 #ifdef PLATFORM_POSIX
2107 root = filesystem->Find("/media/*");
2108 for(int i = 0; i < root.GetCount(); i++) {
2109 String fn = root[i].filename;
2110 if(*fn != '.' && fn.Find("floppy") < 0)
2111 AddPlace("/media/" + fn, fn, "PLACES:SYSTEM", row++);
2112 }
2113 AddPlace("/", t_("Computer"), "PLACES:SYSTEM", row++);
2114 #endif
2115 }
2116
AddStandardPlaces()2117 FileSel& FileSel::AddStandardPlaces()
2118 {
2119 AddPlace(GetHomeDirectory(), t_("Home"), "PLACES:FOLDER");
2120 #ifdef PLATFORM_COCOA
2121 AddPlace(GetSpecialDirectory(SF_NSDesktopDirectory), t_("Desktop"), "PLACES:FOLDER");
2122 AddPlace(GetSpecialDirectory(SF_NSMusicDirectory), t_("Music"), "PLACES:FOLDER");
2123 AddPlace(GetSpecialDirectory(SF_NSPicturesDirectory), t_("Pictures"), "PLACES:FOLDER");
2124 AddPlace(GetSpecialDirectory(SF_NSMoviesDirectory), t_("Videos"), "PLACES:FOLDER");
2125 AddPlace(GetSpecialDirectory(SF_NSDocumentDirectory), t_("Documents"), "PLACES:FOLDER");
2126 AddPlace(GetSpecialDirectory(SF_NSDownloadsDirectory), t_("Downloads"), "PLACES:FOLDER");
2127 #else
2128 AddPlace(GetDesktopFolder(), t_("Desktop"), "PLACES:FOLDER");
2129 AddPlace(GetMusicFolder(), t_("Music"), "PLACES:FOLDER");
2130 AddPlace(GetPicturesFolder(), t_("Pictures"), "PLACES:FOLDER");
2131 AddPlace(GetVideoFolder(), t_("Videos"), "PLACES:FOLDER");
2132 AddPlace(GetDocumentsFolder(), t_("Documents"), "PLACES:FOLDER");
2133 AddPlace(GetDownloadFolder(), t_("Downloads"), "PLACES:FOLDER");
2134 #endif
2135 AddPlaceSeparator();
2136 AddSystemPlaces();
2137 #ifdef PLATFORM_WIN32
2138 AddPlaceSeparator();
2139 AddPlaceRaw("\\", CtrlImg::Network(), t_("Network"), "PLACES:NETWORK");
2140 #endif
2141 return *this;
2142 }
2143
2144 struct DisplayPlace : Display {
PaintUpp::DisplayPlace2145 virtual void Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper,
2146 dword style) const
2147 {
2148 w.DrawRect(r, paper);
2149 ValueArray va = q;
2150 Image m = va[0];
2151 String txt = va[1];
2152 Size isz = m.GetSize();
2153 w.DrawImage(r.left, r.top + (r.Height() - isz.cy) / 2, m);
2154 w.DrawText(r.left + isz.cx + 2, r.top + (r.Height() - GetStdFontCy()) / 2, txt,
2155 StdFont(), ink);
2156 }
GetStdSizeUpp::DisplayPlace2157 virtual Size GetStdSize(const Value& q) const {
2158 ValueArray va = q;
2159 Image m = va[0];
2160 String txt = va[1];
2161 Size isz = m.GetSize();
2162 return Size(isz.cx + GetTextSize(txt, StdFont()).cx + 2, max(isz.cy, GetStdFontCy()));
2163 }
2164 };
2165
FileSel()2166 FileSel::FileSel()
2167 {
2168 loaded = false;
2169 filesystem = &StdFileSystemInfo();
2170 CtrlLayout(*this);
2171 ArrangeOKCancel(ok, cancel);
2172 Acceptor(ok, IDOK); ok.Ok();
2173 Rejector(cancel, IDCANCEL); cancel.Cancel();
2174 list.IconWidth(DPI(16)).Renaming().Columns(3).ClickKill();
2175 list.WhenLeftDouble = THISBACK(OpenItem2);
2176 dirup <<= THISBACK(DirUp);
2177 Add(dirup);
2178 sortby <<= THISBACK(SearchLoad);
2179 Add(sortby);
2180 hidden <<= THISBACK(SearchLoad);
2181 Add(hidden);
2182 hiddenfiles <<= THISBACK(SearchLoad);
2183 Add(hiddenfiles);
2184 mkdir <<= THISBACK(MkDir);
2185 Add(mkdir);
2186 plus <<= THISBACK(Plus);
2187 Add(plus);
2188 minus <<= THISBACK(Minus);
2189 Add(minus);
2190 toggle <<= THISBACK(Toggle);
2191 Add(toggle);
2192
2193 ok <<= THISBACK(Open);
2194 list <<= THISBACK(Update);
2195 file <<= THISBACK(FileUpdate);
2196 list.WhenRename = THISBACK(Rename);
2197 Sizeable();
2198 dirup.SetImage(CtrlImg::DirUp()).NoWantFocus();
2199 dirup.Tip(t_("Dir up") + String(" (Ctrl+Up)"));
2200 mkdir.SetImage(CtrlImg::MkDir()).NoWantFocus();
2201 mkdir.Tip(t_("Create directory") + String(" (F7)"));
2202 plus.SetImage(CtrlImg::Plus()).NoWantFocus();
2203 plus.Tip(t_("Select files"));
2204 minus.SetImage(CtrlImg::Minus()).NoWantFocus();
2205 minus.Tip(t_("Unselect files"));
2206 toggle.SetImage(CtrlImg::Toggle()).NoWantFocus();
2207 toggle.Tip(t_("Toggle files"));
2208 type <<= THISBACK(Load);
2209 for(int pass = 0; pass < 2; pass++) {
2210 int k = pass * FILELISTSORT_DESCENDING;
2211 String d = pass ? t_(" descending") : "";
2212 sortby.Add(FILELISTSORT_NAME|k, t_("Name") + d);
2213 sortby.Add(FILELISTSORT_EXT|k, t_("Extension") + d);
2214 sortby.Add(FILELISTSORT_TIME|k, t_("Last change") + d);
2215 sortby.Add(FILELISTSORT_SIZE|k, t_("Size") + d);
2216 }
2217 sortby <<= FILELISTSORT_NAME;
2218
2219 search.NullText(t_("Search"), StdFont().Italic(), SColorDisabled());
2220 search.SetFilter(CharFilterDefaultToUpperAscii);
2221 search <<= THISBACK(SearchLoad);
2222
2223 filename.SetFont(StdFont());
2224 filename.SetFrame(ViewFrame());
2225 filesize.SetFont(StdFont()).SetAlign(ALIGN_RIGHT);
2226 filesize.SetFrame(ViewFrame());
2227 filetime.SetFont(StdFont());
2228 filetime.SetFrame(ViewFrame());
2229
2230 dir <<= THISBACK(Choice);
2231 dir.DisplayAll();
2232 dir.SetDropLines(24);
2233
2234 readonly.Hide();
2235
2236 lastsby = 0;
2237
2238 asking = true;
2239 rdonly = false;
2240 multi = false;
2241 bidname = false;
2242 appmodal = true;
2243
2244 AddChildBefore(GetFirstChild(), &sizegrip);
2245
2246 preview = NULL;
2247 preview_display.SetFrame(FieldFrame());
2248
2249 SyncSplitter();
2250
2251 BackPaintHint();
2252
2253 places.AddKey();
2254 places.AddColumn().AddIndex().SetDisplay(Single<DisplayPlace>());
2255 places.AddIndex();
2256 places.NoHeader().NoGrid();
2257 places.WhenLeftClick = THISBACK(GoToPlace);
2258 places.NoWantFocus();
2259
2260 #ifdef PLATFORM_WIN32
2261 list.IconWidth(GetFileIcon(GetHomeDirectory(), true, false, false).GetSize().cx);
2262 #endif
2263
2264 AddStandardPlaces();
2265
2266 list.AutoHideSb();
2267 places.AutoHideSb();
2268
2269 WhenIconLazy = NULL;
2270 }
2271
~FileSel()2272 FileSel::~FileSel() {}
2273
2274 }
2275