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
ReleaseApp()405 void CApp::ReleaseApp()
406 {
407 // 24.09: ReleasePanel() will stop panel timer processing.
408 // but we want to stop timer processing for all panels
409 // before ReleasePanel() calling.
410 unsigned i;
411 for (i = 0; i < kNumPanelsMax; i++)
412 Panels[i].Disable_Processing_Timer_Notify_StatusBar();
413 // It's for unloading COM dll's: don't change it.
414 for (i = 0; i < kNumPanelsMax; i++)
415 Panels[i].ReleasePanel();
416 }
417
418 // reduces path to part that exists on disk (or root prefix of path)
419 // output path is normalized (with WCHAR_PATH_SEPARATOR)
Reduce_Path_To_RealFileSystemPath(UString & path)420 static void Reduce_Path_To_RealFileSystemPath(UString &path)
421 {
422 unsigned prefixSize = GetRootPrefixSize(path);
423
424 while (!path.IsEmpty())
425 {
426 if (NFind::DoesDirExist_FollowLink(us2fs(path)))
427 {
428 NName::NormalizeDirPathPrefix(path);
429 break;
430 }
431 int pos = path.ReverseFind_PathSepar();
432 if (pos < 0)
433 {
434 path.Empty();
435 break;
436 }
437 path.DeleteFrom((unsigned)(pos + 1));
438 if ((unsigned)pos + 1 == prefixSize)
439 break;
440 path.DeleteFrom((unsigned)pos);
441 }
442 }
443
444 // returns: true, if such dir exists or is root
445 /*
446 static bool CheckFolderPath(const UString &path)
447 {
448 UString pathReduced = path;
449 Reduce_Path_To_RealFileSystemPath(pathReduced);
450 return (pathReduced == path);
451 }
452 */
453
454 extern UString ConvertSizeToString(UInt64 value);
455
AddSizeValue(UString & s,UInt64 size)456 static void AddSizeValue(UString &s, UInt64 size)
457 {
458 s += MyFormatNew(IDS_FILE_SIZE, ConvertSizeToString(size));
459 }
460
AddValuePair1(UString & s,UINT resourceID,UInt64 size)461 static void AddValuePair1(UString &s, UINT resourceID, UInt64 size)
462 {
463 AddLangString(s, resourceID);
464 s += ": ";
465 AddSizeValue(s, size);
466 s.Add_LF();
467 }
468
469 void AddValuePair2(UString &s, UINT resourceID, UInt64 num, UInt64 size);
AddValuePair2(UString & s,UINT resourceID,UInt64 num,UInt64 size)470 void AddValuePair2(UString &s, UINT resourceID, UInt64 num, UInt64 size)
471 {
472 if (num == 0)
473 return;
474 AddLangString(s, resourceID);
475 s += ": ";
476 s += ConvertSizeToString(num);
477
478 if (size != (UInt64)(Int64)-1)
479 {
480 s += " ( ";
481 AddSizeValue(s, size);
482 s += " )";
483 }
484 s.Add_LF();
485 }
486
AddPropValueToSum(IFolderFolder * folder,UInt32 index,PROPID propID,UInt64 & sum)487 static void AddPropValueToSum(IFolderFolder *folder, UInt32 index, PROPID propID, UInt64 &sum)
488 {
489 if (sum == (UInt64)(Int64)-1)
490 return;
491 NCOM::CPropVariant prop;
492 folder->GetProperty(index, propID, &prop);
493 UInt64 val = 0;
494 if (ConvertPropVariantToUInt64(prop, val))
495 sum += val;
496 else
497 sum = (UInt64)(Int64)-1;
498 }
499
GetItemsInfoString(const CRecordVector<UInt32> & indices)500 UString CPanel::GetItemsInfoString(const CRecordVector<UInt32> &indices)
501 {
502 UString info;
503 UInt64 numDirs, numFiles, filesSize, foldersSize;
504 numDirs = numFiles = filesSize = foldersSize = 0;
505
506 unsigned i;
507 for (i = 0; i < indices.Size(); i++)
508 {
509 const UInt32 index = indices[i];
510 if (IsItem_Folder(index))
511 {
512 AddPropValueToSum(_folder, index, kpidSize, foldersSize);
513 numDirs++;
514 }
515 else
516 {
517 AddPropValueToSum(_folder, index, kpidSize, filesSize);
518 numFiles++;
519 }
520 }
521
522 AddValuePair2(info, IDS_PROP_FOLDERS, numDirs, foldersSize);
523 AddValuePair2(info, IDS_PROP_FILES, numFiles, filesSize);
524 int numDefined = ((foldersSize != (UInt64)(Int64)-1) && foldersSize != 0) ? 1: 0;
525 numDefined += ((filesSize != (UInt64)(Int64)-1) && filesSize != 0) ? 1: 0;
526 if (numDefined == 2)
527 AddValuePair1(info, IDS_PROP_SIZE, filesSize + foldersSize);
528
529 info.Add_LF();
530 info += _currentFolderPrefix;
531
532 for (i = 0; i < indices.Size() && (int)i < (int)kCopyDialog_NumInfoLines - 6; i++)
533 {
534 info.Add_LF();
535 info += " ";
536 const UInt32 index = indices[i];
537 info += GetItemRelPath(index);
538 if (IsItem_Folder(index))
539 info.Add_PathSepar();
540 }
541 if (i != indices.Size())
542 {
543 info.Add_LF();
544 info += " ...";
545 }
546 return info;
547 }
548
549 bool IsCorrectFsName(const UString &name);
550
551
552
553 /* Returns true, if path is path that can be used as path for File System functions
554 */
555
556 /*
557 static bool IsFsPath(const FString &path)
558 {
559 if (!IsAbsolutePath(path))
560 return false;
561 unsigned prefixSize = GetRootPrefixSize(path);
562 }
563 */
564
OnCopy(bool move,bool copyToSame,unsigned srcPanelIndex)565 void CApp::OnCopy(bool move, bool copyToSame, unsigned srcPanelIndex)
566 {
567 const unsigned destPanelIndex = (NumPanels <= 1) ? srcPanelIndex : (1 - srcPanelIndex);
568 CPanel &srcPanel = Panels[srcPanelIndex];
569 CPanel &destPanel = Panels[destPanelIndex];
570
571 CPanel::CDisableTimerProcessing disableTimerProcessing1(destPanel);
572 CPanel::CDisableTimerProcessing disableTimerProcessing2(srcPanel);
573
574 if (move)
575 {
576 if (!srcPanel.CheckBeforeUpdate(IDS_MOVE))
577 return;
578 }
579 else if (!srcPanel.DoesItSupportOperations())
580 {
581 srcPanel.MessageBox_Error_UnsupportOperation();
582 return;
583 }
584
585 CRecordVector<UInt32> indices;
586 UString destPath;
587 bool useDestPanel = false;
588
589 {
590 if (copyToSame)
591 {
592 const int focusedItem = srcPanel._listView.GetFocusedItem();
593 if (focusedItem < 0)
594 return;
595 const unsigned realIndex = srcPanel.GetRealItemIndex(focusedItem);
596 if (realIndex == kParentIndex)
597 return;
598 indices.Add(realIndex);
599 destPath = srcPanel.GetItemName(realIndex);
600 }
601 else
602 {
603 srcPanel.Get_ItemIndices_OperSmart(indices);
604 if (indices.Size() == 0)
605 return;
606 destPath = destPanel.GetFsPath();
607 if (NumPanels == 1)
608 Reduce_Path_To_RealFileSystemPath(destPath);
609 }
610 }
611
612 UStringVector copyFolders;
613 ReadCopyHistory(copyFolders);
614
615 const bool useFullItemPaths = srcPanel.Is_IO_FS_Folder(); // maybe we need flat also here ??
616
617 {
618 CCopyDialog copyDialog;
619
620 copyDialog.Strings = copyFolders;
621 copyDialog.Value = destPath;
622 LangString(move ? IDS_MOVE : IDS_COPY, copyDialog.Title);
623 LangString(move ? IDS_MOVE_TO : IDS_COPY_TO, copyDialog.Static);
624 copyDialog.Info = srcPanel.GetItemsInfoString(indices);
625
626 if (copyDialog.Create(srcPanel.GetParent()) != IDOK)
627 return;
628
629 destPath = copyDialog.Value;
630 }
631
632 {
633 if (destPath.IsEmpty())
634 {
635 srcPanel.MessageBox_Error_UnsupportOperation();
636 return;
637 }
638
639 UString correctName;
640 if (!srcPanel.CorrectFsPath(destPath, correctName))
641 {
642 srcPanel.MessageBox_Error_HRESULT(E_INVALIDARG);
643 return;
644 }
645
646 if (IsAbsolutePath(destPath))
647 destPath.Empty();
648 else
649 destPath = srcPanel.GetFsPath();
650 destPath += correctName;
651
652 #if defined(_WIN32) && !defined(UNDER_CE)
653 if (destPath.Len() != 0 && destPath[0] == '\\')
654 if (destPath.Len() == 1 || destPath[1] != '\\')
655 {
656 srcPanel.MessageBox_Error_UnsupportOperation();
657 return;
658 }
659 #endif
660
661 bool possibleToUseDestPanel = false;
662
663 if (CompareFileNames(destPath, destPanel.GetFsPath()) == 0)
664 {
665 if (NumPanels == 1 || CompareFileNames(destPath, srcPanel.GetFsPath()) == 0)
666 {
667 srcPanel.MessageBox_Error(L"Cannot copy files onto itself");
668 return;
669 }
670
671 if (destPanel.DoesItSupportOperations())
672 possibleToUseDestPanel = true;
673 }
674
675 bool destIsFsPath = false;
676
677 if (possibleToUseDestPanel)
678 {
679 if (destPanel.IsFSFolder() || destPanel.IsAltStreamsFolder())
680 destIsFsPath = true;
681 else if (destPanel.IsFSDrivesFolder() || destPanel.IsRootFolder())
682 {
683 srcPanel.MessageBox_Error_UnsupportOperation();
684 return;
685 }
686 }
687 else
688 {
689 if (IsAltPathPrefix(us2fs(destPath)))
690 {
691 // we allow alt streams dest only to alt stream folder in second panel
692 srcPanel.MessageBox_Error_UnsupportOperation();
693 return;
694 /*
695 FString basePath = us2fs(destPath);
696 basePath.DeleteBack();
697 if (!DoesFileOrDirExist(basePath))
698 {
699 srcPanel.MessageBoxError2Lines(basePath, ERROR_FILE_NOT_FOUND); // GetLastError()
700 return;
701 }
702 destIsFsPath = true;
703 */
704 }
705 else
706 {
707 if (indices.Size() == 1 &&
708 !destPath.IsEmpty() && !IS_PATH_SEPAR(destPath.Back()))
709 {
710 int pos = destPath.ReverseFind_PathSepar();
711 if (pos < 0)
712 {
713 srcPanel.MessageBox_Error_UnsupportOperation();
714 return;
715 }
716 {
717 /*
718 #ifdef _WIN32
719 UString name = destPath.Ptr(pos + 1);
720 if (name.Find(L':') >= 0)
721 {
722 srcPanel.MessageBox_Error_UnsupportOperation();
723 return;
724 }
725 #endif
726 */
727 UString prefix = destPath.Left(pos + 1);
728 if (!CreateComplexDir(us2fs(prefix)))
729 {
730 const HRESULT lastError = GetLastError_noZero_HRESULT();
731 srcPanel.MessageBox_Error_2Lines_Message_HRESULT(prefix, lastError);
732 return;
733 }
734 }
735 // bool isFolder = srcPanael.IsItem_Folder(indices[0]);
736 }
737 else
738 {
739 NName::NormalizeDirPathPrefix(destPath);
740 if (!CreateComplexDir(us2fs(destPath)))
741 {
742 const HRESULT lastError = GetLastError_noZero_HRESULT();
743 srcPanel.MessageBox_Error_2Lines_Message_HRESULT(destPath, lastError);
744 return;
745 }
746 }
747 destIsFsPath = true;
748 }
749 }
750
751 if (!destIsFsPath)
752 useDestPanel = true;
753
754 AddUniqueStringToHeadOfList(copyFolders, destPath);
755 while (copyFolders.Size() > 20)
756 copyFolders.DeleteBack();
757 SaveCopyHistory(copyFolders);
758 }
759
760 bool useSrcPanel = !useDestPanel || !srcPanel.Is_IO_FS_Folder();
761
762 bool useTemp = useSrcPanel && useDestPanel;
763 if (useTemp && NumPanels == 1)
764 {
765 srcPanel.MessageBox_Error_UnsupportOperation();
766 return;
767 }
768
769 CTempDir tempDirectory;
770 FString tempDirPrefix;
771 if (useTemp)
772 {
773 tempDirectory.Create(kTempDirPrefix);
774 tempDirPrefix = tempDirectory.GetPath();
775 NFile::NName::NormalizeDirPathPrefix(tempDirPrefix);
776 }
777
778 CSelectedState srcSelState;
779 CSelectedState destSelState;
780 srcPanel.SaveSelectedState(srcSelState);
781 destPanel.SaveSelectedState(destSelState);
782
783 CPanel::CDisableNotify disableNotify1(destPanel);
784 CPanel::CDisableNotify disableNotify2(srcPanel);
785
786 HRESULT result = S_OK;
787
788 if (useSrcPanel)
789 {
790 CCopyToOptions options;
791 // options.src_Is_IO_FS_Folder = useFullItemPaths;
792 options.folder = useTemp ? fs2us(tempDirPrefix) : destPath;
793 options.moveMode = move;
794 options.includeAltStreams = true;
795 options.replaceAltStreamChars = false;
796 options.showErrorMessages = true;
797
798 result = srcPanel.CopyTo(options, indices, NULL);
799 }
800
801 if (result == S_OK && useDestPanel)
802 {
803 UStringVector filePaths;
804 UString folderPrefix;
805
806 if (useTemp)
807 folderPrefix = fs2us(tempDirPrefix);
808 else
809 folderPrefix = srcPanel.GetFsPath();
810
811 filePaths.ClearAndReserve(indices.Size());
812
813 FOR_VECTOR (i, indices)
814 {
815 UInt32 index = indices[i];
816 UString s;
817 if (useFullItemPaths)
818 s = srcPanel.GetItemRelPath2(index);
819 else
820 s = srcPanel.GetItemName_for_Copy(index);
821 filePaths.AddInReserved(s);
822 }
823
824 result = destPanel.CopyFrom(move, folderPrefix, filePaths, true, NULL);
825 }
826
827 if (result != S_OK)
828 {
829 // disableNotify1.Restore();
830 // disableNotify2.Restore();
831 // For Password:
832 // srcPanel.SetFocusToList();
833 // srcPanel.InvalidateList(NULL, true);
834
835 if (result != E_ABORT)
836 srcPanel.MessageBox_Error_HRESULT(result);
837 // return;
838 }
839
840 RefreshTitleAlways();
841
842 if (copyToSame || move)
843 {
844 srcPanel.RefreshListCtrl(srcSelState);
845 }
846
847 if (!copyToSame)
848 {
849 destPanel.RefreshListCtrl(destSelState);
850 srcPanel.KillSelection();
851 }
852
853 disableNotify1.Restore();
854 disableNotify2.Restore();
855 srcPanel.SetFocusToList();
856 }
857
OnSetSameFolder(unsigned srcPanelIndex)858 void CApp::OnSetSameFolder(unsigned srcPanelIndex)
859 {
860 if (NumPanels <= 1)
861 return;
862 const CPanel &srcPanel = Panels[srcPanelIndex];
863 CPanel &destPanel = Panels[1 - srcPanelIndex];
864 destPanel.BindToPathAndRefresh(srcPanel._currentFolderPrefix);
865 }
866
OnSetSubFolder(unsigned srcPanelIndex)867 void CApp::OnSetSubFolder(unsigned srcPanelIndex)
868 {
869 if (NumPanels <= 1)
870 return;
871 const CPanel &srcPanel = Panels[srcPanelIndex];
872 CPanel &destPanel = Panels[1 - srcPanelIndex];
873
874 const int focusedItem = srcPanel._listView.GetFocusedItem();
875 if (focusedItem < 0)
876 return;
877 const unsigned realIndex = srcPanel.GetRealItemIndex(focusedItem);
878 if (!srcPanel.IsItem_Folder(realIndex))
879 return;
880
881 // destPanel.BindToFolder(srcPanel._currentFolderPrefix + srcPanel.GetItemName(realIndex) + WCHAR_PATH_SEPARATOR);
882
883 CMyComPtr<IFolderFolder> newFolder;
884 if (realIndex == kParentIndex)
885 {
886 if (srcPanel._folder->BindToParentFolder(&newFolder) != S_OK)
887 return;
888 if (!newFolder)
889 {
890 {
891 const UString parentPrefix = srcPanel.GetParentDirPrefix();
892 COpenResult openRes;
893 destPanel.BindToPath(parentPrefix, UString(), openRes);
894 }
895 destPanel.RefreshListCtrl();
896 return;
897 }
898 }
899 else
900 {
901 if (srcPanel._folder->BindToFolder(realIndex, &newFolder) != S_OK)
902 return;
903 }
904
905 if (!newFolder)
906 return;
907
908 destPanel.CloseOpenFolders();
909 destPanel.SetNewFolder(newFolder);
910 destPanel.RefreshListCtrl();
911 }
912
913 /*
914 int CApp::GetFocusedPanelIndex() const
915 {
916 return LastFocusedPanel;
917 HWND hwnd = ::GetFocus();
918 for (;;)
919 {
920 if (hwnd == 0)
921 return 0;
922 for (unsigned i = 0; i < kNumPanelsMax; i++)
923 {
924 if (PanelsCreated[i] &&
925 ((HWND)Panels[i] == hwnd || Panels[i]._listView == hwnd))
926 return i;
927 }
928 hwnd = GetParent(hwnd);
929 }
930 }
931 */
932
933 static UString g_ToolTipBuffer;
934 static CSysString g_ToolTipBufferSys;
935
OnNotify(int,LPNMHDR pnmh)936 void CApp::OnNotify(int /* ctrlID */, LPNMHDR pnmh)
937 {
938 {
939 if (pnmh->code == TTN_GETDISPINFO)
940 {
941 LPNMTTDISPINFO info = (LPNMTTDISPINFO)pnmh;
942 info->hinst = NULL;
943 g_ToolTipBuffer.Empty();
944 SetButtonText((int)info->hdr.idFrom, g_ToolTipBuffer);
945 g_ToolTipBufferSys = GetSystemString(g_ToolTipBuffer);
946 info->lpszText = g_ToolTipBufferSys.Ptr_non_const();
947 return;
948 }
949 #ifndef _UNICODE
950 if (pnmh->code == TTN_GETDISPINFOW)
951 {
952 LPNMTTDISPINFOW info = (LPNMTTDISPINFOW)pnmh;
953 info->hinst = NULL;
954 g_ToolTipBuffer.Empty();
955 SetButtonText((int)info->hdr.idFrom, g_ToolTipBuffer);
956 info->lpszText = g_ToolTipBuffer.Ptr_non_const();
957 return;
958 }
959 #endif
960 }
961 }
962
RefreshTitle(bool always)963 void CApp::RefreshTitle(bool always)
964 {
965 UString path = GetFocusedPanel()._currentFolderPrefix;
966 if (path.IsEmpty())
967 path = "7-Zip"; // LangString(IDS_APP_TITLE);
968 if (!always && path == PrevTitle)
969 return;
970 PrevTitle = path;
971 NWindows::MySetWindowText(_window, path);
972 }
973
RefreshTitlePanel(unsigned panelIndex,bool always)974 void CApp::RefreshTitlePanel(unsigned panelIndex, bool always)
975 {
976 if (panelIndex != GetFocusedPanelIndex())
977 return;
978 RefreshTitle(always);
979 }
980
AddUniqueStringToHead(UStringVector & list,const UString & s)981 static void AddUniqueStringToHead(UStringVector &list, const UString &s)
982 {
983 for (unsigned i = 0; i < list.Size();)
984 if (s.IsEqualTo_NoCase(list[i]))
985 list.Delete(i);
986 else
987 i++;
988 list.Insert(0, s);
989 }
990
991
Normalize()992 void CFolderHistory::Normalize()
993 {
994 const unsigned kMaxSize = 100;
995 if (Strings.Size() > kMaxSize)
996 Strings.DeleteFrom(kMaxSize);
997 }
998
AddString(const UString & s)999 void CFolderHistory::AddString(const UString &s)
1000 {
1001 NSynchronization::CCriticalSectionLock lock(_criticalSection);
1002 AddUniqueStringToHead(Strings, s);
1003 Normalize();
1004 }
1005