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