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