1 // App.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "resource.h"
6 #include "OverwriteDialogRes.h"
7 
8 #include "../../../Windows/FileName.h"
9 #include "../../../Windows/PropVariantConv.h"
10 
11 /*
12 #include "Windows/COM.h"
13 #include "Windows/Error.h"
14 #include "Windows/FileDir.h"
15 
16 #include "Windows/PropVariant.h"
17 #include "Windows/Thread.h"
18 */
19 
20 #include "App.h"
21 #include "CopyDialog.h"
22 #include "ExtractCallback.h"
23 #include "FormatUtils.h"
24 #include "IFolder.h"
25 #include "LangUtils.h"
26 #include "MyLoadMenu.h"
27 #include "RegistryUtils.h"
28 #include "ViewSettings.h"
29 
30 #include "PropertyNameRes.h"
31 
32 using namespace NWindows;
33 using namespace NFile;
34 using namespace NDir;
35 using namespace NFind;
36 using namespace NName;
37 
38 extern DWORD g_ComCtl32Version;
39 extern HINSTANCE g_hInstance;
40 
41 #define kTempDirPrefix FTEXT("7zE")
42 
OnTab()43 void CPanelCallbackImp::OnTab()
44 {
45   if (g_App.NumPanels != 1)
46     _app->Panels[1 - _index].SetFocusToList();
47   _app->RefreshTitle();
48 }
49 
SetFocusToPath(unsigned index)50 void CPanelCallbackImp::SetFocusToPath(unsigned index)
51 {
52   int newPanelIndex = index;
53   if (g_App.NumPanels == 1)
54     newPanelIndex = g_App.LastFocusedPanel;
55   _app->RefreshTitle();
56   _app->Panels[newPanelIndex]._headerComboBox.SetFocus();
57   _app->Panels[newPanelIndex]._headerComboBox.ShowDropDown();
58 }
59 
60 
OnCopy(bool move,bool copyToSame)61 void CPanelCallbackImp::OnCopy(bool move, bool copyToSame) { _app->OnCopy(move, copyToSame, _index); }
OnSetSameFolder()62 void CPanelCallbackImp::OnSetSameFolder() { _app->OnSetSameFolder(_index); }
OnSetSubFolder()63 void CPanelCallbackImp::OnSetSubFolder()  { _app->OnSetSubFolder(_index); }
PanelWasFocused()64 void CPanelCallbackImp::PanelWasFocused() { _app->SetFocusedPanel(_index); _app->RefreshTitlePanel(_index); }
DragBegin()65 void CPanelCallbackImp::DragBegin() { _app->DragBegin(_index); }
DragEnd()66 void CPanelCallbackImp::DragEnd() { _app->DragEnd(); }
RefreshTitle(bool always)67 void CPanelCallbackImp::RefreshTitle(bool always) { _app->RefreshTitlePanel(_index, always); }
68 
ReloadLang()69 void CApp::ReloadLang()
70 {
71   LangString(IDS_N_SELECTED_ITEMS, LangString_N_SELECTED_ITEMS);
72 }
73 
SetListSettings()74 void CApp::SetListSettings()
75 {
76   CFmSettings st;
77   st.Load();
78 
79   ShowSystemMenu = st.ShowSystemMenu;
80 
81   DWORD extendedStyle = LVS_EX_HEADERDRAGDROP;
82   if (st.FullRow)
83     extendedStyle |= LVS_EX_FULLROWSELECT;
84   if (st.ShowGrid)
85     extendedStyle |= LVS_EX_GRIDLINES;
86 
87   if (st.SingleClick)
88   {
89     extendedStyle |= LVS_EX_ONECLICKACTIVATE | LVS_EX_TRACKSELECT;
90     /*
91     if (ReadUnderline())
92       extendedStyle |= LVS_EX_UNDERLINEHOT;
93     */
94   }
95 
96   for (unsigned i = 0; i < kNumPanelsMax; i++)
97   {
98     CPanel &panel = Panels[i];
99     panel._mySelectMode = st.AlternativeSelection;
100     panel._showDots = st.ShowDots;
101     panel._showRealFileIcons = st.ShowRealFileIcons;
102     panel._exStyle = extendedStyle;
103 
104     DWORD style = (DWORD)panel._listView.GetStyle();
105     if (st.AlternativeSelection)
106       style |= LVS_SINGLESEL;
107     else
108       style &= ~LVS_SINGLESEL;
109     panel._listView.SetStyle(style);
110     panel.SetExtendedStyle();
111   }
112 }
113 
114 #ifndef ILC_COLOR32
115 #define ILC_COLOR32 0x0020
116 #endif
117 
CreateOnePanel(int panelIndex,const UString & mainPath,const UString & arcFormat,bool needOpenArc,bool & archiveIsOpened,bool & encrypted)118 HRESULT CApp::CreateOnePanel(int panelIndex, const UString &mainPath, const UString &arcFormat,
119     bool needOpenArc,
120     bool &archiveIsOpened, bool &encrypted)
121 {
122   if (Panels[panelIndex].PanelCreated)
123     return S_OK;
124 
125   m_PanelCallbackImp[panelIndex].Init(this, panelIndex);
126 
127   UString path;
128   if (mainPath.IsEmpty())
129   {
130     if (!::ReadPanelPath(panelIndex, path))
131       path.Empty();
132   }
133   else
134     path = mainPath;
135 
136   int id = 1000 + 100 * panelIndex;
137 
138   return Panels[panelIndex].Create(_window, _window,
139       id, path, arcFormat, &m_PanelCallbackImp[panelIndex], &AppState,
140       needOpenArc,
141       archiveIsOpened, encrypted);
142 }
143 
144 
CreateToolbar(HWND parent,NControl::CImageList & imageList,NControl::CToolBar & toolBar,bool largeButtons)145 static void CreateToolbar(HWND parent,
146     NControl::CImageList &imageList,
147     NControl::CToolBar &toolBar,
148     bool largeButtons)
149 {
150   toolBar.Attach(::CreateWindowEx(0, TOOLBARCLASSNAME, NULL, 0
151       | WS_CHILD
152       | WS_VISIBLE
153       | TBSTYLE_FLAT
154       | TBSTYLE_TOOLTIPS
155       | TBSTYLE_WRAPABLE
156       // | TBSTYLE_AUTOSIZE
157       // | CCS_NORESIZE
158       #ifdef UNDER_CE
159       | CCS_NODIVIDER
160       | CCS_NOPARENTALIGN
161       #endif
162       ,0,0,0,0, parent, NULL, g_hInstance, NULL));
163 
164   // TB_BUTTONSTRUCTSIZE message, which is required for
165   // backward compatibility.
166   toolBar.ButtonStructSize();
167 
168   imageList.Create(
169       largeButtons ? 48: 24,
170       largeButtons ? 36: 24,
171       ILC_MASK | ILC_COLOR32, 0, 0);
172   toolBar.SetImageList(0, imageList);
173 }
174 
175 
176 struct CButtonInfo
177 {
178   int CommandID;
179   UINT BitmapResID;
180   UINT Bitmap2ResID;
181   UINT StringResID;
182 
GetTextCButtonInfo183   UString GetText() const { return LangString(StringResID); }
184 };
185 
186 static const CButtonInfo g_StandardButtons[] =
187 {
188   { IDM_COPY_TO,    IDB_COPY,   IDB_COPY2,   IDS_BUTTON_COPY },
189   { IDM_MOVE_TO,    IDB_MOVE,   IDB_MOVE2,   IDS_BUTTON_MOVE },
190   { IDM_DELETE,     IDB_DELETE, IDB_DELETE2, IDS_BUTTON_DELETE } ,
191   { IDM_PROPERTIES, IDB_INFO,   IDB_INFO2,   IDS_BUTTON_INFO }
192 };
193 
194 static const CButtonInfo g_ArchiveButtons[] =
195 {
196   { kMenuCmdID_Toolbar_Add,     IDB_ADD,     IDB_ADD2,     IDS_ADD },
197   { kMenuCmdID_Toolbar_Extract, IDB_EXTRACT, IDB_EXTRACT2, IDS_EXTRACT },
198   { kMenuCmdID_Toolbar_Test,    IDB_TEST,    IDB_TEST2,    IDS_TEST }
199 };
200 
SetButtonText(int commandID,const CButtonInfo * buttons,unsigned numButtons,UString & s)201 static bool SetButtonText(int commandID, const CButtonInfo *buttons, unsigned numButtons, UString &s)
202 {
203   for (unsigned i = 0; i < numButtons; i++)
204   {
205     const CButtonInfo &b = buttons[i];
206     if (b.CommandID == commandID)
207     {
208       s = b.GetText();
209       return true;
210     }
211   }
212   return false;
213 }
214 
SetButtonText(int commandID,UString & s)215 static void SetButtonText(int commandID, UString &s)
216 {
217   if (SetButtonText(commandID, g_StandardButtons, ARRAY_SIZE(g_StandardButtons), s))
218     return;
219   SetButtonText(commandID, g_ArchiveButtons, ARRAY_SIZE(g_ArchiveButtons), s);
220 }
221 
AddButton(NControl::CImageList & imageList,NControl::CToolBar & toolBar,const CButtonInfo & butInfo,bool showText,bool large)222 static void AddButton(
223     NControl::CImageList &imageList,
224     NControl::CToolBar &toolBar,
225     const CButtonInfo &butInfo, bool showText, bool large)
226 {
227   TBBUTTON but;
228   but.iBitmap = 0;
229   but.idCommand = butInfo.CommandID;
230   but.fsState = TBSTATE_ENABLED;
231   but.fsStyle = TBSTYLE_BUTTON;
232   but.dwData = 0;
233 
234   UString s = butInfo.GetText();
235   but.iString = 0;
236   if (showText)
237     but.iString = (INT_PTR)(LPCWSTR)s;
238 
239   but.iBitmap = imageList.GetImageCount();
240   HBITMAP b = ::LoadBitmap(g_hInstance,
241       large ?
242       MAKEINTRESOURCE(butInfo.BitmapResID):
243       MAKEINTRESOURCE(butInfo.Bitmap2ResID));
244   if (b != 0)
245   {
246     imageList.AddMasked(b, RGB(255, 0, 255));
247     ::DeleteObject(b);
248   }
249   #ifdef _UNICODE
250   toolBar.AddButton(1, &but);
251   #else
252   toolBar.AddButtonW(1, &but);
253   #endif
254 }
255 
ReloadToolbars()256 void CApp::ReloadToolbars()
257 {
258   _buttonsImageList.Destroy();
259   _toolBar.Destroy();
260 
261 
262   if (ShowArchiveToolbar || ShowStandardToolbar)
263   {
264     CreateToolbar(_window, _buttonsImageList, _toolBar, LargeButtons);
265     unsigned i;
266     if (ShowArchiveToolbar)
267       for (i = 0; i < ARRAY_SIZE(g_ArchiveButtons); i++)
268         AddButton(_buttonsImageList, _toolBar, g_ArchiveButtons[i], ShowButtonsLables, LargeButtons);
269     if (ShowStandardToolbar)
270       for (i = 0; i < ARRAY_SIZE(g_StandardButtons); i++)
271         AddButton(_buttonsImageList, _toolBar, g_StandardButtons[i], ShowButtonsLables, LargeButtons);
272 
273     _toolBar.AutoSize();
274   }
275 }
276 
SaveToolbarChanges()277 void CApp::SaveToolbarChanges()
278 {
279   SaveToolbar();
280   ReloadToolbars();
281   MoveSubWindows();
282 }
283 
284 
Create(HWND hwnd,const UString & mainPath,const UString & arcFormat,int xSizes[2],bool needOpenArc,bool & archiveIsOpened,bool & encrypted)285 HRESULT CApp::Create(HWND hwnd, const UString &mainPath, const UString &arcFormat, int xSizes[2], bool needOpenArc, bool &archiveIsOpened, bool &encrypted)
286 {
287   _window.Attach(hwnd);
288 
289   #ifdef UNDER_CE
290   _commandBar.Create(g_hInstance, hwnd, 1);
291   #endif
292 
293   MyLoadMenu();
294 
295   #ifdef UNDER_CE
296   _commandBar.AutoSize();
297   #endif
298 
299   ReadToolbar();
300   ReloadToolbars();
301 
302   unsigned i;
303   for (i = 0; i < kNumPanelsMax; i++)
304     Panels[i].PanelCreated = false;
305 
306   AppState.Read();
307 
308   SetListSettings();
309 
310   if (LastFocusedPanel >= kNumPanelsMax)
311     LastFocusedPanel = 0;
312   // ShowDeletedFiles = Read_ShowDeleted();
313 
314   CListMode listMode;
315   listMode.Read();
316 
317   for (i = 0; i < kNumPanelsMax; i++)
318   {
319     CPanel &panel = Panels[i];
320     panel._ListViewMode = listMode.Panels[i];
321     panel._xSize = xSizes[i];
322     panel._flatModeForArc = ReadFlatView(i);
323   }
324 
325   for (i = 0; i < kNumPanelsMax; i++)
326   {
327     unsigned panelIndex = i;
328     if (needOpenArc && LastFocusedPanel == 1)
329       panelIndex = 1 - i;
330 
331     bool isMainPanel = (panelIndex == LastFocusedPanel);
332 
333     if (NumPanels > 1 || isMainPanel)
334     {
335       if (NumPanels == 1)
336         Panels[panelIndex]._xSize = xSizes[0] + xSizes[1];
337       bool archiveIsOpened2 = false;
338       bool encrypted2 = false;
339       UString path;
340       if (isMainPanel)
341         path = mainPath;
342 
343       RINOK(CreateOnePanel(panelIndex, path, arcFormat,
344           isMainPanel && needOpenArc,
345           archiveIsOpened2, encrypted2));
346 
347       if (isMainPanel)
348       {
349         archiveIsOpened = archiveIsOpened2;
350         encrypted = encrypted2;
351         if (needOpenArc && !archiveIsOpened2)
352           return S_OK;
353       }
354     }
355   }
356 
357   SetFocusedPanel(LastFocusedPanel);
358   Panels[LastFocusedPanel].SetFocusToList();
359   return S_OK;
360 }
361 
362 
SwitchOnOffOnePanel()363 HRESULT CApp::SwitchOnOffOnePanel()
364 {
365   if (NumPanels == 1)
366   {
367     NumPanels++;
368     bool archiveIsOpened, encrypted;
369     RINOK(CreateOnePanel(1 - LastFocusedPanel, UString(), UString(),
370         false, // needOpenArc
371         archiveIsOpened, encrypted));
372     Panels[1 - LastFocusedPanel].Enable(true);
373     Panels[1 - LastFocusedPanel].Show(SW_SHOWNORMAL);
374   }
375   else
376   {
377     NumPanels--;
378     Panels[1 - LastFocusedPanel].Enable(false);
379     Panels[1 - LastFocusedPanel].Show(SW_HIDE);
380   }
381   MoveSubWindows();
382   return S_OK;
383 }
384 
Save()385 void CApp::Save()
386 {
387   AppState.Save();
388   CListMode listMode;
389 
390   for (unsigned i = 0; i < kNumPanelsMax; i++)
391   {
392     const CPanel &panel = Panels[i];
393     UString path;
394     if (panel._parentFolders.IsEmpty())
395       path = panel._currentFolderPrefix;
396     else
397       path = panel._parentFolders[0].ParentFolderPath;
398       // GetFolderPath(panel._parentFolders[0].ParentFolder);
399     SavePanelPath(i, path);
400     listMode.Panels[i] = panel.GetListViewMode();
401     SaveFlatView(i, panel._flatModeForArc);
402   }
403 
404   listMode.Save();
405   // Save_ShowDeleted(ShowDeletedFiles);
406 }
407 
Release()408 void CApp::Release()
409 {
410   // It's for unloading COM dll's: don't change it.
411   for (unsigned i = 0; i < kNumPanelsMax; i++)
412     Panels[i].Release();
413 }
414 
415 // reduces path to part that exists on disk (or root prefix of path)
416 // output path is normalized (with WCHAR_PATH_SEPARATOR)
ReducePathToRealFileSystemPath(UString & path)417 static void ReducePathToRealFileSystemPath(UString &path)
418 {
419   unsigned prefixSize = GetRootPrefixSize(path);
420 
421   while (!path.IsEmpty())
422   {
423     if (NFind::DoesDirExist(us2fs(path)))
424     {
425       NName::NormalizeDirPathPrefix(path);
426       break;
427     }
428     int pos = path.ReverseFind_PathSepar();
429     if (pos < 0)
430     {
431       path.Empty();
432       break;
433     }
434     path.DeleteFrom(pos + 1);
435     if ((unsigned)pos + 1 == prefixSize)
436       break;
437     path.DeleteFrom(pos);
438   }
439 }
440 
441 // returns: true, if such dir exists or is root
442 /*
443 static bool CheckFolderPath(const UString &path)
444 {
445   UString pathReduced = path;
446   ReducePathToRealFileSystemPath(pathReduced);
447   return (pathReduced == path);
448 }
449 */
450 
451 extern UString ConvertSizeToString(UInt64 value);
452 
AddSizeValue(UString & s,UInt64 size)453 static void AddSizeValue(UString &s, UInt64 size)
454 {
455   s += MyFormatNew(IDS_FILE_SIZE, ConvertSizeToString(size));
456 }
457 
AddValuePair1(UString & s,UINT resourceID,UInt64 size)458 static void AddValuePair1(UString &s, UINT resourceID, UInt64 size)
459 {
460   AddLangString(s, resourceID);
461   s += ": ";
462   AddSizeValue(s, size);
463   s.Add_LF();
464 }
465 
AddValuePair2(UString & s,UINT resourceID,UInt64 num,UInt64 size)466 void AddValuePair2(UString &s, UINT resourceID, UInt64 num, UInt64 size)
467 {
468   if (num == 0)
469     return;
470   AddLangString(s, resourceID);
471   s += ": ";
472   s += ConvertSizeToString(num);
473 
474   if (size != (UInt64)(Int64)-1)
475   {
476     s += "    ( ";
477     AddSizeValue(s, size);
478     s += " )";
479   }
480   s.Add_LF();
481 }
482 
AddPropValueToSum(IFolderFolder * folder,int index,PROPID propID,UInt64 & sum)483 static void AddPropValueToSum(IFolderFolder *folder, int index, PROPID propID, UInt64 &sum)
484 {
485   if (sum == (UInt64)(Int64)-1)
486     return;
487   NCOM::CPropVariant prop;
488   folder->GetProperty(index, propID, &prop);
489   UInt64 val = 0;
490   if (ConvertPropVariantToUInt64(prop, val))
491     sum += val;
492   else
493     sum = (UInt64)(Int64)-1;
494 }
495 
GetItemsInfoString(const CRecordVector<UInt32> & indices)496 UString CPanel::GetItemsInfoString(const CRecordVector<UInt32> &indices)
497 {
498   UString info;
499   UInt64 numDirs, numFiles, filesSize, foldersSize;
500   numDirs = numFiles = filesSize = foldersSize = 0;
501 
502   unsigned i;
503   for (i = 0; i < indices.Size(); i++)
504   {
505     int index = indices[i];
506     if (IsItem_Folder(index))
507     {
508       AddPropValueToSum(_folder, index, kpidSize, foldersSize);
509       numDirs++;
510     }
511     else
512     {
513       AddPropValueToSum(_folder, index, kpidSize, filesSize);
514       numFiles++;
515     }
516   }
517 
518   AddValuePair2(info, IDS_PROP_FOLDERS, numDirs, foldersSize);
519   AddValuePair2(info, IDS_PROP_FILES, numFiles, filesSize);
520   int numDefined = ((foldersSize != (UInt64)(Int64)-1) && foldersSize != 0) ? 1: 0;
521   numDefined += ((filesSize != (UInt64)(Int64)-1) && filesSize != 0) ? 1: 0;
522   if (numDefined == 2)
523     AddValuePair1(info, IDS_PROP_SIZE, filesSize + foldersSize);
524 
525   info.Add_LF();
526   info += _currentFolderPrefix;
527 
528   for (i = 0; i < indices.Size() && (int)i < (int)kCopyDialog_NumInfoLines - 6; i++)
529   {
530     info.Add_LF();
531     info += "  ";
532     int index = indices[i];
533     info += GetItemRelPath(index);
534     if (IsItem_Folder(index))
535       info.Add_PathSepar();
536   }
537   if (i != indices.Size())
538   {
539     info.Add_LF();
540     info += "  ...";
541   }
542   return info;
543 }
544 
545 bool IsCorrectFsName(const UString &name);
546 
547 
548 
549 /* Returns true, if path is path that can be used as path for File System functions
550 */
551 
552 /*
553 static bool IsFsPath(const FString &path)
554 {
555   if (!IsAbsolutePath(path))
556     return false;
557   unsigned prefixSize = GetRootPrefixSize(path);
558 }
559 */
560 
OnCopy(bool move,bool copyToSame,int srcPanelIndex)561 void CApp::OnCopy(bool move, bool copyToSame, int srcPanelIndex)
562 {
563   unsigned destPanelIndex = (NumPanels <= 1) ? srcPanelIndex : (1 - srcPanelIndex);
564   CPanel &srcPanel = Panels[srcPanelIndex];
565   CPanel &destPanel = Panels[destPanelIndex];
566 
567   CPanel::CDisableTimerProcessing disableTimerProcessing1(destPanel);
568   CPanel::CDisableTimerProcessing disableTimerProcessing2(srcPanel);
569 
570   if (move)
571   {
572     if (!srcPanel.CheckBeforeUpdate(IDS_MOVE))
573       return;
574   }
575   else if (!srcPanel.DoesItSupportOperations())
576   {
577     srcPanel.MessageBox_Error_UnsupportOperation();
578     return;
579   }
580 
581   CRecordVector<UInt32> indices;
582   UString destPath;
583   bool useDestPanel = false;
584 
585   {
586     if (copyToSame)
587     {
588       int focusedItem = srcPanel._listView.GetFocusedItem();
589       if (focusedItem < 0)
590         return;
591       int realIndex = srcPanel.GetRealItemIndex(focusedItem);
592       if (realIndex == kParentIndex)
593         return;
594       indices.Add(realIndex);
595       destPath = srcPanel.GetItemName(realIndex);
596     }
597     else
598     {
599       srcPanel.GetOperatedIndicesSmart(indices);
600       if (indices.Size() == 0)
601         return;
602       destPath = destPanel.GetFsPath();
603       if (NumPanels == 1)
604         ReducePathToRealFileSystemPath(destPath);
605     }
606   }
607 
608   UStringVector copyFolders;
609   ReadCopyHistory(copyFolders);
610 
611   bool useFullItemPaths = srcPanel.Is_IO_FS_Folder(); // maybe we need flat also here ??
612 
613   {
614     CCopyDialog copyDialog;
615 
616     copyDialog.Strings = copyFolders;
617     copyDialog.Value = destPath;
618     LangString(move ? IDS_MOVE : IDS_COPY, copyDialog.Title);
619     LangString(move ? IDS_MOVE_TO : IDS_COPY_TO, copyDialog.Static);
620     copyDialog.Info = srcPanel.GetItemsInfoString(indices);
621 
622     if (copyDialog.Create(srcPanel.GetParent()) != IDOK)
623       return;
624 
625     destPath = copyDialog.Value;
626   }
627 
628   {
629     if (destPath.IsEmpty())
630     {
631       srcPanel.MessageBox_Error_UnsupportOperation();
632       return;
633     }
634 
635     UString correctName;
636     if (!srcPanel.CorrectFsPath(destPath, correctName))
637     {
638       srcPanel.MessageBox_Error_HRESULT(E_INVALIDARG);
639       return;
640     }
641 
642     if (IsAbsolutePath(destPath))
643       destPath.Empty();
644     else
645       destPath = srcPanel.GetFsPath();
646     destPath += correctName;
647 
648     #if defined(_WIN32) && !defined(UNDER_CE)
649     if (destPath.Len() > 0 && destPath[0] == '\\')
650       if (destPath.Len() == 1 || destPath[1] != '\\')
651       {
652         srcPanel.MessageBox_Error_UnsupportOperation();
653         return;
654       }
655     #endif
656 
657     bool possibleToUseDestPanel = false;
658 
659     if (CompareFileNames(destPath, destPanel.GetFsPath()) == 0)
660     {
661       if (NumPanels == 1 || CompareFileNames(destPath, srcPanel.GetFsPath()) == 0)
662       {
663         srcPanel.MessageBox_Error(L"Can not copy files onto itself");
664         return;
665       }
666 
667       if (destPanel.DoesItSupportOperations())
668         possibleToUseDestPanel = true;
669     }
670 
671     bool destIsFsPath = false;
672 
673     if (possibleToUseDestPanel)
674     {
675       if (destPanel.IsFSFolder() || destPanel.IsAltStreamsFolder())
676         destIsFsPath = true;
677       else if (destPanel.IsFSDrivesFolder() || destPanel.IsRootFolder())
678       {
679         srcPanel.MessageBox_Error_UnsupportOperation();
680         return;
681       }
682     }
683     else
684     {
685       if (IsAltPathPrefix(us2fs(destPath)))
686       {
687         // we allow alt streams dest only to alt stream folder in second panel
688         srcPanel.MessageBox_Error_UnsupportOperation();
689         return;
690         /*
691         FString basePath = us2fs(destPath);
692         basePath.DeleteBack();
693         if (!DoesFileOrDirExist(basePath))
694         {
695           srcPanel.MessageBoxError2Lines(basePath, ERROR_FILE_NOT_FOUND); // GetLastError()
696           return;
697         }
698         destIsFsPath = true;
699         */
700       }
701       else
702       {
703         if (indices.Size() == 1 &&
704           !destPath.IsEmpty() && !IS_PATH_SEPAR(destPath.Back()))
705         {
706           int pos = destPath.ReverseFind_PathSepar();
707           if (pos < 0)
708           {
709             srcPanel.MessageBox_Error_UnsupportOperation();
710             return;
711           }
712           {
713             /*
714             #ifdef _WIN32
715             UString name = destPath.Ptr(pos + 1);
716             if (name.Find(L':') >= 0)
717             {
718               srcPanel.MessageBox_Error_UnsupportOperation();
719               return;
720             }
721             #endif
722             */
723             UString prefix = destPath.Left(pos + 1);
724             if (!CreateComplexDir(us2fs(prefix)))
725             {
726               DWORD lastError = ::GetLastError();
727               srcPanel.MessageBox_Error_2Lines_Message_HRESULT(prefix, lastError);
728               return;
729             }
730           }
731           // bool isFolder = srcPanael.IsItem_Folder(indices[0]);
732         }
733         else
734         {
735           NName::NormalizeDirPathPrefix(destPath);
736           if (!CreateComplexDir(us2fs(destPath)))
737           {
738             DWORD lastError = ::GetLastError();
739             srcPanel.MessageBox_Error_2Lines_Message_HRESULT(destPath, lastError);
740             return;
741           }
742         }
743         destIsFsPath = true;
744       }
745     }
746 
747     if (!destIsFsPath)
748       useDestPanel = true;
749 
750     AddUniqueStringToHeadOfList(copyFolders, destPath);
751     while (copyFolders.Size() > 20)
752       copyFolders.DeleteBack();
753     SaveCopyHistory(copyFolders);
754   }
755 
756   bool useSrcPanel = !useDestPanel || !srcPanel.Is_IO_FS_Folder();
757 
758   bool useTemp = useSrcPanel && useDestPanel;
759   if (useTemp && NumPanels == 1)
760   {
761     srcPanel.MessageBox_Error_UnsupportOperation();
762     return;
763   }
764 
765   CTempDir tempDirectory;
766   FString tempDirPrefix;
767   if (useTemp)
768   {
769     tempDirectory.Create(kTempDirPrefix);
770     tempDirPrefix = tempDirectory.GetPath();
771     NFile::NName::NormalizeDirPathPrefix(tempDirPrefix);
772   }
773 
774   CSelectedState srcSelState;
775   CSelectedState destSelState;
776   srcPanel.SaveSelectedState(srcSelState);
777   destPanel.SaveSelectedState(destSelState);
778 
779   CPanel::CDisableNotify disableNotify1(destPanel);
780   CPanel::CDisableNotify disableNotify2(srcPanel);
781 
782   HRESULT result = S_OK;
783 
784   if (useSrcPanel)
785   {
786     CCopyToOptions options;
787     options.folder = useTemp ? fs2us(tempDirPrefix) : destPath;
788     options.moveMode = move;
789     options.includeAltStreams = true;
790     options.replaceAltStreamChars = false;
791     options.showErrorMessages = true;
792 
793     result = srcPanel.CopyTo(options, indices, NULL);
794   }
795 
796   if (result == S_OK && useDestPanel)
797   {
798     UStringVector filePaths;
799     UString folderPrefix;
800 
801     if (useTemp)
802       folderPrefix = fs2us(tempDirPrefix);
803     else
804       folderPrefix = srcPanel.GetFsPath();
805 
806     filePaths.ClearAndReserve(indices.Size());
807 
808     FOR_VECTOR (i, indices)
809     {
810       UInt32 index = indices[i];
811       UString s;
812       if (useFullItemPaths)
813         s = srcPanel.GetItemRelPath2(index);
814       else
815         s = srcPanel.GetItemName_for_Copy(index);
816       filePaths.AddInReserved(s);
817     }
818 
819     result = destPanel.CopyFrom(move, folderPrefix, filePaths, true, 0);
820   }
821 
822   if (result != S_OK)
823   {
824     // disableNotify1.Restore();
825     // disableNotify2.Restore();
826     // For Password:
827     // srcPanel.SetFocusToList();
828     // srcPanel.InvalidateList(NULL, true);
829 
830     if (result != E_ABORT)
831       srcPanel.MessageBox_Error_HRESULT(result);
832     // return;
833   }
834 
835   RefreshTitleAlways();
836 
837   if (copyToSame || move)
838   {
839     srcPanel.RefreshListCtrl(srcSelState);
840   }
841 
842   if (!copyToSame)
843   {
844     destPanel.RefreshListCtrl(destSelState);
845     srcPanel.KillSelection();
846   }
847 
848   disableNotify1.Restore();
849   disableNotify2.Restore();
850   srcPanel.SetFocusToList();
851 }
852 
OnSetSameFolder(int srcPanelIndex)853 void CApp::OnSetSameFolder(int srcPanelIndex)
854 {
855   if (NumPanels <= 1)
856     return;
857   const CPanel &srcPanel = Panels[srcPanelIndex];
858   CPanel &destPanel = Panels[1 - srcPanelIndex];
859   destPanel.BindToPathAndRefresh(srcPanel._currentFolderPrefix);
860 }
861 
OnSetSubFolder(int srcPanelIndex)862 void CApp::OnSetSubFolder(int srcPanelIndex)
863 {
864   if (NumPanels <= 1)
865     return;
866   const CPanel &srcPanel = Panels[srcPanelIndex];
867   CPanel &destPanel = Panels[1 - srcPanelIndex];
868 
869   int focusedItem = srcPanel._listView.GetFocusedItem();
870   if (focusedItem < 0)
871     return;
872   int realIndex = srcPanel.GetRealItemIndex(focusedItem);
873   if (!srcPanel.IsItem_Folder(realIndex))
874     return;
875 
876   // destPanel.BindToFolder(srcPanel._currentFolderPrefix + srcPanel.GetItemName(realIndex) + WCHAR_PATH_SEPARATOR);
877 
878   CMyComPtr<IFolderFolder> newFolder;
879   if (realIndex == kParentIndex)
880   {
881     if (srcPanel._folder->BindToParentFolder(&newFolder) != S_OK)
882       return;
883     if (!newFolder)
884     {
885       const UString parentPrefix = srcPanel.GetParentDirPrefix();
886       bool archiveIsOpened, encrypted;
887       destPanel.BindToPath(parentPrefix, UString(), archiveIsOpened, encrypted);
888       destPanel.RefreshListCtrl();
889       return;
890     }
891   }
892   else
893   {
894     if (srcPanel._folder->BindToFolder(realIndex, &newFolder) != S_OK)
895       return;
896   }
897 
898   if (!newFolder)
899     return;
900 
901   destPanel.CloseOpenFolders();
902   destPanel.SetNewFolder(newFolder);
903   destPanel.RefreshListCtrl();
904 }
905 
906 /*
907 int CApp::GetFocusedPanelIndex() const
908 {
909   return LastFocusedPanel;
910   HWND hwnd = ::GetFocus();
911   for (;;)
912   {
913     if (hwnd == 0)
914       return 0;
915     for (unsigned i = 0; i < kNumPanelsMax; i++)
916     {
917       if (PanelsCreated[i] &&
918           ((HWND)Panels[i] == hwnd || Panels[i]._listView == hwnd))
919         return i;
920     }
921     hwnd = GetParent(hwnd);
922   }
923 }
924 */
925 
926 static UString g_ToolTipBuffer;
927 static CSysString g_ToolTipBufferSys;
928 
OnNotify(int,LPNMHDR pnmh)929 void CApp::OnNotify(int /* ctrlID */, LPNMHDR pnmh)
930 {
931   {
932     if (pnmh->code == TTN_GETDISPINFO)
933     {
934       LPNMTTDISPINFO info = (LPNMTTDISPINFO)pnmh;
935       info->hinst = 0;
936       g_ToolTipBuffer.Empty();
937       SetButtonText((int)info->hdr.idFrom, g_ToolTipBuffer);
938       g_ToolTipBufferSys = GetSystemString(g_ToolTipBuffer);
939       info->lpszText = (LPTSTR)(LPCTSTR)g_ToolTipBufferSys;
940       return;
941     }
942     #ifndef _UNICODE
943     if (pnmh->code == TTN_GETDISPINFOW)
944     {
945       LPNMTTDISPINFOW info = (LPNMTTDISPINFOW)pnmh;
946       info->hinst = 0;
947       g_ToolTipBuffer.Empty();
948       SetButtonText((int)info->hdr.idFrom, g_ToolTipBuffer);
949       info->lpszText = (LPWSTR)(LPCWSTR)g_ToolTipBuffer;
950       return;
951     }
952     #endif
953   }
954 }
955 
RefreshTitle(bool always)956 void CApp::RefreshTitle(bool always)
957 {
958   UString path = GetFocusedPanel()._currentFolderPrefix;
959   if (path.IsEmpty())
960     path = "7-Zip"; // LangString(IDS_APP_TITLE);
961   if (!always && path == PrevTitle)
962     return;
963   PrevTitle = path;
964   NWindows::MySetWindowText(_window, path);
965 }
966 
RefreshTitlePanel(unsigned panelIndex,bool always)967 void CApp::RefreshTitlePanel(unsigned panelIndex, bool always)
968 {
969   if (panelIndex != GetFocusedPanelIndex())
970     return;
971   RefreshTitle(always);
972 }
973 
AddUniqueStringToHead(UStringVector & list,const UString & s)974 void AddUniqueStringToHead(UStringVector &list, const UString &s)
975 {
976   for (unsigned i = 0; i < list.Size();)
977     if (s.IsEqualTo_NoCase(list[i]))
978       list.Delete(i);
979     else
980       i++;
981   list.Insert(0, s);
982 }
983 
984 
Normalize()985 void CFolderHistory::Normalize()
986 {
987   const unsigned kMaxSize = 100;
988   if (Strings.Size() > kMaxSize)
989     Strings.DeleteFrom(kMaxSize);
990 }
991 
AddString(const UString & s)992 void CFolderHistory::AddString(const UString &s)
993 {
994   NSynchronization::CCriticalSectionLock lock(_criticalSection);
995   AddUniqueStringToHead(Strings, s);
996   Normalize();
997 }
998