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 = "*.*";
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 (IS_PATH_SEPAR(s.Back()))
472 s.DeleteBack();
473 if (s.IsEmpty())
474 return false;
475 if (IS_PATH_SEPAR(s.Back()))
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.IsEqualTo(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;
555 enumerator.SetDirPrefix(us2fs(pathPrefix));
556 for (;;)
557 {
558 bool found;
559 CFileInfo fi;
560 if (!enumerator.Next(fi, found))
561 return GetNormalizedError();
562 if (!found)
563 break;
564 if (!fi.IsDir())
565 {
566 if (FolderMode)
567 continue;
568 if (!ShowAllFiles)
569 {
570 unsigned i;
571 for (i = 0; i < Filters.Size(); i++)
572 if (DoesWildcardMatchName(Filters[i], fs2us(fi.Name)))
573 break;
574 if (i == Filters.Size())
575 continue;
576 }
577 }
578 files.Add(fi);
579 }
580 }
581
582 DirPrefix = pathPrefix;
583
584 _files = files;
585
586 SetItemText(IDT_BROWSE_FOLDER, DirPrefix);
587
588 _list.SetRedraw(false);
589 _list.DeleteAllItems();
590
591 LVITEMW item;
592
593 int index = 0;
594 int cursorIndex = -1;
595
596 #ifndef _SFX
597 if (_showDots && _topDirPrefix != DirPrefix)
598 {
599 item.iItem = index;
600 const UString itemName ("..");
601 if (selectedName.IsEmpty())
602 cursorIndex = index;
603 item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
604 int subItem = 0;
605 item.iSubItem = subItem++;
606 item.lParam = kParentIndex;
607 item.pszText = (wchar_t *)(const wchar_t *)itemName;
608 item.iImage = _extToIconMap.GetIconIndex(FILE_ATTRIBUTE_DIRECTORY, DirPrefix);
609 if (item.iImage < 0)
610 item.iImage = 0;
611 _list.InsertItem(&item);
612 _list.SetSubItem(index, subItem++, L"");
613 _list.SetSubItem(index, subItem++, L"");
614 index++;
615 }
616 #endif
617
618 for (unsigned i = 0; i < _files.Size(); i++, index++)
619 {
620 item.iItem = index;
621 const CFileInfo &fi = _files[i];
622 const UString name = fs2us(fi.Name);
623 if (!selectedName.IsEmpty() && CompareFileNames(name, selectedName) == 0)
624 cursorIndex = index;
625 item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
626 int subItem = 0;
627 item.iSubItem = subItem++;
628 item.lParam = i;
629 item.pszText = (wchar_t *)(const wchar_t *)name;
630
631 const UString fullPath = DirPrefix + name;
632 #ifndef UNDER_CE
633 if (isDrive)
634 {
635 if (GetRealIconIndex(fi.Name + FCHAR_PATH_SEPARATOR, FILE_ATTRIBUTE_DIRECTORY, item.iImage) == 0)
636 item.iImage = 0;
637 }
638 else
639 #endif
640 item.iImage = _extToIconMap.GetIconIndex(fi.Attrib, fullPath);
641 if (item.iImage < 0)
642 item.iImage = 0;
643 _list.InsertItem(&item);
644 wchar_t s[32];
645 {
646 s[0] = 0;
647 ConvertUtcFileTimeToString(fi.MTime, s,
648 #ifndef UNDER_CE
649 kTimestampPrintLevel_MIN
650 #else
651 kTimestampPrintLevel_DAY
652 #endif
653 );
654 _list.SetSubItem(index, subItem++, s);
655 }
656 {
657 s[0] = 0;
658 if (!fi.IsDir())
659 ConvertSizeToString(fi.Size, s);
660 _list.SetSubItem(index, subItem++, s);
661 }
662 }
663
664 if (_list.GetItemCount() > 0 && cursorIndex >= 0)
665 _list.SetItemState_FocusedSelected(cursorIndex);
666 _list.SortItems(CompareItems2, (LPARAM)this);
667 if (_list.GetItemCount() > 0 && cursorIndex < 0)
668 _list.SetItemState(0, LVIS_FOCUSED, LVIS_FOCUSED);
669 _list.EnsureVisible(_list.GetFocusedItem(), false);
670 _list.SetRedraw(true);
671 _list.InvalidateRect(NULL, true);
672 return S_OK;
673 }
674
Reload()675 HRESULT CBrowseDialog::Reload()
676 {
677 UString selected;
678 int index = _list.GetNextSelectedItem(-1);
679 if (index >= 0)
680 {
681 int fileIndex = GetRealItemIndex(index);
682 if (fileIndex != kParentIndex)
683 selected = fs2us(_files[fileIndex].Name);
684 }
685 UString dirPathTemp = DirPrefix;
686 return Reload(dirPathTemp, selected);
687 }
688
OpenParentFolder()689 void CBrowseDialog::OpenParentFolder()
690 {
691 UString parent, selected;
692 if (GetParentPath(DirPrefix, parent, selected))
693 {
694 Reload(parent, selected);
695 SetPathEditText();
696 }
697 }
698
SetPathEditText()699 void CBrowseDialog::SetPathEditText()
700 {
701 int index = _list.GetNextSelectedItem(-1);
702 if (index < 0)
703 {
704 if (FolderMode)
705 _pathEdit.SetText(DirPrefix);
706 return;
707 }
708 int fileIndex = GetRealItemIndex(index);
709 if (fileIndex == kParentIndex)
710 {
711 if (FolderMode)
712 _pathEdit.SetText(L".." WSTRING_PATH_SEPARATOR);
713 return;
714 }
715 const CFileInfo &file = _files[fileIndex];
716 if (file.IsDir())
717 {
718 if (!FolderMode)
719 return;
720 _pathEdit.SetText(fs2us(file.Name) + WCHAR_PATH_SEPARATOR);
721 }
722 else
723 _pathEdit.SetText(fs2us(file.Name));
724 }
725
OnCreateDir()726 void CBrowseDialog::OnCreateDir()
727 {
728 UString name;
729 {
730 UString enteredName;
731 Dlg_CreateFolder((HWND)*this, enteredName);
732 if (enteredName.IsEmpty())
733 return;
734 if (!CorrectFsPath(DirPrefix, enteredName, name))
735 {
736 MessageBox_HResError((HWND)*this, ERROR_INVALID_NAME, name);
737 return;
738 }
739 }
740 if (name.IsEmpty())
741 return;
742
743 FString destPath;
744 if (GetFullPath(us2fs(DirPrefix), us2fs(name), destPath))
745 {
746 if (!NDir::CreateComplexDir(destPath))
747 {
748 MessageBox_HResError((HWND)*this, GetNormalizedError(), fs2us(destPath));
749 }
750 else
751 {
752 UString tempPath = DirPrefix;
753 Reload(tempPath, name);
754 SetPathEditText();
755 }
756 _list.SetFocus();
757 }
758 }
759
OnItemEnter()760 void CBrowseDialog::OnItemEnter()
761 {
762 int index = _list.GetNextSelectedItem(-1);
763 if (index < 0)
764 return;
765 int fileIndex = GetRealItemIndex(index);
766 if (fileIndex == kParentIndex)
767 OpenParentFolder();
768 else
769 {
770 const CFileInfo &file = _files[fileIndex];
771 if (!file.IsDir())
772 {
773 if (!FolderMode)
774 FinishOnOK();
775 /*
776 MessageBox_Error_Global(*this, FolderMode ?
777 L"You must select some folder":
778 L"You must select some file");
779 */
780 return;
781 }
782 UString s = DirPrefix;
783 s += fs2us(file.Name);
784 s.Add_PathSepar();
785 HRESULT res = Reload(s, UString());
786 if (res != S_OK)
787 MessageBox_HResError(*this, res, s);
788 SetPathEditText();
789 }
790 }
791
FinishOnOK()792 void CBrowseDialog::FinishOnOK()
793 {
794 UString s;
795 _pathEdit.GetText(s);
796 FString destPath;
797 if (!GetFullPath(us2fs(DirPrefix), us2fs(s), destPath))
798 {
799 MessageBox_HResError((HWND)*this, ERROR_INVALID_NAME, s);
800 return;
801 }
802 FilePath = fs2us(destPath);
803 if (FolderMode)
804 NormalizeDirPathPrefix(FilePath);
805 End(IDOK);
806 }
807
808 #endif
809
MyBrowseForFolder(HWND owner,LPCWSTR title,LPCWSTR path,UString & resultPath)810 bool MyBrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR path, UString &resultPath)
811 {
812 resultPath.Empty();
813
814 #ifndef UNDER_CE
815
816 #ifdef USE_MY_BROWSE_DIALOG
817 if (!IsSuperOrDevicePath(path))
818 #endif
819 return NShell::BrowseForFolder(owner, title, path, resultPath);
820
821 #endif
822
823 #ifdef USE_MY_BROWSE_DIALOG
824
825 CBrowseDialog dialog;
826 dialog.FolderMode = true;
827 if (title)
828 dialog.Title = title;
829 if (path)
830 dialog.FilePath = path;
831 if (dialog.Create(owner) != IDOK)
832 return false;
833 resultPath = dialog.FilePath;
834 #endif
835
836 return true;
837 }
838
MyBrowseForFile(HWND owner,LPCWSTR title,LPCWSTR path,LPCWSTR filterDescription,LPCWSTR filter,UString & resultPath)839 bool MyBrowseForFile(HWND owner, LPCWSTR title, LPCWSTR path,
840 LPCWSTR filterDescription, LPCWSTR filter, UString &resultPath)
841 {
842 resultPath.Empty();
843
844 #ifndef UNDER_CE
845
846 #ifdef USE_MY_BROWSE_DIALOG
847 if (!IsSuperOrDevicePath(path))
848 #endif
849 {
850 if (MyGetOpenFileName(owner, title, NULL, path, filterDescription, filter, resultPath))
851 return true;
852 #ifdef UNDER_CE
853 return false;
854 #else
855 // maybe we must use GetLastError in WinCE.
856 DWORD errorCode = CommDlgExtendedError();
857 const char *errorMessage = NULL;
858 switch (errorCode)
859 {
860 case 0: return false; // cancel or close obn dialog
861 case FNERR_INVALIDFILENAME: errorMessage = "Invalid File Name"; break;
862 default: errorMessage = "Open Dialog Error";
863 }
864 if (!errorMessage)
865 return false;
866 {
867 UString s (errorMessage);
868 s.Add_LF();
869 s += path;
870 MessageBox_Error_Global(owner, s);
871 }
872 #endif
873 }
874
875 #endif
876
877 #ifdef USE_MY_BROWSE_DIALOG
878 CBrowseDialog dialog;
879 if (title)
880 dialog.Title = title;
881 if (path)
882 dialog.FilePath = path;
883 dialog.FolderMode = false;
884 if (filter)
885 dialog.SetFilter(filter);
886 if (filterDescription)
887 dialog.FilterDescription = filterDescription;
888 if (dialog.Create(owner) != IDOK)
889 return false;
890 resultPath = dialog.FilePath;
891 #endif
892
893 return true;
894 }
895
896
897 #ifdef _WIN32
898
RemoveDotsAndSpaces(UString & path)899 static void RemoveDotsAndSpaces(UString &path)
900 {
901 while (!path.IsEmpty())
902 {
903 wchar_t c = path.Back();
904 if (c != ' ' && c != '.')
905 return;
906 path.DeleteBack();
907 }
908 }
909
910
CorrectFsPath(const UString & relBase,const UString & path2,UString & result)911 bool CorrectFsPath(const UString &relBase, const UString &path2, UString &result)
912 {
913 result.Empty();
914
915 UString path = path2;
916 path.Replace(L'/', WCHAR_PATH_SEPARATOR);
917 unsigned start = 0;
918 UString base;
919
920 if (IsAbsolutePath(path))
921 {
922 #if defined(_WIN32) && !defined(UNDER_CE)
923 if (IsSuperOrDevicePath(path))
924 {
925 result = path;
926 return true;
927 }
928 #endif
929 int pos = GetRootPrefixSize(path);
930 if (pos > 0)
931 start = pos;
932 }
933 else
934 {
935 #if defined(_WIN32) && !defined(UNDER_CE)
936 if (IsSuperOrDevicePath(relBase))
937 {
938 result = path;
939 return true;
940 }
941 #endif
942 base = relBase;
943 }
944
945 /* We can't use backward, since we must change only disk paths */
946 /*
947 for (;;)
948 {
949 if (path.Len() <= start)
950 break;
951 if (DoesFileOrDirExist(us2fs(path)))
952 break;
953 if (path.Back() == WCHAR_PATH_SEPARATOR)
954 {
955 path.DeleteBack();
956 result.Insert(0, WCHAR_PATH_SEPARATOR);;
957 }
958 int pos = path.ReverseFind(WCHAR_PATH_SEPARATOR) + 1;
959 UString cur = path.Ptr(pos);
960 RemoveDotsAndSpaces(cur);
961 result.Insert(0, cur);
962 path.DeleteFrom(pos);
963 }
964 result.Insert(0, path);
965 return true;
966 */
967
968 result += path.Left(start);
969 bool checkExist = true;
970 UString cur;
971
972 for (;;)
973 {
974 if (start == path.Len())
975 break;
976 int slashPos = path.Find(WCHAR_PATH_SEPARATOR, start);
977 cur.SetFrom(path.Ptr(start), (slashPos < 0 ? path.Len() : slashPos) - start);
978 if (checkExist)
979 {
980 CFileInfo fi;
981 if (fi.Find(us2fs(base + result + cur)))
982 {
983 if (!fi.IsDir())
984 {
985 result = path;
986 break;
987 }
988 }
989 else
990 checkExist = false;
991 }
992 if (!checkExist)
993 RemoveDotsAndSpaces(cur);
994 result += cur;
995 if (slashPos < 0)
996 break;
997 result.Add_PathSepar();
998 start = slashPos + 1;
999 }
1000
1001 return true;
1002 }
1003
1004 #else
1005
CorrectFsPath(const UString &,const UString & path,UString & result)1006 bool CorrectFsPath(const UString & /* relBase */, const UString &path, UString &result)
1007 {
1008 result = path;
1009 return true;
1010 }
1011
1012 #endif
1013
Dlg_CreateFolder(HWND wnd,UString & destName)1014 bool Dlg_CreateFolder(HWND wnd, UString &destName)
1015 {
1016 destName.Empty();
1017 CComboDialog dlg;
1018 LangString(IDS_CREATE_FOLDER, dlg.Title);
1019 LangString(IDS_CREATE_FOLDER_NAME, dlg.Static);
1020 LangString(IDS_CREATE_FOLDER_DEFAULT_NAME, dlg.Value);
1021 if (dlg.Create(wnd) != IDOK)
1022 return false;
1023 destName = dlg.Value;
1024 return true;
1025 }
1026