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