xref: /aosp_15_r20/external/lzma/CPP/7zip/UI/FileManager/PanelFolderChange.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // PanelFolderChange.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../Common/StringConvert.h"
6 #include "../../../Common/Wildcard.h"
7 
8 #include "../../../Windows/FileName.h"
9 #include "../../../Windows/FileDir.h"
10 #include "../../../Windows/PropVariant.h"
11 
12 #include "../../PropID.h"
13 
14 #ifdef UNDER_CE
15 #include "FSFolder.h"
16 #else
17 #include "FSDrives.h"
18 #endif
19 #include "LangUtils.h"
20 #include "ListViewDialog.h"
21 #include "Panel.h"
22 #include "RootFolder.h"
23 #include "ViewSettings.h"
24 
25 #include "resource.h"
26 
27 using namespace NWindows;
28 using namespace NFile;
29 using namespace NFind;
30 
ReleaseFolder()31 void CPanel::ReleaseFolder()
32 {
33   DeleteListItems();
34 
35   _folder.Release();
36 
37   _folderCompare.Release();
38   _folderGetItemName.Release();
39   _folderRawProps.Release();
40   _folderAltStreams.Release();
41   _folderOperations.Release();
42 
43   _thereAreDeletedItems = false;
44 }
45 
SetNewFolder(IFolderFolder * newFolder)46 void CPanel::SetNewFolder(IFolderFolder *newFolder)
47 {
48   ReleaseFolder();
49   _folder = newFolder;
50   if (_folder)
51   {
52     _folder.QueryInterface(IID_IFolderCompare, &_folderCompare);
53     _folder.QueryInterface(IID_IFolderGetItemName, &_folderGetItemName);
54     _folder.QueryInterface(IID_IArchiveGetRawProps, &_folderRawProps);
55     _folder.QueryInterface(IID_IFolderAltStreams, &_folderAltStreams);
56     _folder.QueryInterface(IID_IFolderOperations, &_folderOperations);
57   }
58 }
59 
SetToRootFolder()60 void CPanel::SetToRootFolder()
61 {
62   ReleaseFolder();
63   _library.Free();
64 
65   CRootFolder *rootFolderSpec = new CRootFolder;
66   SetNewFolder(rootFolderSpec);
67   rootFolderSpec->Init();
68 }
69 
70 
DoesNameContainWildcard_SkipRoot(const UString & path)71 static bool DoesNameContainWildcard_SkipRoot(const UString &path)
72 {
73   return DoesNameContainWildcard(path.Ptr(NName::GetRootPrefixSize(path)));
74 }
75 
BindToPath(const UString & fullPath,const UString & arcFormat,COpenResult & openRes)76 HRESULT CPanel::BindToPath(const UString &fullPath, const UString &arcFormat, COpenResult &openRes)
77 {
78   UString path = fullPath;
79   #ifdef _WIN32
80   path.Replace(L'/', WCHAR_PATH_SEPARATOR);
81   #endif
82 
83   openRes.ArchiveIsOpened = false;
84   openRes.Encrypted = false;
85 
86   CDisableTimerProcessing disableTimerProcessing(*this);
87   CDisableNotify disableNotify(*this);
88 
89   for (; !_parentFolders.IsEmpty(); CloseOneLevel())
90   {
91     // ---------- we try to use open archive ----------
92 
93     const CFolderLink &link = _parentFolders.Back();
94     const UString &virtPath = link.VirtualPath;
95     if (!path.IsPrefixedBy(virtPath))
96       continue;
97     UString relatPath = path.Ptr(virtPath.Len());
98     if (!relatPath.IsEmpty())
99     {
100       if (!IS_PATH_SEPAR(relatPath[0]))
101         continue;
102       else
103         relatPath.Delete(0);
104     }
105 
106     UString relatPath2 = relatPath;
107     if (!relatPath2.IsEmpty() && !IS_PATH_SEPAR(relatPath2.Back()))
108       relatPath2.Add_PathSepar();
109 
110     for (;;)
111     {
112       const UString foldPath = GetFolderPath(_folder);
113       if (relatPath2 == foldPath)
114         break;
115       if (relatPath.IsPrefixedBy(foldPath))
116       {
117         path = relatPath.Ptr(foldPath.Len());
118         break;
119       }
120       CMyComPtr<IFolderFolder> newFolder;
121       if (_folder->BindToParentFolder(&newFolder) != S_OK)
122         throw 20140918;
123       if (!newFolder) // we exit from loop above if (relatPath.IsPrefixedBy(empty path for root folder)
124         throw 20140918;
125       SetNewFolder(newFolder);
126     }
127     break;
128   }
129 
130   if (_parentFolders.IsEmpty())
131   {
132     // ---------- we open file or folder from file system ----------
133 
134     CloseOpenFolders();
135     UString sysPath = path;
136     /* we will Empty() sysPath variable, if we need to BindToFolder()
137        directly with (path) variable */
138     const unsigned prefixSize = NName::GetRootPrefixSize(sysPath);
139     if (prefixSize == 0 || sysPath[prefixSize] == 0)
140       sysPath.Empty();
141 
142     #if defined(_WIN32) && !defined(UNDER_CE)
143     if (!sysPath.IsEmpty() && sysPath.Back() == ':' &&
144       (sysPath.Len() != 2 || !NName::IsDrivePath2(sysPath)))
145     {
146       // if base item for alt streams prefix "base:" exists, we will use it
147       UString baseFile = sysPath;
148       baseFile.DeleteBack();
149       if (NFind::DoesFileOrDirExist(us2fs(baseFile)))
150         sysPath.Empty();
151     }
152     #endif
153 
154     CFileInfo fileInfo;
155 
156     while (!sysPath.IsEmpty())
157     {
158       if (sysPath.Len() <= prefixSize)
159       {
160         path.DeleteFrom(prefixSize);
161         sysPath.Empty();
162         break;
163       }
164 
165       fileInfo.ClearBase();
166       if (IsPathSepar(sysPath.Back()))
167       {
168         /* Windows 10 by default doesn't allow look "Local Settings" that is junction to "AppData\Local",
169            but it does allow look "Local Settings\Temp\*"
170            22.02: at first we try to use paths with slashes "path\" */
171         CFileInfo fi;
172         // CFindFile findFile;
173         // FString path2 = us2fs(sysPath);
174         // path2 += '*'; // CHAR_ANY_MASK;
175         // if (findFile.FindFirst(path2, fi))
176         CEnumerator enumerator;
177         enumerator.SetDirPrefix(us2fs(sysPath));
178         bool found = false;
179         if (enumerator.Next(fi, found))
180         {
181           // sysPath.DeleteBack();
182           fileInfo.SetAsDir();
183           fileInfo.Size = 0;
184           fileInfo.Name.Empty();
185           break;
186         }
187         sysPath.DeleteBack();
188         continue;
189       }
190 
191       if (fileInfo.Find(us2fs(sysPath)))
192         break;
193       int pos = sysPath.ReverseFind_PathSepar();
194       if (pos < 0)
195       {
196         sysPath.Empty();
197         break;
198       }
199       {
200         if ((unsigned)pos != sysPath.Len() - 1)
201           pos++;
202         sysPath.DeleteFrom((unsigned)pos);
203       }
204     }
205 
206     SetToRootFolder();
207 
208     CMyComPtr<IFolderFolder> newFolder;
209 
210     if (sysPath.IsEmpty())
211     {
212       _folder->BindToFolder(path, &newFolder);
213     }
214     else if (fileInfo.IsDir())
215     {
216       #ifdef _WIN32
217       if (DoesNameContainWildcard_SkipRoot(sysPath))
218       {
219         FString dirPrefix, fileName;
220         NDir::GetFullPathAndSplit(us2fs(sysPath), dirPrefix, fileName);
221         if (DoesNameContainWildcard_SkipRoot(fs2us(dirPrefix)))
222           return E_INVALIDARG;
223         sysPath = fs2us(dirPrefix + fileInfo.Name);
224       }
225       #endif
226 
227       NName::NormalizeDirPathPrefix(sysPath);
228       _folder->BindToFolder(sysPath, &newFolder);
229     }
230     else
231     {
232       FString dirPrefix, fileName;
233 
234       NDir::GetFullPathAndSplit(us2fs(sysPath), dirPrefix, fileName);
235 
236       HRESULT res = S_OK;
237 
238       #ifdef _WIN32
239       if (DoesNameContainWildcard_SkipRoot(fs2us(dirPrefix)))
240         return E_INVALIDARG;
241 
242       if (DoesNameContainWildcard(fs2us(fileName)))
243         res = S_FALSE;
244       else
245       #endif
246       {
247         CTempFileInfo tfi;
248         tfi.RelPath = fs2us(fileName);
249         tfi.FolderPath = dirPrefix;
250         tfi.FilePath = us2fs(sysPath);
251         res = OpenAsArc(NULL, tfi, sysPath, arcFormat, openRes);
252       }
253 
254       if (res == S_FALSE)
255         _folder->BindToFolder(fs2us(dirPrefix), &newFolder);
256       else
257       {
258         RINOK(res)
259         openRes.ArchiveIsOpened = true;
260         _parentFolders.Back().ParentFolderPath = fs2us(dirPrefix);
261         path.DeleteFrontal(sysPath.Len());
262         if (!path.IsEmpty() && IS_PATH_SEPAR(path[0]))
263           path.Delete(0);
264       }
265     }
266 
267     if (newFolder)
268     {
269       SetNewFolder(newFolder);
270       // LoadFullPath();
271       return S_OK;
272     }
273   }
274 
275   {
276     // ---------- we open folder remPath in archive and sub archives ----------
277 
278     for (unsigned curPos = 0; curPos != path.Len();)
279     {
280       UString s = path.Ptr(curPos);
281       const int slashPos = NName::FindSepar(s);
282       unsigned skipLen = s.Len();
283       if (slashPos >= 0)
284       {
285         s.DeleteFrom((unsigned)slashPos);
286         skipLen = (unsigned)slashPos + 1;
287       }
288 
289       CMyComPtr<IFolderFolder> newFolder;
290       _folder->BindToFolder(s, &newFolder);
291       if (newFolder)
292         curPos += skipLen;
293       else if (_folderAltStreams)
294       {
295         const int pos = s.Find(L':');
296         if (pos >= 0)
297         {
298           UString baseName = s;
299           baseName.DeleteFrom((unsigned)pos);
300           if (_folderAltStreams->BindToAltStreams(baseName, &newFolder) == S_OK && newFolder)
301             curPos += (unsigned)pos + 1;
302         }
303       }
304 
305       if (!newFolder)
306         break;
307 
308       SetNewFolder(newFolder);
309     }
310   }
311 
312   return S_OK;
313 }
314 
BindToPathAndRefresh(const UString & path)315 HRESULT CPanel::BindToPathAndRefresh(const UString &path)
316 {
317   CDisableTimerProcessing disableTimerProcessing(*this);
318   CDisableNotify disableNotify(*this);
319   COpenResult openRes;
320   UString s = path;
321 
322   #ifdef _WIN32
323     if (!s.IsEmpty() && s[0] == '\"' && s.Back() == '\"')
324     {
325       s.DeleteBack();
326       s.Delete(0);
327     }
328   #endif
329 
330   HRESULT res = BindToPath(s, UString(), openRes);
331   RefreshListCtrl();
332   return res;
333 }
334 
SetBookmark(unsigned index)335 void CPanel::SetBookmark(unsigned index)
336 {
337   _appState->FastFolders.SetString(index, _currentFolderPrefix);
338 }
339 
OpenBookmark(unsigned index)340 void CPanel::OpenBookmark(unsigned index)
341 {
342   BindToPathAndRefresh(_appState->FastFolders.GetString(index));
343 }
344 
GetFolderPath(IFolderFolder * folder)345 UString GetFolderPath(IFolderFolder *folder)
346 {
347   {
348     NCOM::CPropVariant prop;
349     if (folder->GetFolderProperty(kpidPath, &prop) == S_OK)
350       if (prop.vt == VT_BSTR)
351         return (wchar_t *)prop.bstrVal;
352   }
353   return UString();
354 }
355 
LoadFullPath()356 void CPanel::LoadFullPath()
357 {
358   _currentFolderPrefix.Empty();
359   FOR_VECTOR (i, _parentFolders)
360   {
361     const CFolderLink &folderLink = _parentFolders[i];
362     _currentFolderPrefix += folderLink.ParentFolderPath;
363         // GetFolderPath(folderLink.ParentFolder);
364     _currentFolderPrefix += folderLink.RelPath;
365     _currentFolderPrefix.Add_PathSepar();
366   }
367   if (_folder)
368     _currentFolderPrefix += GetFolderPath(_folder);
369 }
370 
371 
372 
GetRealIconIndex_for_DirPath(CFSTR path,DWORD attrib)373 static int GetRealIconIndex_for_DirPath(CFSTR path, DWORD attrib)
374 {
375   attrib |= FILE_ATTRIBUTE_DIRECTORY; // optional
376   int index = -1;
377   if (Shell_GetFileInfo_SysIconIndex_for_Path_attrib_iconIndexRef(path, attrib, index))
378     if (index >= 0)
379       return index;
380   return g_Ext_to_Icon_Map.GetIconIndex_DIR(attrib);
381 }
382 
383 
384 extern UString RootFolder_GetName_Computer(int &iconIndex);
385 extern UString RootFolder_GetName_Network(int &iconIndex);
386 extern UString RootFolder_GetName_Documents(int &iconIndex);
387 
388 
Find_FileExtension_DotPos_in_path(const wchar_t * path)389 static int Find_FileExtension_DotPos_in_path(const wchar_t *path)
390 {
391   int dotPos = -1;
392   unsigned i;
393   for (i = 0;; i++)
394   {
395     const wchar_t c = path[i];
396     if (c == 0)
397       return dotPos;
398     if (c == '.')
399       dotPos = (int)i;
400     else if (IS_PATH_SEPAR(c) || c == ':')
401       dotPos = -1;
402   }
403 }
404 
405 
LoadFullPathAndShow()406 void CPanel::LoadFullPathAndShow()
407 {
408   LoadFullPath();
409   _appState->FolderHistory.AddString(_currentFolderPrefix);
410 
411   _headerComboBox.SetText(_currentFolderPrefix);
412 
413   #ifndef UNDER_CE
414 
415   COMBOBOXEXITEM item;
416   item.mask = 0;
417   item.iImage = -1;
418 
419   UString path = _currentFolderPrefix;
420   // path = "\\\\.\\PhysicalDrive1\\"; // for debug
421   // path = "\\\\.\\y:\\"; // for debug
422   if (!path.IsEmpty())
423   {
424     const unsigned rootPrefixSize = NName::GetRootPrefixSize(path);
425     if (rootPrefixSize == 0 && path[0] != '\\')
426     {
427       int iconIndex = -1;
428       UString name_Computer = RootFolder_GetName_Computer(iconIndex);
429       name_Computer.Add_PathSepar();
430       if (path == name_Computer
431           || path == L"\\\\?\\")
432         item.iImage = iconIndex;
433       else
434       {
435         UString name = RootFolder_GetName_Network(iconIndex);
436         name.Add_PathSepar();
437         if (path == name)
438           item.iImage = iconIndex;
439       }
440     }
441 
442     if (item.iImage < 0)
443     {
444       if (rootPrefixSize == 0 || rootPrefixSize == path.Len())
445       {
446         DWORD attrib = FILE_ATTRIBUTE_DIRECTORY;
447         CFileInfo info;
448         if (info.Find(us2fs(path)))
449           attrib = info.Attrib;
450         NName::If_IsSuperPath_RemoveSuperPrefix(path);
451         item.iImage = GetRealIconIndex_for_DirPath(us2fs(path), attrib);
452       }
453       else if (rootPrefixSize == NName::kDevicePathPrefixSize
454           && NName::IsDevicePath(us2fs(path.Left(path.Len() - 1))))
455       {
456         if (path.IsPrefixedBy_Ascii_NoCase("\\\\.\\"))
457           path.DeleteFrontal(4);
458         if (path.Len() > 3) // is not "c:\\"
459         {
460           // PhysicalDrive
461           if (path.Back() == '\\')
462             path.DeleteBack();
463         }
464         item.iImage = Shell_GetFileInfo_SysIconIndex_for_Path(us2fs(path), FILE_ATTRIBUTE_ARCHIVE);
465       }
466       else
467       {
468         if (path.Back() == '\\')
469           path.DeleteBack();
470         bool need_Fs_Check = true;
471         bool is_File = false;
472         if (!_parentFolders.IsEmpty())
473         {
474           const CFolderLink &link = _parentFolders.Back();
475           if (link.VirtualPath == path)
476           {
477             is_File = true;
478             if (_parentFolders.Size() != 1)
479               need_Fs_Check = false;
480           }
481           else
482             need_Fs_Check = false;
483         }
484         if (need_Fs_Check)
485         {
486           CFileInfo info;
487           const bool finded = info.Find(us2fs(path));
488           DWORD attrib = FILE_ATTRIBUTE_DIRECTORY;
489           if (finded)
490             attrib = info.Attrib;
491           item.iImage = Shell_GetFileInfo_SysIconIndex_for_Path(us2fs(path), attrib);
492         }
493         if (item.iImage <= 0 && is_File)
494         {
495           int dotPos = Find_FileExtension_DotPos_in_path(path);
496           if (dotPos < 0)
497             dotPos = (int)path.Len();
498           item.iImage = g_Ext_to_Icon_Map.GetIconIndex(FILE_ATTRIBUTE_ARCHIVE, path.Ptr(dotPos));
499         }
500       }
501     }
502   }
503 
504   if (item.iImage < 0)
505     item.iImage = g_Ext_to_Icon_Map.GetIconIndex_DIR();
506   // if (item.iImage < 0) item.iImage = 0;
507   // item.iImage = -1; // for debug
508   if (item.iImage >= 0)
509   {
510     item.iSelectedImage = item.iImage;
511     item.mask |= (CBEIF_IMAGE | CBEIF_SELECTEDIMAGE);
512   }
513   item.iItem = -1;
514   _headerComboBox.SetItem(&item);
515 
516   #endif
517 
518   RefreshTitle();
519 }
520 
521 #ifndef UNDER_CE
OnNotifyComboBoxEnter(const UString & s)522 LRESULT CPanel::OnNotifyComboBoxEnter(const UString &s)
523 {
524   if (BindToPathAndRefresh(GetUnicodeString(s)) == S_OK)
525   {
526     PostMsg(kSetFocusToListView);
527     return TRUE;
528   }
529   return FALSE;
530 }
531 
OnNotifyComboBoxEndEdit(PNMCBEENDEDITW info,LRESULT & result)532 bool CPanel::OnNotifyComboBoxEndEdit(PNMCBEENDEDITW info, LRESULT &result)
533 {
534   if (info->iWhy == CBENF_ESCAPE)
535   {
536     _headerComboBox.SetText(_currentFolderPrefix);
537     PostMsg(kSetFocusToListView);
538     result = FALSE;
539     return true;
540   }
541 
542   /*
543   if (info->iWhy == CBENF_DROPDOWN)
544   {
545     result = FALSE;
546     return true;
547   }
548   */
549 
550   if (info->iWhy == CBENF_RETURN)
551   {
552     // When we use Edit control and press Enter.
553     UString s;
554     _headerComboBox.GetText(s);
555     result = OnNotifyComboBoxEnter(s);
556     return true;
557   }
558   return false;
559 }
560 #endif
561 
562 #ifndef _UNICODE
OnNotifyComboBoxEndEdit(PNMCBEENDEDIT info,LRESULT & result)563 bool CPanel::OnNotifyComboBoxEndEdit(PNMCBEENDEDIT info, LRESULT &result)
564 {
565   if (info->iWhy == CBENF_ESCAPE)
566   {
567     _headerComboBox.SetText(_currentFolderPrefix);
568     PostMsg(kSetFocusToListView);
569     result = FALSE;
570     return true;
571   }
572   /*
573   if (info->iWhy == CBENF_DROPDOWN)
574   {
575     result = FALSE;
576     return true;
577   }
578   */
579 
580   if (info->iWhy == CBENF_RETURN)
581   {
582     UString s;
583     _headerComboBox.GetText(s);
584     // GetUnicodeString(info->szText)
585     result = OnNotifyComboBoxEnter(s);
586     return true;
587   }
588   return false;
589 }
590 #endif
591 
AddComboBoxItem(const UString & name,int iconIndex,unsigned indent,bool addToList)592 void CPanel::AddComboBoxItem(const UString &name, int iconIndex, unsigned indent, bool addToList)
593 {
594   #ifdef UNDER_CE
595 
596   UString s;
597   iconIndex = iconIndex;
598   for (unsigned i = 0; i < indent; i++)
599     s += "  ";
600   _headerComboBox.AddString(s + name);
601 
602   #else
603 
604   COMBOBOXEXITEMW item;
605   item.mask = CBEIF_TEXT | CBEIF_INDENT;
606   if (iconIndex < 0)
607     iconIndex = g_Ext_to_Icon_Map.GetIconIndex_DIR();
608   item.iSelectedImage = item.iImage = iconIndex;
609   if (iconIndex >= 0)
610     item.mask |= (CBEIF_IMAGE | CBEIF_SELECTEDIMAGE);
611   item.iItem = -1;
612   item.iIndent = (int)indent;
613   item.pszText = name.Ptr_non_const();
614   _headerComboBox.InsertItem(&item);
615 
616   #endif
617 
618   if (addToList)
619   {
620     UString s = name;
621     s.Add_PathSepar();
622     ComboBoxPaths.Add(s);
623   }
624 }
625 
626 
OnComboBoxCommand(UINT code,LPARAM,LRESULT & result)627 bool CPanel::OnComboBoxCommand(UINT code, LPARAM /* param */, LRESULT &result)
628 {
629   result = FALSE;
630   switch (code)
631   {
632     case CBN_DROPDOWN:
633     {
634       ComboBoxPaths.Clear();
635       _headerComboBox.ResetContent();
636 
637       UString sumPath;
638       UStringVector pathParts;
639       unsigned indent = 0;
640       {
641         UString path = _currentFolderPrefix;
642         // path = L"\\\\.\\y:\\"; // for debug
643         UString prefix0;
644         if (path.IsPrefixedBy_Ascii_NoCase("\\\\"))
645         {
646           const int separ = FindCharPosInString(path.Ptr(2), '\\');
647           if (separ > 0
648             && (separ > 1 || path[2] != '.')) // "\\\\.\\" will be processed later
649           {
650             const UString s = path.Left(2 + separ);
651             prefix0 = s;
652             prefix0.Add_PathSepar();
653             AddComboBoxItem(s,
654                 GetRealIconIndex_for_DirPath(us2fs(prefix0), FILE_ATTRIBUTE_DIRECTORY),
655                 indent++,
656                 false); // addToList
657             ComboBoxPaths.Add(prefix0);
658           }
659         }
660 
661         unsigned rootPrefixSize = NName::GetRootPrefixSize(path);
662 
663         sumPath = path;
664 
665         if (rootPrefixSize <= prefix0.Len())
666         {
667           rootPrefixSize = prefix0.Len();
668           sumPath.DeleteFrom(rootPrefixSize);
669         }
670         else
671         {
672           // rootPrefixSize > prefix0.Len()
673           sumPath.DeleteFrom(rootPrefixSize);
674 
675           CFileInfo info;
676           DWORD attrib = FILE_ATTRIBUTE_DIRECTORY;
677           if (info.Find(us2fs(sumPath)) && info.IsDir())
678             attrib = info.Attrib;
679           UString s = sumPath.Ptr(prefix0.Len());
680           if (!s.IsEmpty())
681           {
682             const wchar_t c = s.Back();
683             if (IS_PATH_SEPAR(c))
684               s.DeleteBack();
685           }
686           UString path_for_icon = sumPath;
687           NName::If_IsSuperPath_RemoveSuperPrefix(path_for_icon);
688 
689           AddComboBoxItem(s,
690               GetRealIconIndex_for_DirPath(us2fs(path_for_icon), attrib),
691               indent++,
692               false); // addToList
693           ComboBoxPaths.Add(sumPath);
694         }
695 
696         path.DeleteFrontal(rootPrefixSize);
697         SplitPathToParts(path, pathParts);
698       }
699 
700       // it's expected that pathParts.Back() is empty, because _currentFolderPrefix has PathSeparator.
701       unsigned next_Arc_index = 0;
702       int iconIndex_Computer;
703       const UString name_Computer = RootFolder_GetName_Computer(iconIndex_Computer);
704 
705       // const bool is_devicePrefix = (sumPath == L"\\\\.\\");
706 
707       if (pathParts.Size() > 1)
708       if (!sumPath.IsEmpty()
709           || pathParts.Size() != 2
710           || pathParts[0] != name_Computer)
711       for (unsigned i = 0; i + 1 < pathParts.Size(); i++)
712       {
713         UString name = pathParts[i];
714         sumPath += name;
715 
716         bool isRootDir_inLink = false;
717         if (next_Arc_index < _parentFolders.Size())
718         {
719           const CFolderLink &link = _parentFolders[next_Arc_index];
720           if (link.VirtualPath == sumPath)
721           {
722             isRootDir_inLink = true;
723             next_Arc_index++;
724           }
725         }
726 
727         int iconIndex = -1;
728         DWORD attrib = isRootDir_inLink ?
729             FILE_ATTRIBUTE_ARCHIVE:
730             FILE_ATTRIBUTE_DIRECTORY;
731         if (next_Arc_index == 0
732             || (next_Arc_index == 1 && isRootDir_inLink))
733         {
734           if (i == 0 && NName::IsDevicePath(us2fs(sumPath)))
735           {
736             UString path = name;
737             path.Add_PathSepar();
738             attrib = FILE_ATTRIBUTE_ARCHIVE;
739               // FILE_ATTRIBUTE_DIRECTORY;
740           }
741           else
742           {
743             CFileInfo info;
744             if (info.Find(us2fs(sumPath)))
745               attrib = info.Attrib;
746           }
747           iconIndex = Shell_GetFileInfo_SysIconIndex_for_Path(us2fs(sumPath), attrib);
748         }
749 
750         if (iconIndex < 0)
751           iconIndex = g_Ext_to_Icon_Map.GetIconIndex(attrib, name);
752         // iconIndex = -1; // for debug
753         if (iconIndex < 0 && isRootDir_inLink)
754           iconIndex = 0; // default file
755 
756         sumPath.Add_PathSepar();
757 
758         ComboBoxPaths.Add(sumPath);
759         if (name.IsEmpty())
760           name.Add_PathSepar();
761         AddComboBoxItem(name, iconIndex, indent++,
762             false); // addToList
763       }
764 
765 #ifndef UNDER_CE
766 
767       {
768         int iconIndex;
769         const UString name = RootFolder_GetName_Documents(iconIndex);
770         // iconIndex = -1; // for debug
771         AddComboBoxItem(name, iconIndex, 0, true);
772       }
773       AddComboBoxItem(name_Computer, iconIndex_Computer, 0, true);
774       {
775         FStringVector driveStrings;
776         MyGetLogicalDriveStrings(driveStrings);
777         FOR_VECTOR (i, driveStrings)
778         {
779           FString s = driveStrings[i];
780           ComboBoxPaths.Add(fs2us(s));
781           int iconIndex2 = GetRealIconIndex_for_DirPath(s, FILE_ATTRIBUTE_DIRECTORY);
782           if (!s.IsEmpty())
783           {
784             const FChar c = s.Back();
785             if (IS_PATH_SEPAR(c))
786               s.DeleteBack();
787           }
788           // iconIndex2 = -1; // for debug
789           AddComboBoxItem(fs2us(s), iconIndex2, 1, false);
790         }
791       }
792       {
793         int iconIndex;
794         const UString name = RootFolder_GetName_Network(iconIndex);
795         AddComboBoxItem(name, iconIndex, 0, true);
796       }
797 
798 #endif
799 
800       return false;
801     }
802 
803     case CBN_SELENDOK:
804     {
805       int index = _headerComboBox.GetCurSel();
806       if (index >= 0)
807       {
808         const UString path = ComboBoxPaths[index];
809         _headerComboBox.SetCurSel(-1);
810         // _headerComboBox.SetText(pass); // it's fix for selecting by mouse.
811         if (BindToPathAndRefresh(path) == S_OK)
812         {
813           PostMsg(kSetFocusToListView);
814           #ifdef UNDER_CE
815           PostMsg(kRefresh_HeaderComboBox);
816           #endif
817           return true;
818         }
819       }
820       return false;
821     }
822     /*
823     case CBN_CLOSEUP:
824     {
825       LoadFullPathAndShow();
826       true;
827 
828     }
829     case CBN_SELCHANGE:
830     {
831       // LoadFullPathAndShow();
832       return true;
833     }
834     */
835   }
836   return false;
837 }
838 
OnNotifyComboBox(LPNMHDR NON_CE_VAR (header),LRESULT & NON_CE_VAR (result))839 bool CPanel::OnNotifyComboBox(LPNMHDR NON_CE_VAR(header), LRESULT & NON_CE_VAR(result))
840 {
841   #ifndef UNDER_CE
842   switch (header->code)
843   {
844     case CBEN_BEGINEDIT:
845     {
846       _lastFocusedIsList = false;
847       _panelCallback->PanelWasFocused();
848       break;
849     }
850     #ifndef _UNICODE
851     case CBEN_ENDEDIT:
852     {
853       return OnNotifyComboBoxEndEdit((PNMCBEENDEDIT)header, result);
854     }
855     #endif
856     case CBEN_ENDEDITW:
857     {
858       return OnNotifyComboBoxEndEdit((PNMCBEENDEDITW)header, result);
859     }
860   }
861   #endif
862   return false;
863 }
864 
865 
FoldersHistory()866 void CPanel::FoldersHistory()
867 {
868   CListViewDialog listViewDialog;
869   listViewDialog.DeleteIsAllowed = true;
870   listViewDialog.SelectFirst = true;
871   LangString(IDS_FOLDERS_HISTORY, listViewDialog.Title);
872   _appState->FolderHistory.GetList(listViewDialog.Strings);
873   if (listViewDialog.Create(GetParent()) != IDOK)
874     return;
875   UString selectString;
876   if (listViewDialog.StringsWereChanged)
877   {
878     _appState->FolderHistory.RemoveAll();
879     for (int i = (int)listViewDialog.Strings.Size() - 1; i >= 0; i--)
880       _appState->FolderHistory.AddString(listViewDialog.Strings[i]);
881     if (listViewDialog.FocusedItemIndex >= 0)
882       selectString = listViewDialog.Strings[listViewDialog.FocusedItemIndex];
883   }
884   else
885   {
886     if (listViewDialog.FocusedItemIndex >= 0)
887       selectString = listViewDialog.Strings[listViewDialog.FocusedItemIndex];
888   }
889   if (listViewDialog.FocusedItemIndex >= 0)
890     BindToPathAndRefresh(selectString);
891 }
892 
893 
GetParentDirPrefix() const894 UString CPanel::GetParentDirPrefix() const
895 {
896   UString s;
897   if (!_currentFolderPrefix.IsEmpty())
898   {
899     wchar_t c = _currentFolderPrefix.Back();
900     if (IS_PATH_SEPAR(c) || c == ':')
901     {
902       s = _currentFolderPrefix;
903       s.DeleteBack();
904       if (s != L"\\\\." &&
905           s != L"\\\\?")
906       {
907         int pos = s.ReverseFind_PathSepar();
908         if (pos >= 0)
909           s.DeleteFrom((unsigned)(pos + 1));
910       }
911     }
912   }
913   return s;
914 }
915 
916 
OpenParentFolder()917 void CPanel::OpenParentFolder()
918 {
919   LoadFullPath(); // Maybe we don't need it ??
920 
921   UString parentFolderPrefix;
922   UString focusedName;
923 
924   if (!_currentFolderPrefix.IsEmpty())
925   {
926     wchar_t c = _currentFolderPrefix.Back();
927     if (IS_PATH_SEPAR(c) || c == ':')
928     {
929       focusedName = _currentFolderPrefix;
930       focusedName.DeleteBack();
931       /*
932       if (c == ':' && !focusedName.IsEmpty() && IS_PATH_SEPAR(focusedName.Back()))
933       {
934         focusedName.DeleteBack();
935       }
936       else
937       */
938       if (focusedName != L"\\\\." &&
939           focusedName != L"\\\\?")
940       {
941         const int pos = focusedName.ReverseFind_PathSepar();
942         if (pos >= 0)
943         {
944           parentFolderPrefix = focusedName;
945           parentFolderPrefix.DeleteFrom((unsigned)(pos + 1));
946           focusedName.DeleteFrontal((unsigned)(pos + 1));
947         }
948       }
949     }
950   }
951 
952   CDisableTimerProcessing disableTimerProcessing(*this);
953   CDisableNotify disableNotify(*this);
954 
955   CMyComPtr<IFolderFolder> newFolder;
956   _folder->BindToParentFolder(&newFolder);
957 
958   // newFolder.Release(); // for test
959 
960   if (newFolder)
961     SetNewFolder(newFolder);
962   else
963   {
964     bool needSetFolder = true;
965     if (!_parentFolders.IsEmpty())
966     {
967       {
968         const CFolderLink &link = _parentFolders.Back();
969         parentFolderPrefix = link.ParentFolderPath;
970         focusedName = link.RelPath;
971       }
972       CloseOneLevel();
973       needSetFolder = (!_folder);
974     }
975 
976     if (needSetFolder)
977     {
978       {
979         COpenResult openRes;
980         BindToPath(parentFolderPrefix, UString(), openRes);
981       }
982     }
983   }
984 
985   CSelectedState state;
986   state.FocusedName = focusedName;
987   state.FocusedName_Defined = true;
988   /*
989   if (!focusedName.IsEmpty())
990     state.SelectedNames.Add(focusedName);
991   */
992   LoadFullPath();
993   // ::SetCurrentDirectory(::_currentFolderPrefix);
994   RefreshListCtrl(state);
995   // _listView.EnsureVisible(_listView.GetFocusedItem(), false);
996 }
997 
998 
CloseOneLevel()999 void CPanel::CloseOneLevel()
1000 {
1001   ReleaseFolder();
1002   _library.Free();
1003   {
1004     CFolderLink &link = _parentFolders.Back();
1005     if (link.ParentFolder)
1006       SetNewFolder(link.ParentFolder);
1007     _library.Attach(link.Library.Detach());
1008   }
1009   if (_parentFolders.Size() > 1)
1010     OpenParentArchiveFolder();
1011   _parentFolders.DeleteBack();
1012   if (_parentFolders.IsEmpty())
1013     _flatMode = _flatModeForDisk;
1014 }
1015 
CloseOpenFolders()1016 void CPanel::CloseOpenFolders()
1017 {
1018   while (!_parentFolders.IsEmpty())
1019     CloseOneLevel();
1020   _flatMode = _flatModeForDisk;
1021   ReleaseFolder();
1022   _library.Free();
1023 }
1024 
OpenRootFolder()1025 void CPanel::OpenRootFolder()
1026 {
1027   CDisableTimerProcessing disableTimerProcessing(*this);
1028   CDisableNotify disableNotify(*this);
1029   _parentFolders.Clear();
1030   SetToRootFolder();
1031   RefreshListCtrl();
1032   // ::SetCurrentDirectory(::_currentFolderPrefix);
1033   /*
1034   BeforeChangeFolder();
1035   _currentFolderPrefix.Empty();
1036   AfterChangeFolder();
1037   SetCurrentPathText();
1038   RefreshListCtrl(UString(), 0, UStringVector());
1039   _listView.EnsureVisible(_listView.GetFocusedItem(), false);
1040   */
1041 }
1042 
OpenDrivesFolder()1043 void CPanel::OpenDrivesFolder()
1044 {
1045   CloseOpenFolders();
1046   #ifdef UNDER_CE
1047   NFsFolder::CFSFolder *folderSpec = new NFsFolder::CFSFolder;
1048   SetNewFolder(folderSpec);
1049   folderSpec->InitToRoot();
1050   #else
1051   CFSDrives *folderSpec = new CFSDrives;
1052   SetNewFolder(folderSpec);
1053   folderSpec->Init();
1054   #endif
1055   RefreshListCtrl();
1056 }
1057 
OpenFolder(unsigned index)1058 void CPanel::OpenFolder(unsigned index)
1059 {
1060   if (index == kParentIndex)
1061   {
1062     OpenParentFolder();
1063     return;
1064   }
1065   CMyComPtr<IFolderFolder> newFolder;
1066   const HRESULT res = _folder->BindToFolder((unsigned)index, &newFolder);
1067   if (res != 0)
1068   {
1069     MessageBox_Error_HRESULT(res);
1070     return;
1071   }
1072   if (!newFolder)
1073     return;
1074   SetNewFolder(newFolder);
1075   LoadFullPath();
1076   RefreshListCtrl();
1077   // 17.02: fixed : now we don't select first item
1078   // _listView.SetItemState_Selected(_listView.GetFocusedItem());
1079   _listView.EnsureVisible(_listView.GetFocusedItem(), false);
1080 }
1081 
OpenAltStreams()1082 void CPanel::OpenAltStreams()
1083 {
1084   CRecordVector<UInt32> indices;
1085   Get_ItemIndices_Operated(indices);
1086   Int32 realIndex = -1;
1087   if (indices.Size() > 1)
1088     return;
1089   if (indices.Size() == 1)
1090     realIndex = (Int32)indices[0];
1091 
1092   if (_folderAltStreams)
1093   {
1094     CMyComPtr<IFolderFolder> newFolder;
1095     _folderAltStreams->BindToAltStreams((UInt32)realIndex, &newFolder);
1096     if (newFolder)
1097     {
1098       CDisableTimerProcessing disableTimerProcessing(*this);
1099       CDisableNotify disableNotify(*this);
1100       SetNewFolder(newFolder);
1101       RefreshListCtrl();
1102       return;
1103     }
1104     return;
1105   }
1106 
1107   #if defined(_WIN32) && !defined(UNDER_CE)
1108   UString path;
1109   if (realIndex >= 0)
1110     path = GetItemFullPath((UInt32)realIndex);
1111   else
1112   {
1113     path = GetFsPath();
1114     if (!NName::IsDriveRootPath_SuperAllowed(us2fs(path)))
1115       if (!path.IsEmpty() && IS_PATH_SEPAR(path.Back()))
1116         path.DeleteBack();
1117   }
1118 
1119   path.Add_Colon();
1120   BindToPathAndRefresh(path);
1121   #endif
1122 }
1123