1 // BrowseDialog.cpp
2
3 #include "StdAfx.h"
4
5 #ifndef UNDER_CE
6 #include "../../../Windows/CommonDialog.h"
7 #include "../../../Windows/Shell.h"
8 #endif
9
10 #include "../../../Windows/FileName.h"
11 #include "../../../Windows/FileFind.h"
12
13 #ifdef UNDER_CE
14 #include <commdlg.h>
15 #endif
16
17 #include "BrowseDialog.h"
18
19 #define USE_MY_BROWSE_DIALOG
20
21 #ifdef USE_MY_BROWSE_DIALOG
22
23 #include "../../../Common/Defs.h"
24 #include "../../../Common/IntToString.h"
25 #include "../../../Common/Wildcard.h"
26
27 #include "../../../Windows/FileDir.h"
28 #include "../../../Windows/PropVariantConv.h"
29
30 #include "../../../Windows/Control/ComboBox.h"
31 #include "../../../Windows/Control/Dialog.h"
32 #include "../../../Windows/Control/Edit.h"
33 #include "../../../Windows/Control/ListView.h"
34
35 #include "BrowseDialogRes.h"
36 #include "PropertyNameRes.h"
37 #include "SysIconUtils.h"
38
39 #ifndef _SFX
40 #include "RegistryUtils.h"
41 #endif
42
43 #endif
44
45 #include "ComboDialog.h"
46 #include "LangUtils.h"
47
48 #include "resource.h"
49
50 using namespace NWindows;
51 using namespace NFile;
52 using namespace NName;
53 using namespace NFind;
54
55 #ifdef USE_MY_BROWSE_DIALOG
56
57 extern bool g_LVN_ITEMACTIVATE_Support;
58
59 static const int kParentIndex = -1;
60 static const UINT k_Message_RefreshPathEdit = WM_APP + 1;
61
GetNormalizedError()62 static HRESULT GetNormalizedError()
63 {
64 DWORD errorCode = GetLastError();
65 return errorCode == 0 ? E_FAIL : errorCode;
66 }
67
68 extern UString HResultToMessage(HRESULT errorCode);
69
MessageBox_Error_Global(HWND wnd,const wchar_t * message)70 static void MessageBox_Error_Global(HWND wnd, const wchar_t *message)
71 {
72 ::MessageBoxW(wnd, message, L"7-Zip", MB_ICONERROR);
73 }
74
MessageBox_HResError(HWND wnd,HRESULT errorCode,const wchar_t * name)75 static void MessageBox_HResError(HWND wnd, HRESULT errorCode, const wchar_t *name)
76 {
77 UString s = HResultToMessage(errorCode);
78 if (name)
79 {
80 s += L'\n';
81 s += name;
82 }
83 MessageBox_Error_Global(wnd, s);
84 }
85
86 class CBrowseDialog: public NControl::CModalDialog
87 {
88 NControl::CListView _list;
89 NControl::CEdit _pathEdit;
90 NControl::CComboBox _filterCombo;
91
92 CObjectVector<CFileInfo> _files;
93
94 CExtToIconMap _extToIconMap;
95 int _sortIndex;
96 bool _ascending;
97 bool _showDots;
98 UString _topDirPrefix; // we don't open parent of that folder
99 UString DirPrefix;
100
101 virtual bool OnInit();
102 virtual bool OnSize(WPARAM wParam, int xSize, int ySize);
103 virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
104 virtual bool OnNotify(UINT controlID, LPNMHDR header);
105 virtual bool OnKeyDown(LPNMLVKEYDOWN keyDownInfo);
106 virtual bool OnButtonClicked(int buttonID, HWND buttonHWND);
107 virtual void OnOK();
108
Post_RefreshPathEdit()109 void Post_RefreshPathEdit() { PostMessage(k_Message_RefreshPathEdit); }
110
111 bool GetParentPath(const UString &path, UString &parentPrefix, UString &name);
112 // Reload changes DirPrefix. Don't send DirPrefix in pathPrefix parameter
113 HRESULT Reload(const UString &pathPrefix, const UString &selectedName);
114 HRESULT Reload();
115
116 void OpenParentFolder();
117 void SetPathEditText();
118 void OnCreateDir();
119 void OnItemEnter();
120 void FinishOnOK();
121
GetRealItemIndex(int indexInListView) const122 int GetRealItemIndex(int indexInListView) const
123 {
124 LPARAM param;
125 if (!_list.GetItemParam(indexInListView, param))
126 return (int)-1;
127 return (int)param;
128 }
129
130 public:
131 bool FolderMode;
132 UString Title;
133 UString FilePath; // input/ result path
134 bool ShowAllFiles;
135 UStringVector Filters;
136 UString FilterDescription;
137
CBrowseDialog()138 CBrowseDialog(): FolderMode(false), _showDots(false), ShowAllFiles(true) {}
139 void SetFilter(const UString &s);
Create(HWND parent=0)140 INT_PTR Create(HWND parent = 0) { return CModalDialog::Create(IDD_BROWSE, parent); }
141 int CompareItems(LPARAM lParam1, LPARAM lParam2);
142 };
143
SetFilter(const UString & s)144 void CBrowseDialog::SetFilter(const UString &s)
145 {
146 Filters.Clear();
147 UString mask;
148 unsigned i;
149 for (i = 0; i < s.Len(); i++)
150 {
151 wchar_t c = s[i];
152 if (c == ';')
153 {
154 if (!mask.IsEmpty())
155 Filters.Add(mask);
156 mask.Empty();
157 }
158 else
159 mask += c;
160 }
161 if (!mask.IsEmpty())
162 Filters.Add(mask);
163 ShowAllFiles = Filters.IsEmpty();
164 for (i = 0; i < Filters.Size(); i++)
165 {
166 const UString &f = Filters[i];
167 if (f == L"*.*" || f == L"*")
168 {
169 ShowAllFiles = true;
170 break;
171 }
172 }
173 }
174
OnInit()175 bool CBrowseDialog::OnInit()
176 {
177 #ifdef LANG
178 LangSetDlgItems(*this, NULL, 0);
179 #endif
180 if (!Title.IsEmpty())
181 SetText(Title);
182 _list.Attach(GetItem(IDL_BROWSE));
183 _filterCombo.Attach(GetItem(IDC_BROWSE_FILTER));
184 _pathEdit.Attach(GetItem(IDE_BROWSE_PATH));
185
186 if (FolderMode)
187 HideItem(IDC_BROWSE_FILTER);
188 else
189 EnableItem(IDC_BROWSE_FILTER, false);
190
191 #ifndef UNDER_CE
192 _list.SetUnicodeFormat();
193 #endif
194
195 #ifndef _SFX
196 if (ReadSingleClick())
197 _list.SetExtendedListViewStyle(LVS_EX_ONECLICKACTIVATE | LVS_EX_TRACKSELECT);
198 _showDots = ReadShowDots();
199 #endif
200
201 {
202 UString s;
203 if (!FilterDescription.IsEmpty())
204 s = FilterDescription;
205 else if (ShowAllFiles)
206 s = L"*.*";
207 else
208 {
209 FOR_VECTOR (i, Filters)
210 {
211 if (i != 0)
212 s += L' ';
213 s += Filters[i];
214 }
215 }
216 _filterCombo.AddString(s);
217 _filterCombo.SetCurSel(0);
218 }
219
220 _list.SetImageList(GetSysImageList(true), LVSIL_SMALL);
221 _list.SetImageList(GetSysImageList(false), LVSIL_NORMAL);
222
223 _list.InsertColumn(0, LangString(IDS_PROP_NAME), 100);
224 _list.InsertColumn(1, LangString(IDS_PROP_MTIME), 100);
225 {
226 LV_COLUMNW column;
227 column.iSubItem = 2;
228 column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
229 column.fmt = LVCFMT_RIGHT;
230 column.cx = 100;
231 const UString s = LangString(IDS_PROP_SIZE);
232 column.pszText = (wchar_t *)(const wchar_t *)s;
233 _list.InsertColumn(2, &column);
234 }
235
236 _list.InsertItem(0, L"12345678901234567"
237 #ifndef UNDER_CE
238 L"1234567890"
239 #endif
240 );
241 _list.SetSubItem(0, 1, L"2009-09-09"
242 #ifndef UNDER_CE
243 L" 09:09"
244 #endif
245 );
246 _list.SetSubItem(0, 2, L"9999 MB");
247 for (int i = 0; i < 3; i++)
248 _list.SetColumnWidthAuto(i);
249 _list.DeleteAllItems();
250
251 _ascending = true;
252 _sortIndex = 0;
253
254 NormalizeSize();
255
256 _topDirPrefix.Empty();
257 {
258 int rootSize = GetRootPrefixSize(FilePath);
259 // We can go up from root folder to drives list
260 if (NName::IsDrivePath(FilePath))
261 rootSize = 0;
262 else if (IsSuperPath(FilePath))
263 {
264 if (NName::IsDrivePath(&FilePath[kSuperPathPrefixSize]))
265 rootSize = kSuperPathPrefixSize;
266 }
267 _topDirPrefix.SetFrom(FilePath, rootSize);
268 }
269
270 UString name;
271 if (!GetParentPath(FilePath, DirPrefix, name))
272 DirPrefix = _topDirPrefix;
273
274 for(;;)
275 {
276 UString baseFolder = DirPrefix;
277 if (Reload(baseFolder, name) == S_OK)
278 break;
279 name.Empty();
280 if (DirPrefix.IsEmpty())
281 break;
282 UString parent, name2;
283 GetParentPath(DirPrefix, parent, name2);
284 DirPrefix = parent;
285 }
286
287 if (name.IsEmpty())
288 name = FilePath;
289 if (FolderMode)
290 NormalizeDirPathPrefix(name);
291 _pathEdit.SetText(name);
292
293 #ifndef UNDER_CE
294 /* If we clear UISF_HIDEFOCUS, the focus rectangle in ListView will be visible,
295 even if we use mouse for pressing the button to open this dialog. */
296 PostMessage(MY__WM_UPDATEUISTATE, MAKEWPARAM(MY__UIS_CLEAR, MY__UISF_HIDEFOCUS));
297 #endif
298
299 return CModalDialog::OnInit();
300 }
301
OnSize(WPARAM,int xSize,int ySize)302 bool CBrowseDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize)
303 {
304 int mx, my;
305 {
306 RECT r;
307 GetClientRectOfItem(IDB_BROWSE_PARENT, r);
308 mx = r.left;
309 my = r.top;
310 }
311 InvalidateRect(NULL);
312
313 int xLim = xSize - mx;
314 {
315 RECT r;
316 GetClientRectOfItem(IDT_BROWSE_FOLDER, r);
317 MoveItem(IDT_BROWSE_FOLDER, r.left, r.top, xLim - r.left, RECT_SIZE_Y(r));
318 }
319
320 int bx1, bx2, by;
321 GetItemSizes(IDCANCEL, bx1, by);
322 GetItemSizes(IDOK, bx2, by);
323 int y = ySize - my - by;
324 int x = xLim - bx1;
325 MoveItem(IDCANCEL, x, y, bx1, by);
326 MoveItem(IDOK, x - mx - bx2, y, bx2, by);
327
328 // Y_Size of ComboBox is tricky. So we use Y_Size of _pathEdit instead
329
330 int yPathSize;
331 {
332 RECT r;
333 GetClientRectOfItem(IDE_BROWSE_PATH, r);
334 yPathSize = RECT_SIZE_Y(r);
335 _pathEdit.Move(r.left, y - my - yPathSize - my - yPathSize, xLim - r.left, yPathSize);
336 }
337
338 {
339 RECT r;
340 GetClientRectOfItem(IDC_BROWSE_FILTER, r);
341 _filterCombo.Move(r.left, y - my - yPathSize, xLim - r.left, RECT_SIZE_Y(r));
342 }
343
344 {
345 RECT r;
346 GetClientRectOfItem(IDL_BROWSE, r);
347 _list.Move(r.left, r.top, xLim - r.left, y - my - yPathSize - my - yPathSize - my - r.top);
348 }
349
350 return false;
351 }
352
OnMessage(UINT message,WPARAM wParam,LPARAM lParam)353 bool CBrowseDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
354 {
355 if (message == k_Message_RefreshPathEdit)
356 {
357 SetPathEditText();
358 return true;
359 }
360 return CModalDialog::OnMessage(message, wParam, lParam);
361 }
362
OnNotify(UINT,LPNMHDR header)363 bool CBrowseDialog::OnNotify(UINT /* controlID */, LPNMHDR header)
364 {
365 if (header->hwndFrom != _list)
366 return false;
367 switch (header->code)
368 {
369 case LVN_ITEMACTIVATE:
370 if (g_LVN_ITEMACTIVATE_Support)
371 OnItemEnter();
372 break;
373 case NM_DBLCLK:
374 case NM_RETURN: // probabably it's unused
375 if (!g_LVN_ITEMACTIVATE_Support)
376 OnItemEnter();
377 break;
378 case LVN_COLUMNCLICK:
379 {
380 int index = LPNMLISTVIEW(header)->iSubItem;
381 if (index == _sortIndex)
382 _ascending = !_ascending;
383 else
384 {
385 _ascending = (index == 0);
386 _sortIndex = index;
387 }
388 Reload();
389 return false;
390 }
391 case LVN_KEYDOWN:
392 {
393 bool boolResult = OnKeyDown(LPNMLVKEYDOWN(header));
394 Post_RefreshPathEdit();
395 return boolResult;
396 }
397 case NM_RCLICK:
398 case NM_CLICK:
399 case LVN_BEGINDRAG:
400 Post_RefreshPathEdit();
401 break;
402 }
403 return false;
404 }
405
OnKeyDown(LPNMLVKEYDOWN keyDownInfo)406 bool CBrowseDialog::OnKeyDown(LPNMLVKEYDOWN keyDownInfo)
407 {
408 bool ctrl = IsKeyDown(VK_CONTROL);
409
410 switch (keyDownInfo->wVKey)
411 {
412 case VK_BACK:
413 OpenParentFolder();
414 return true;
415 case 'R':
416 if (ctrl)
417 {
418 Reload();
419 return true;
420 }
421 return false;
422 case VK_F7:
423 OnCreateDir();
424 return true;
425 }
426 return false;
427 }
428
OnButtonClicked(int buttonID,HWND buttonHWND)429 bool CBrowseDialog::OnButtonClicked(int buttonID, HWND buttonHWND)
430 {
431 switch (buttonID)
432 {
433 case IDB_BROWSE_PARENT: OpenParentFolder(); break;
434 case IDB_BROWSE_CREATE_DIR: OnCreateDir(); break;
435 default: return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
436 }
437 _list.SetFocus();
438 return true;
439 }
440
OnOK()441 void CBrowseDialog::OnOK()
442 {
443 /* When we press "Enter" in listview, Windows sends message to first Button.
444 We check that message was from ListView; */
445 if (GetFocus() == _list)
446 {
447 OnItemEnter();
448 return;
449 }
450 FinishOnOK();
451 }
452
453
GetParentPath(const UString & path,UString & parentPrefix,UString & name)454 bool CBrowseDialog::GetParentPath(const UString &path, UString &parentPrefix, UString &name)
455 {
456 parentPrefix.Empty();
457 name.Empty();
458 if (path.IsEmpty())
459 return false;
460 if (_topDirPrefix == path)
461 return false;
462 UString s = path;
463 if (s.Back() == WCHAR_PATH_SEPARATOR)
464 s.DeleteBack();
465 if (s.IsEmpty())
466 return false;
467 if (s.Back() == WCHAR_PATH_SEPARATOR)
468 return false;
469 int pos = s.ReverseFind(WCHAR_PATH_SEPARATOR);
470 parentPrefix.SetFrom(s, pos + 1);
471 name = s.Ptr(pos + 1);
472 return true;
473 }
474
CompareItems(LPARAM lParam1,LPARAM lParam2)475 int CBrowseDialog::CompareItems(LPARAM lParam1, LPARAM lParam2)
476 {
477 if (lParam1 == kParentIndex) return -1;
478 if (lParam2 == kParentIndex) return 1;
479 const CFileInfo &f1 = _files[(int)lParam1];
480 const CFileInfo &f2 = _files[(int)lParam2];
481
482 bool isDir1 = f1.IsDir();
483 bool isDir2 = f2.IsDir();
484 if (isDir1 && !isDir2) return -1;
485 if (isDir2 && !isDir1) return 1;
486
487 int res = 0;
488 switch (_sortIndex)
489 {
490 case 0: res = CompareFileNames(fs2us(f1.Name), fs2us(f2.Name)); break;
491 case 1: res = CompareFileTime(&f1.MTime, &f2.MTime); break;
492 case 2: res = MyCompare(f1.Size, f2.Size); break;
493 }
494 return _ascending ? res: -res;
495 }
496
CompareItems2(LPARAM lParam1,LPARAM lParam2,LPARAM lpData)497 static int CALLBACK CompareItems2(LPARAM lParam1, LPARAM lParam2, LPARAM lpData)
498 {
499 return ((CBrowseDialog *)lpData)->CompareItems(lParam1, lParam2);
500 }
501
ConvertSizeToString(UInt64 v,wchar_t * s)502 static void ConvertSizeToString(UInt64 v, wchar_t *s)
503 {
504 Byte c = 0;
505 if (v >= ((UInt64)10000 << 20)) { v >>= 30; c = 'G'; }
506 else if (v >= ((UInt64)10000 << 10)) { v >>= 20; c = 'M'; }
507 else if (v >= ((UInt64)10000 << 0)) { v >>= 10; c = 'K'; }
508 ConvertUInt64ToString(v, s);
509 if (c != 0)
510 {
511 s += MyStringLen(s);
512 *s++ = ' ';
513 *s++ = c;
514 *s++ = 0;
515 }
516 }
517
518 // Reload changes DirPrefix. Don't send DirPrefix in pathPrefix parameter
519
Reload(const UString & pathPrefix,const UString & selectedName)520 HRESULT CBrowseDialog::Reload(const UString &pathPrefix, const UString &selectedName)
521 {
522 CObjectVector<CFileInfo> files;
523
524 #ifndef UNDER_CE
525 bool isDrive = false;
526 if (pathPrefix.IsEmpty() || pathPrefix == kSuperPathPrefix)
527 {
528 isDrive = true;
529 FStringVector drives;
530 if (!MyGetLogicalDriveStrings(drives))
531 return GetNormalizedError();
532 FOR_VECTOR (i, drives)
533 {
534 FString d = drives[i];
535 if (d.Len() < 3 || d.Back() != '\\')
536 return E_FAIL;
537 d.DeleteBack();
538 CFileInfo &fi = files.AddNew();
539 fi.SetAsDir();
540 fi.Name = d;
541 }
542 }
543 else
544 #endif
545 {
546 CEnumerator enumerator(us2fs(pathPrefix + L'*'));
547 for (;;)
548 {
549 bool found;
550 CFileInfo fi;
551 if (!enumerator.Next(fi, found))
552 return GetNormalizedError();
553 if (!found)
554 break;
555 if (!fi.IsDir())
556 {
557 if (FolderMode)
558 continue;
559 if (!ShowAllFiles)
560 {
561 unsigned i;
562 for (i = 0; i < Filters.Size(); i++)
563 if (DoesWildcardMatchName(Filters[i], fs2us(fi.Name)))
564 break;
565 if (i == Filters.Size())
566 continue;
567 }
568 }
569 files.Add(fi);
570 }
571 }
572
573 DirPrefix = pathPrefix;
574
575 _files = files;
576
577 SetItemText(IDT_BROWSE_FOLDER, DirPrefix);
578
579 _list.SetRedraw(false);
580 _list.DeleteAllItems();
581
582 LVITEMW item;
583
584 int index = 0;
585 int cursorIndex = -1;
586
587 #ifndef _SFX
588 if (_showDots && _topDirPrefix != DirPrefix)
589 {
590 item.iItem = index;
591 const UString itemName = L"..";
592 if (selectedName.IsEmpty())
593 cursorIndex = index;
594 item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
595 int subItem = 0;
596 item.iSubItem = subItem++;
597 item.lParam = kParentIndex;
598 item.pszText = (wchar_t *)(const wchar_t *)itemName;
599 item.iImage = _extToIconMap.GetIconIndex(FILE_ATTRIBUTE_DIRECTORY, DirPrefix);
600 if (item.iImage < 0)
601 item.iImage = 0;
602 _list.InsertItem(&item);
603 _list.SetSubItem(index, subItem++, L"");
604 _list.SetSubItem(index, subItem++, L"");
605 index++;
606 }
607 #endif
608
609 for (unsigned i = 0; i < _files.Size(); i++, index++)
610 {
611 item.iItem = index;
612 const CFileInfo &fi = _files[i];
613 const UString name = fs2us(fi.Name);
614 if (!selectedName.IsEmpty() && CompareFileNames(name, selectedName) == 0)
615 cursorIndex = index;
616 item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
617 int subItem = 0;
618 item.iSubItem = subItem++;
619 item.lParam = i;
620 item.pszText = (wchar_t *)(const wchar_t *)name;
621
622 const UString fullPath = DirPrefix + name;
623 #ifndef UNDER_CE
624 if (isDrive)
625 {
626 if (GetRealIconIndex(fi.Name + FCHAR_PATH_SEPARATOR, FILE_ATTRIBUTE_DIRECTORY, item.iImage) == 0)
627 item.iImage = 0;
628 }
629 else
630 #endif
631 item.iImage = _extToIconMap.GetIconIndex(fi.Attrib, fullPath);
632 if (item.iImage < 0)
633 item.iImage = 0;
634 _list.InsertItem(&item);
635 wchar_t s[32];
636 {
637 FILETIME ft;
638 s[0] = 0;
639 if (FileTimeToLocalFileTime(&fi.MTime, &ft))
640 ConvertFileTimeToString(ft, s,
641 #ifndef UNDER_CE
642 true
643 #else
644 false
645 #endif
646 , false);
647 _list.SetSubItem(index, subItem++, s);
648 }
649 {
650 s[0] = 0;
651 if (!fi.IsDir())
652 ConvertSizeToString(fi.Size, s);
653 _list.SetSubItem(index, subItem++, s);
654 }
655 }
656
657 if (_list.GetItemCount() > 0 && cursorIndex >= 0)
658 _list.SetItemState_FocusedSelected(cursorIndex);
659 _list.SortItems(CompareItems2, (LPARAM)this);
660 if (_list.GetItemCount() > 0 && cursorIndex < 0)
661 _list.SetItemState(0, LVIS_FOCUSED, LVIS_FOCUSED);
662 _list.EnsureVisible(_list.GetFocusedItem(), false);
663 _list.SetRedraw(true);
664 _list.InvalidateRect(NULL, true);
665 return S_OK;
666 }
667
Reload()668 HRESULT CBrowseDialog::Reload()
669 {
670 UString selected;
671 int index = _list.GetNextSelectedItem(-1);
672 if (index >= 0)
673 {
674 int fileIndex = GetRealItemIndex(index);
675 if (fileIndex != kParentIndex)
676 selected = fs2us(_files[fileIndex].Name);
677 }
678 UString dirPathTemp = DirPrefix;
679 return Reload(dirPathTemp, selected);
680 }
681
OpenParentFolder()682 void CBrowseDialog::OpenParentFolder()
683 {
684 UString parent, selected;
685 if (GetParentPath(DirPrefix, parent, selected))
686 {
687 Reload(parent, selected);
688 SetPathEditText();
689 }
690 }
691
SetPathEditText()692 void CBrowseDialog::SetPathEditText()
693 {
694 int index = _list.GetNextSelectedItem(-1);
695 if (index < 0)
696 {
697 if (FolderMode)
698 _pathEdit.SetText(DirPrefix);
699 return;
700 }
701 int fileIndex = GetRealItemIndex(index);
702 if (fileIndex == kParentIndex)
703 {
704 if (FolderMode)
705 _pathEdit.SetText(L".." WSTRING_PATH_SEPARATOR);
706 return;
707 }
708 const CFileInfo &file = _files[fileIndex];
709 if (file.IsDir())
710 {
711 if (!FolderMode)
712 return;
713 _pathEdit.SetText(fs2us(file.Name) + WCHAR_PATH_SEPARATOR);
714 }
715 else
716 _pathEdit.SetText(fs2us(file.Name));
717 }
718
OnCreateDir()719 void CBrowseDialog::OnCreateDir()
720 {
721 UString name;
722 {
723 UString enteredName;
724 Dlg_CreateFolder((HWND)*this, enteredName);
725 if (enteredName.IsEmpty())
726 return;
727 if (!CorrectFsPath(DirPrefix, enteredName, name))
728 {
729 MessageBox_HResError((HWND)*this, ERROR_INVALID_NAME, name);
730 return;
731 }
732 }
733 if (name.IsEmpty())
734 return;
735
736 FString destPath;
737 if (GetFullPath(us2fs(DirPrefix), us2fs(name), destPath))
738 {
739 if (!NDir::CreateComplexDir(destPath))
740 {
741 MessageBox_HResError((HWND)*this, GetNormalizedError(), fs2us(destPath));
742 }
743 else
744 {
745 UString tempPath = DirPrefix;
746 Reload(tempPath, name);
747 SetPathEditText();
748 }
749 _list.SetFocus();
750 }
751 }
752
OnItemEnter()753 void CBrowseDialog::OnItemEnter()
754 {
755 int index = _list.GetNextSelectedItem(-1);
756 if (index < 0)
757 return;
758 int fileIndex = GetRealItemIndex(index);
759 if (fileIndex == kParentIndex)
760 OpenParentFolder();
761 else
762 {
763 const CFileInfo &file = _files[fileIndex];
764 if (!file.IsDir())
765 {
766 if (!FolderMode)
767 FinishOnOK();
768 /*
769 MessageBox_Error_Global(*this, FolderMode ?
770 L"You must select some folder":
771 L"You must select some file");
772 */
773 return;
774 }
775 UString s = DirPrefix + fs2us(file.Name) + WCHAR_PATH_SEPARATOR;
776 HRESULT res = Reload(s, L"");
777 if (res != S_OK)
778 MessageBox_HResError(*this, res, s);
779 SetPathEditText();
780 }
781 }
782
FinishOnOK()783 void CBrowseDialog::FinishOnOK()
784 {
785 UString s;
786 _pathEdit.GetText(s);
787 FString destPath;
788 if (!GetFullPath(us2fs(DirPrefix), us2fs(s), destPath))
789 {
790 MessageBox_HResError((HWND)*this, ERROR_INVALID_NAME, s);
791 return;
792 }
793 FilePath = fs2us(destPath);
794 if (FolderMode)
795 NormalizeDirPathPrefix(FilePath);
796 End(IDOK);
797 }
798
799 #endif
800
MyBrowseForFolder(HWND owner,LPCWSTR title,LPCWSTR path,UString & resultPath)801 bool MyBrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR path, UString &resultPath)
802 {
803 resultPath.Empty();
804
805 #ifndef UNDER_CE
806
807 #ifdef USE_MY_BROWSE_DIALOG
808 if (!IsSuperOrDevicePath(path))
809 #endif
810 return NShell::BrowseForFolder(owner, title, path, resultPath);
811
812 #endif
813
814 #ifdef USE_MY_BROWSE_DIALOG
815
816 CBrowseDialog dialog;
817 dialog.FolderMode = true;
818 if (title)
819 dialog.Title = title;
820 if (path)
821 dialog.FilePath = path;
822 if (dialog.Create(owner) != IDOK)
823 return false;
824 resultPath = dialog.FilePath;
825 #endif
826
827 return true;
828 }
829
MyBrowseForFile(HWND owner,LPCWSTR title,LPCWSTR path,LPCWSTR filterDescription,LPCWSTR filter,UString & resultPath)830 bool MyBrowseForFile(HWND owner, LPCWSTR title, LPCWSTR path,
831 LPCWSTR filterDescription, LPCWSTR filter, UString &resultPath)
832 {
833 resultPath.Empty();
834
835 #ifndef UNDER_CE
836
837 #ifdef USE_MY_BROWSE_DIALOG
838 if (!IsSuperOrDevicePath(path))
839 #endif
840 {
841 if (MyGetOpenFileName(owner, title, NULL, path, filterDescription, filter, resultPath))
842 return true;
843 #ifdef UNDER_CE
844 return false;
845 #else
846 // maybe we must use GetLastError in WinCE.
847 DWORD errorCode = CommDlgExtendedError();
848 const wchar_t *errorMessage = NULL;
849 switch (errorCode)
850 {
851 case 0: return false; // cancel or close obn dialog
852 case FNERR_INVALIDFILENAME: errorMessage = L"Invalid File Name"; break;
853 default: errorMessage = L"Open Dialog Error";
854 }
855 if (!errorMessage)
856 return false;
857 {
858 UString s = errorMessage;
859 s += L"\n";
860 s += path;
861 MessageBox_Error_Global(owner, s);
862 }
863 #endif
864 }
865
866 #endif
867
868 #ifdef USE_MY_BROWSE_DIALOG
869 CBrowseDialog dialog;
870 if (title)
871 dialog.Title = title;
872 if (path)
873 dialog.FilePath = path;
874 dialog.FolderMode = false;
875 if (filter)
876 dialog.SetFilter(filter);
877 if (filterDescription)
878 dialog.FilterDescription = filterDescription;
879 if (dialog.Create(owner) != IDOK)
880 return false;
881 resultPath = dialog.FilePath;
882 #endif
883
884 return true;
885 }
886
887
888 #ifdef _WIN32
889
RemoveDotsAndSpaces(UString & path)890 static void RemoveDotsAndSpaces(UString &path)
891 {
892 while (!path.IsEmpty())
893 {
894 wchar_t c = path.Back();
895 if (c != ' ' && c != '.')
896 return;
897 path.DeleteBack();
898 }
899 }
900
901
CorrectFsPath(const UString & relBase,const UString & path2,UString & result)902 bool CorrectFsPath(const UString &relBase, const UString &path2, UString &result)
903 {
904 result.Empty();
905
906 UString path = path2;
907 path.Replace('/', WCHAR_PATH_SEPARATOR);
908 unsigned start = 0;
909 UString base;
910 if (NName::IsAbsolutePath(path))
911 {
912 if (IsSuperOrDevicePath(path))
913 {
914 result = path;
915 return true;
916 }
917 int pos = GetRootPrefixSize(path);
918 if (pos > 0)
919 start = pos;
920 }
921 else
922 {
923 if (IsSuperOrDevicePath(relBase))
924 {
925 result = path;
926 return true;
927 }
928 base = relBase;
929 }
930
931 /* We can't use backward, since we must change only disk paths */
932 /*
933 for (;;)
934 {
935 if (path.Len() <= start)
936 break;
937 if (DoesFileOrDirExist(us2fs(path)))
938 break;
939 if (path.Back() == WCHAR_PATH_SEPARATOR)
940 {
941 path.DeleteBack();
942 result.Insert(0, WCHAR_PATH_SEPARATOR);;
943 }
944 int pos = path.ReverseFind(WCHAR_PATH_SEPARATOR) + 1;
945 UString cur = path.Ptr(pos);
946 RemoveDotsAndSpaces(cur);
947 result.Insert(0, cur);
948 path.DeleteFrom(pos);
949 }
950 result.Insert(0, path);
951 return true;
952 */
953
954 result += path.Left(start);
955 bool checkExist = true;
956 UString cur;
957 for (;;)
958 {
959 if (start == path.Len())
960 break;
961 int slashPos = path.Find(WCHAR_PATH_SEPARATOR, start);
962 cur.SetFrom(path.Ptr(start), (slashPos < 0 ? path.Len() : slashPos) - start);
963 if (checkExist)
964 {
965 CFileInfo fi;
966 if (fi.Find(us2fs(base + result + cur)))
967 {
968 if (!fi.IsDir())
969 {
970 result = path;
971 break;
972 }
973 }
974 else
975 checkExist = false;
976 }
977 if (!checkExist)
978 RemoveDotsAndSpaces(cur);
979 result += cur;
980 if (slashPos < 0)
981 break;
982 result += WCHAR_PATH_SEPARATOR;
983 start = slashPos + 1;
984 }
985
986 return true;
987 }
988
989 #else
CorrectFsPath(const UString &,const UString & path,UString & result)990 bool CorrectFsPath(const UString & /* relBase */, const UString &path, UString &result)
991 {
992 result = path;
993 return true;
994 }
995 #endif
996
Dlg_CreateFolder(HWND wnd,UString & destName)997 bool Dlg_CreateFolder(HWND wnd, UString &destName)
998 {
999 destName.Empty();
1000 CComboDialog dlg;
1001 LangString(IDS_CREATE_FOLDER, dlg.Title);
1002 LangString(IDS_CREATE_FOLDER_NAME, dlg.Static);
1003 LangString(IDS_CREATE_FOLDER_DEFAULT_NAME, dlg.Value);
1004 if (dlg.Create(wnd) != IDOK)
1005 return false;
1006 destName = dlg.Value;
1007 return true;
1008 }
1009