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