• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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