Imported Upstream version 9.20
[platform/upstream/7zip.git] / CPP / 7zip / UI / FileManager / App.cpp
1 // App.cpp\r
2 \r
3 #include "StdAfx.h"\r
4 \r
5 #include "resource.h"\r
6 #include "OverwriteDialogRes.h"\r
7 \r
8 #include "Common/IntToString.h"\r
9 #include "Common/StringConvert.h"\r
10 \r
11 #include "Windows/COM.h"\r
12 #include "Windows/Error.h"\r
13 #include "Windows/FileDir.h"\r
14 #include "Windows/PropVariant.h"\r
15 #include "Windows/PropVariantConversions.h"\r
16 #include "Windows/Thread.h"\r
17 \r
18 #include "App.h"\r
19 #include "CopyDialog.h"\r
20 #include "ExtractCallback.h"\r
21 #include "FormatUtils.h"\r
22 #include "IFolder.h"\r
23 #include "LangUtils.h"\r
24 #include "RegistryUtils.h"\r
25 #include "ViewSettings.h"\r
26 \r
27 using namespace NWindows;\r
28 using namespace NFile;\r
29 using namespace NFind;\r
30 \r
31 extern DWORD g_ComCtl32Version;\r
32 extern HINSTANCE g_hInstance;\r
33 \r
34 static LPCWSTR kTempDirPrefix = L"7zE";\r
35 \r
36 void CPanelCallbackImp::OnTab()\r
37 {\r
38   if (g_App.NumPanels != 1)\r
39     _app->Panels[1 - _index].SetFocusToList();\r
40   _app->RefreshTitle();\r
41 }\r
42 \r
43 void CPanelCallbackImp::SetFocusToPath(int index)\r
44 {\r
45   int newPanelIndex = index;\r
46   if (g_App.NumPanels == 1)\r
47     newPanelIndex = g_App.LastFocusedPanel;\r
48   _app->RefreshTitle();\r
49   _app->Panels[newPanelIndex]._headerComboBox.SetFocus();\r
50   _app->Panels[newPanelIndex]._headerComboBox.ShowDropDown();\r
51 }\r
52 \r
53 \r
54 void CPanelCallbackImp::OnCopy(bool move, bool copyToSame) { _app->OnCopy(move, copyToSame, _index); }\r
55 void CPanelCallbackImp::OnSetSameFolder() { _app->OnSetSameFolder(_index); }\r
56 void CPanelCallbackImp::OnSetSubFolder()  { _app->OnSetSubFolder(_index); }\r
57 void CPanelCallbackImp::PanelWasFocused() { _app->SetFocusedPanel(_index); _app->RefreshTitle(_index); }\r
58 void CPanelCallbackImp::DragBegin() { _app->DragBegin(_index); }\r
59 void CPanelCallbackImp::DragEnd() { _app->DragEnd(); }\r
60 void CPanelCallbackImp::RefreshTitle(bool always) { _app->RefreshTitle(_index, always); }\r
61 \r
62 void CApp::SetListSettings()\r
63 {\r
64   bool showDots = ReadShowDots();\r
65   bool showRealFileIcons = ReadShowRealFileIcons();\r
66 \r
67   DWORD extendedStyle = LVS_EX_HEADERDRAGDROP;\r
68   if (ReadFullRow())\r
69     extendedStyle |= LVS_EX_FULLROWSELECT;\r
70   if (ReadShowGrid())\r
71     extendedStyle |= LVS_EX_GRIDLINES;\r
72   bool mySelectionMode = ReadAlternativeSelection();\r
73   \r
74   if (ReadSingleClick())\r
75   {\r
76     extendedStyle |= LVS_EX_ONECLICKACTIVATE | LVS_EX_TRACKSELECT;\r
77     /*\r
78     if (ReadUnderline())\r
79       extendedStyle |= LVS_EX_UNDERLINEHOT;\r
80     */\r
81   }\r
82 \r
83   for (int i = 0; i < kNumPanelsMax; i++)\r
84   {\r
85     CPanel &panel = Panels[i];\r
86     panel._mySelectMode = mySelectionMode;\r
87     panel._showDots = showDots;\r
88     panel._showRealFileIcons = showRealFileIcons;\r
89     panel._exStyle = extendedStyle;\r
90 \r
91     DWORD style = (DWORD)panel._listView.GetStyle();\r
92     if (mySelectionMode)\r
93       style |= LVS_SINGLESEL;\r
94     else\r
95       style &= ~LVS_SINGLESEL;\r
96     panel._listView.SetStyle(style);\r
97     panel.SetExtendedStyle();\r
98   }\r
99 }\r
100 \r
101 void CApp::SetShowSystemMenu()\r
102 {\r
103   ShowSystemMenu = ReadShowSystemMenu();\r
104 }\r
105 \r
106 #ifndef ILC_COLOR32\r
107 #define ILC_COLOR32 0x0020\r
108 #endif\r
109 \r
110 HRESULT CApp::CreateOnePanel(int panelIndex, const UString &mainPath, const UString &arcFormat,\r
111   bool &archiveIsOpened, bool &encrypted)\r
112 {\r
113   if (PanelsCreated[panelIndex])\r
114     return S_OK;\r
115   m_PanelCallbackImp[panelIndex].Init(this, panelIndex);\r
116   UString path;\r
117   if (mainPath.IsEmpty())\r
118   {\r
119     if (!::ReadPanelPath(panelIndex, path))\r
120       path.Empty();\r
121   }\r
122   else\r
123     path = mainPath;\r
124   int id = 1000 + 100 * panelIndex;\r
125   RINOK(Panels[panelIndex].Create(_window, _window,\r
126       id, path, arcFormat, &m_PanelCallbackImp[panelIndex], &AppState, archiveIsOpened, encrypted));\r
127   PanelsCreated[panelIndex] = true;\r
128   return S_OK;\r
129 }\r
130 \r
131 static void CreateToolbar(HWND parent,\r
132     NWindows::NControl::CImageList &imageList,\r
133     NWindows::NControl::CToolBar &toolBar,\r
134     bool largeButtons)\r
135 {\r
136   toolBar.Attach(::CreateWindowEx(0, TOOLBARCLASSNAME, NULL, 0\r
137       | WS_CHILD\r
138       | WS_VISIBLE\r
139       | TBSTYLE_FLAT\r
140       | TBSTYLE_TOOLTIPS\r
141       | TBSTYLE_WRAPABLE\r
142       // | TBSTYLE_AUTOSIZE\r
143       // | CCS_NORESIZE\r
144       #ifdef UNDER_CE\r
145       | CCS_NODIVIDER\r
146       | CCS_NOPARENTALIGN\r
147       #endif\r
148       ,0,0,0,0, parent, NULL, g_hInstance, NULL));\r
149 \r
150   // TB_BUTTONSTRUCTSIZE message, which is required for\r
151   // backward compatibility.\r
152   toolBar.ButtonStructSize();\r
153 \r
154   imageList.Create(\r
155       largeButtons ? 48: 24,\r
156       largeButtons ? 36: 24,\r
157       ILC_MASK | ILC_COLOR32, 0, 0);\r
158   toolBar.SetImageList(0, imageList);\r
159 }\r
160 \r
161 struct CButtonInfo\r
162 {\r
163   int CommandID;\r
164   UINT BitmapResID;\r
165   UINT Bitmap2ResID;\r
166   UINT StringResID;\r
167   UInt32 LangID;\r
168   UString GetText() const { return LangString(StringResID, LangID); }\r
169 };\r
170 \r
171 static CButtonInfo g_StandardButtons[] =\r
172 {\r
173   { IDM_COPY_TO, IDB_COPY, IDB_COPY2, IDS_BUTTON_COPY, 0x03020420},\r
174   { IDM_MOVE_TO, IDB_MOVE, IDB_MOVE2, IDS_BUTTON_MOVE, 0x03020421},\r
175   { IDM_DELETE, IDB_DELETE, IDB_DELETE2, IDS_BUTTON_DELETE, 0x03020422} ,\r
176   { IDM_FILE_PROPERTIES, IDB_INFO, IDB_INFO2, IDS_BUTTON_INFO, 0x03020423}\r
177 };\r
178 \r
179 static CButtonInfo g_ArchiveButtons[] =\r
180 {\r
181   { kAddCommand, IDB_ADD, IDB_ADD2, IDS_ADD, 0x03020400},\r
182   { kExtractCommand, IDB_EXTRACT, IDB_EXTRACT2, IDS_EXTRACT, 0x03020401},\r
183   { kTestCommand , IDB_TEST, IDB_TEST2, IDS_TEST, 0x03020402}\r
184 };\r
185 \r
186 static bool SetButtonText(int commandID, CButtonInfo *buttons, int numButtons, UString &s)\r
187 {\r
188   for (int i = 0; i < numButtons; i++)\r
189   {\r
190     const CButtonInfo &b = buttons[i];\r
191     if (b.CommandID == commandID)\r
192     {\r
193       s = b.GetText();\r
194       return true;\r
195     }\r
196   }\r
197   return false;\r
198 }\r
199 \r
200 static void SetButtonText(int commandID, UString &s)\r
201 {\r
202   if (SetButtonText(commandID, g_StandardButtons,\r
203       sizeof(g_StandardButtons) / sizeof(g_StandardButtons[0]), s))\r
204     return;\r
205   SetButtonText(commandID, g_ArchiveButtons,\r
206       sizeof(g_ArchiveButtons) / sizeof(g_ArchiveButtons[0]), s);\r
207 }\r
208 \r
209 static void AddButton(\r
210     NControl::CImageList &imageList,\r
211     NControl::CToolBar &toolBar,\r
212     CButtonInfo &butInfo, bool showText, bool large)\r
213 {\r
214   TBBUTTON but;\r
215   but.iBitmap = 0;\r
216   but.idCommand = butInfo.CommandID;\r
217   but.fsState = TBSTATE_ENABLED;\r
218   but.fsStyle = TBSTYLE_BUTTON;\r
219   but.dwData = 0;\r
220 \r
221   UString s = butInfo.GetText();\r
222   but.iString = 0;\r
223   if (showText)\r
224     but.iString = (INT_PTR)(LPCWSTR)s;\r
225 \r
226   but.iBitmap = imageList.GetImageCount();\r
227   HBITMAP b = ::LoadBitmap(g_hInstance,\r
228       large ?\r
229       MAKEINTRESOURCE(butInfo.BitmapResID):\r
230       MAKEINTRESOURCE(butInfo.Bitmap2ResID));\r
231   if (b != 0)\r
232   {\r
233     imageList.AddMasked(b, RGB(255, 0, 255));\r
234     ::DeleteObject(b);\r
235   }\r
236   #ifdef _UNICODE\r
237   toolBar.AddButton(1, &but);\r
238   #else\r
239   toolBar.AddButtonW(1, &but);\r
240   #endif\r
241 }\r
242 \r
243 void CApp::ReloadToolbars()\r
244 {\r
245   _buttonsImageList.Destroy();\r
246   _toolBar.Destroy();\r
247 \r
248 \r
249   if (ShowArchiveToolbar || ShowStandardToolbar)\r
250   {\r
251     CreateToolbar(_window, _buttonsImageList, _toolBar, LargeButtons);\r
252     int i;\r
253     if (ShowArchiveToolbar)\r
254       for (i = 0; i < sizeof(g_ArchiveButtons) / sizeof(g_ArchiveButtons[0]); i++)\r
255         AddButton(_buttonsImageList, _toolBar, g_ArchiveButtons[i], ShowButtonsLables, LargeButtons);\r
256     if (ShowStandardToolbar)\r
257       for (i = 0; i < sizeof(g_StandardButtons) / sizeof(g_StandardButtons[0]); i++)\r
258         AddButton(_buttonsImageList, _toolBar, g_StandardButtons[i], ShowButtonsLables, LargeButtons);\r
259 \r
260     _toolBar.AutoSize();\r
261   }\r
262 }\r
263 \r
264 void CApp::SaveToolbarChanges()\r
265 {\r
266   SaveToolbar();\r
267   ReloadToolbars();\r
268   MoveSubWindows();\r
269 }\r
270 \r
271 void MyLoadMenu();\r
272 \r
273 HRESULT CApp::Create(HWND hwnd, const UString &mainPath, const UString &arcFormat, int xSizes[2], bool &archiveIsOpened, bool &encrypted)\r
274 {\r
275   _window.Attach(hwnd);\r
276   #ifdef UNDER_CE\r
277   _commandBar.Create(g_hInstance, hwnd, 1);\r
278   #endif\r
279   MyLoadMenu();\r
280   #ifdef UNDER_CE\r
281   _commandBar.AutoSize();\r
282   #endif\r
283 \r
284   ReadToolbar();\r
285   ReloadToolbars();\r
286 \r
287   int i;\r
288   for (i = 0; i < kNumPanelsMax; i++)\r
289     PanelsCreated[i] = false;\r
290 \r
291   AppState.Read();\r
292   SetListSettings();\r
293   SetShowSystemMenu();\r
294   if (LastFocusedPanel >= kNumPanelsMax)\r
295     LastFocusedPanel = 0;\r
296 \r
297   CListMode listMode;\r
298   ReadListMode(listMode);\r
299   for (i = 0; i < kNumPanelsMax; i++)\r
300   {\r
301     CPanel &panel = Panels[i];\r
302     panel._ListViewMode = listMode.Panels[i];\r
303     panel._xSize = xSizes[i];\r
304     panel._flatModeForArc = ReadFlatView(i);\r
305   }\r
306   for (i = 0; i < kNumPanelsMax; i++)\r
307     if (NumPanels > 1 || i == LastFocusedPanel)\r
308     {\r
309       if (NumPanels == 1)\r
310         Panels[i]._xSize = xSizes[0] + xSizes[1];\r
311       bool archiveIsOpened2 = false;\r
312       bool encrypted2 = false;\r
313       bool mainPanel = (i == LastFocusedPanel);\r
314       RINOK(CreateOnePanel(i, mainPanel ? mainPath : L"", arcFormat, archiveIsOpened2, encrypted2));\r
315       if (mainPanel)\r
316       {\r
317         archiveIsOpened = archiveIsOpened2;\r
318         encrypted = encrypted2;\r
319       }\r
320     }\r
321   SetFocusedPanel(LastFocusedPanel);\r
322   Panels[LastFocusedPanel].SetFocusToList();\r
323   return S_OK;\r
324 }\r
325 \r
326 HRESULT CApp::SwitchOnOffOnePanel()\r
327 {\r
328   if (NumPanels == 1)\r
329   {\r
330     NumPanels++;\r
331     bool archiveIsOpened, encrypted;\r
332     RINOK(CreateOnePanel(1 - LastFocusedPanel, UString(), UString(), archiveIsOpened, encrypted));\r
333     Panels[1 - LastFocusedPanel].Enable(true);\r
334     Panels[1 - LastFocusedPanel].Show(SW_SHOWNORMAL);\r
335   }\r
336   else\r
337   {\r
338     NumPanels--;\r
339     Panels[1 - LastFocusedPanel].Enable(false);\r
340     Panels[1 - LastFocusedPanel].Show(SW_HIDE);\r
341   }\r
342   MoveSubWindows();\r
343   return S_OK;\r
344 }\r
345 \r
346 void CApp::Save()\r
347 {\r
348   AppState.Save();\r
349   CListMode listMode;\r
350   for (int i = 0; i < kNumPanelsMax; i++)\r
351   {\r
352     const CPanel &panel = Panels[i];\r
353     UString path;\r
354     if (panel._parentFolders.IsEmpty())\r
355       path = panel._currentFolderPrefix;\r
356     else\r
357       path = GetFolderPath(panel._parentFolders[0].ParentFolder);\r
358     SavePanelPath(i, path);\r
359     listMode.Panels[i] = panel.GetListViewMode();\r
360     SaveFlatView(i, panel._flatModeForArc);\r
361   }\r
362   SaveListMode(listMode);\r
363 }\r
364 \r
365 void CApp::Release()\r
366 {\r
367   // It's for unloading COM dll's: don't change it.\r
368   for (int i = 0; i < kNumPanelsMax; i++)\r
369     Panels[i].Release();\r
370 }\r
371 \r
372 // reduces path to part that exists on disk\r
373 static void ReducePathToRealFileSystemPath(UString &path)\r
374 {\r
375   while (!path.IsEmpty())\r
376   {\r
377     if (NFind::DoesDirExist(path))\r
378     {\r
379       NName::NormalizeDirPathPrefix(path);\r
380       break;\r
381     }\r
382     int pos = path.ReverseFind(WCHAR_PATH_SEPARATOR);\r
383     if (pos < 0)\r
384       path.Empty();\r
385     else\r
386     {\r
387       path = path.Left(pos + 1);\r
388       if (path.Length() == 3 && path[1] == L':')\r
389         break;\r
390       if (path.Length() > 2 && path[0] == '\\' && path[1] == '\\')\r
391       {\r
392         int nextPos = path.Find(WCHAR_PATH_SEPARATOR, 2); // pos after \\COMPNAME\r
393         if (nextPos > 0 && path.Find(WCHAR_PATH_SEPARATOR, nextPos + 1) == pos)\r
394           break;\r
395       }\r
396       path = path.Left(pos);\r
397     }\r
398   }\r
399 }\r
400 \r
401 // return true for dir\, if dir exist\r
402 static bool CheckFolderPath(const UString &path)\r
403 {\r
404   UString pathReduced = path;\r
405   ReducePathToRealFileSystemPath(pathReduced);\r
406   return (pathReduced == path);\r
407 }\r
408 \r
409 static bool IsPathAbsolute(const UString &path)\r
410 {\r
411   if (path.Length() >= 1 && path[0] == WCHAR_PATH_SEPARATOR)\r
412     return true;\r
413   #ifdef _WIN32\r
414   if (path.Length() >= 3 && path[1] == L':' && path[2] == L'\\')\r
415     return true;\r
416   #endif\r
417   return false;\r
418 }\r
419 \r
420 extern UString ConvertSizeToString(UInt64 value);\r
421 \r
422 static UString AddSizeValue(UInt64 size)\r
423 {\r
424   return MyFormatNew(IDS_FILE_SIZE, 0x02000982, ConvertSizeToString(size));\r
425 }\r
426 \r
427 static void AddValuePair1(UINT resourceID, UInt32 langID, UInt64 size, UString &s)\r
428 {\r
429   s += LangString(resourceID, langID);\r
430   s += L" ";\r
431   s += AddSizeValue(size);\r
432   s += L"\n";\r
433 }\r
434 \r
435 void AddValuePair2(UINT resourceID, UInt32 langID, UInt64 num, UInt64 size, UString &s)\r
436 {\r
437   if (num == 0)\r
438     return;\r
439   s += LangString(resourceID, langID);\r
440   s += L" ";\r
441   s += ConvertSizeToString(num);\r
442 \r
443   if (size != (UInt64)(Int64)-1)\r
444   {\r
445     s += L"    ( ";\r
446     s += AddSizeValue(size);\r
447     s += L" )";\r
448   }\r
449   s += L"\n";\r
450 }\r
451 \r
452 static void AddPropValueToSum(IFolderFolder *folder, int index, PROPID propID, UInt64 &sum)\r
453 {\r
454   if (sum == (UInt64)(Int64)-1)\r
455     return;\r
456   NCOM::CPropVariant prop;\r
457   folder->GetProperty(index, propID, &prop);\r
458   switch(prop.vt)\r
459   {\r
460     case VT_UI4:\r
461     case VT_UI8:\r
462       sum += ConvertPropVariantToUInt64(prop);\r
463       break;\r
464     default:\r
465       sum = (UInt64)(Int64)-1;\r
466   }\r
467 }\r
468 \r
469 UString CPanel::GetItemsInfoString(const CRecordVector<UInt32> &indices)\r
470 {\r
471   UString info;\r
472   UInt64 numDirs, numFiles, filesSize, foldersSize;\r
473   numDirs = numFiles = filesSize = foldersSize = 0;\r
474   int i;\r
475   for (i = 0; i < indices.Size(); i++)\r
476   {\r
477     int index = indices[i];\r
478     if (IsItemFolder(index))\r
479     {\r
480       AddPropValueToSum(_folder, index, kpidSize, foldersSize);\r
481       numDirs++;\r
482     }\r
483     else\r
484     {\r
485       AddPropValueToSum(_folder, index, kpidSize, filesSize);\r
486       numFiles++;\r
487     }\r
488   }\r
489 \r
490   AddValuePair2(IDS_FOLDERS_COLON, 0x02000321, numDirs, foldersSize, info);\r
491   AddValuePair2(IDS_FILES_COLON, 0x02000320, numFiles, filesSize, info);\r
492   int numDefined = ((foldersSize != (UInt64)(Int64)-1) && foldersSize != 0) ? 1: 0;\r
493   numDefined += ((filesSize != (UInt64)(Int64)-1) && filesSize != 0) ? 1: 0;\r
494   if (numDefined == 2)\r
495     AddValuePair1(IDS_SIZE_COLON, 0x02000322, filesSize + foldersSize, info);\r
496   \r
497   info += L"\n";\r
498   info += _currentFolderPrefix;\r
499   \r
500   for (i = 0; i < indices.Size() && i < kCopyDialog_NumInfoLines - 6; i++)\r
501   {\r
502     info += L"\n  ";\r
503     int index = indices[i];\r
504     info += GetItemRelPath(index);\r
505     if (IsItemFolder(index))\r
506       info += WCHAR_PATH_SEPARATOR;\r
507   }\r
508   if (i != indices.Size())\r
509     info += L"\n  ...";\r
510   return info;\r
511 }\r
512 \r
513 void CApp::OnCopy(bool move, bool copyToSame, int srcPanelIndex)\r
514 {\r
515   int destPanelIndex = (NumPanels <= 1) ? srcPanelIndex : (1 - srcPanelIndex);\r
516   CPanel &srcPanel = Panels[srcPanelIndex];\r
517   CPanel &destPanel = Panels[destPanelIndex];\r
518 \r
519   CPanel::CDisableTimerProcessing disableTimerProcessing1(destPanel);\r
520   CPanel::CDisableTimerProcessing disableTimerProcessing2(srcPanel);\r
521 \r
522   if (!srcPanel.DoesItSupportOperations())\r
523   {\r
524     srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);\r
525     return;\r
526   }\r
527 \r
528   CRecordVector<UInt32> indices;\r
529   UString destPath;\r
530   bool useDestPanel = false;\r
531 \r
532   {\r
533     if (copyToSame)\r
534     {\r
535       int focusedItem = srcPanel._listView.GetFocusedItem();\r
536       if (focusedItem < 0)\r
537         return;\r
538       int realIndex = srcPanel.GetRealItemIndex(focusedItem);\r
539       if (realIndex == kParentIndex)\r
540         return;\r
541       indices.Add(realIndex);\r
542       destPath = srcPanel.GetItemName(realIndex);\r
543     }\r
544     else\r
545     {\r
546       srcPanel.GetOperatedIndicesSmart(indices);\r
547       if (indices.Size() == 0)\r
548         return;\r
549       destPath = destPanel._currentFolderPrefix;\r
550       if (NumPanels == 1)\r
551         ReducePathToRealFileSystemPath(destPath);\r
552     }\r
553 \r
554     CCopyDialog copyDialog;\r
555     UStringVector copyFolders;\r
556     ReadCopyHistory(copyFolders);\r
557 \r
558     copyDialog.Strings = copyFolders;\r
559     copyDialog.Value = destPath;\r
560     \r
561     copyDialog.Title = move ?\r
562         LangString(IDS_MOVE, 0x03020202):\r
563         LangString(IDS_COPY, 0x03020201);\r
564     copyDialog.Static = move ?\r
565         LangString(IDS_MOVE_TO, 0x03020204):\r
566         LangString(IDS_COPY_TO, 0x03020203);\r
567 \r
568     copyDialog.Info = srcPanel.GetItemsInfoString(indices);\r
569 \r
570     if (copyDialog.Create(srcPanel.GetParent()) == IDCANCEL)\r
571       return;\r
572 \r
573     destPath = copyDialog.Value;\r
574 \r
575     if (destPath.IsEmpty())\r
576     {\r
577       srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);\r
578       return;\r
579     }\r
580 \r
581     if (!IsPathAbsolute(destPath))\r
582     {\r
583       if (!srcPanel.IsFSFolder())\r
584       {\r
585         srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);\r
586         return;\r
587       }\r
588       destPath = srcPanel._currentFolderPrefix + destPath;\r
589     }\r
590 \r
591     #ifndef UNDER_CE\r
592     if (destPath.Length() > 0 && destPath[0] == '\\')\r
593       if (destPath.Length() == 1 || destPath[1] != '\\')\r
594       {\r
595         srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);\r
596         return;\r
597       }\r
598     #endif\r
599 \r
600     if (indices.Size() > 1 ||\r
601         (!destPath.IsEmpty() && destPath.Back() == WCHAR_PATH_SEPARATOR) ||\r
602         NFind::DoesDirExist(destPath) ||\r
603         srcPanel.IsArcFolder())\r
604     {\r
605       NDirectory::CreateComplexDirectory(destPath);\r
606       NName::NormalizeDirPathPrefix(destPath);\r
607       if (!CheckFolderPath(destPath))\r
608       {\r
609         if (NumPanels < 2 || destPath != destPanel._currentFolderPrefix || !destPanel.DoesItSupportOperations())\r
610         {\r
611           srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);\r
612           return;\r
613         }\r
614         useDestPanel = true;\r
615       }\r
616     }\r
617     else\r
618     {\r
619       int pos = destPath.ReverseFind(WCHAR_PATH_SEPARATOR);\r
620       if (pos >= 0)\r
621       {\r
622         UString prefix = destPath.Left(pos + 1);\r
623         NDirectory::CreateComplexDirectory(prefix);\r
624         if (!CheckFolderPath(prefix))\r
625         {\r
626           srcPanel.MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);\r
627           return;\r
628         }\r
629       }\r
630     }\r
631 \r
632     AddUniqueStringToHeadOfList(copyFolders, destPath);\r
633     while (copyFolders.Size() > 20)\r
634       copyFolders.DeleteBack();\r
635     SaveCopyHistory(copyFolders);\r
636   }\r
637 \r
638   /*\r
639   if (destPath == destPanel._currentFolderPrefix)\r
640   {\r
641     if (destPanel.GetFolderTypeID() == L"PhysDrive")\r
642       useDestPanel = true;\r
643   }\r
644   */\r
645 \r
646   bool useSrcPanel = (!useDestPanel || !srcPanel.IsFsOrDrivesFolder() || destPanel.IsFSFolder());\r
647   bool useTemp = useSrcPanel && useDestPanel;\r
648   NFile::NDirectory::CTempDirectoryW tempDirectory;\r
649   UString tempDirPrefix;\r
650   if (useTemp)\r
651   {\r
652     tempDirectory.Create(kTempDirPrefix);\r
653     tempDirPrefix = tempDirectory.GetPath();\r
654     NFile::NName::NormalizeDirPathPrefix(tempDirPrefix);\r
655   }\r
656 \r
657   CSelectedState srcSelState;\r
658   CSelectedState destSelState;\r
659   srcPanel.SaveSelectedState(srcSelState);\r
660   destPanel.SaveSelectedState(destSelState);\r
661 \r
662   HRESULT result;\r
663   if (useSrcPanel)\r
664   {\r
665     UString folder = useTemp ? tempDirPrefix : destPath;\r
666     result = srcPanel.CopyTo(indices, folder, move, true, 0);\r
667     if (result != S_OK)\r
668     {\r
669       disableTimerProcessing1.Restore();\r
670       disableTimerProcessing2.Restore();\r
671       // For Password:\r
672       srcPanel.SetFocusToList();\r
673       if (result != E_ABORT)\r
674         srcPanel.MessageBoxError(result, L"Error");\r
675       return;\r
676     }\r
677   }\r
678   \r
679   if (useDestPanel)\r
680   {\r
681     UStringVector filePaths;\r
682     UString folderPrefix;\r
683     if (useTemp)\r
684       folderPrefix = tempDirPrefix;\r
685     else\r
686       folderPrefix = srcPanel._currentFolderPrefix;\r
687     filePaths.Reserve(indices.Size());\r
688     for (int i = 0; i < indices.Size(); i++)\r
689       filePaths.Add(srcPanel.GetItemRelPath(indices[i]));\r
690 \r
691     result = destPanel.CopyFrom(folderPrefix, filePaths, true, 0);\r
692 \r
693     if (result != S_OK)\r
694     {\r
695       disableTimerProcessing1.Restore();\r
696       disableTimerProcessing2.Restore();\r
697       // For Password:\r
698       srcPanel.SetFocusToList();\r
699       if (result != E_ABORT)\r
700         srcPanel.MessageBoxError(result, L"Error");\r
701       return;\r
702     }\r
703   }\r
704 \r
705   RefreshTitleAlways();\r
706   if (copyToSame || move)\r
707   {\r
708     srcPanel.RefreshListCtrl(srcSelState);\r
709   }\r
710   if (!copyToSame)\r
711   {\r
712     destPanel.RefreshListCtrl(destSelState);\r
713     srcPanel.KillSelection();\r
714   }\r
715   disableTimerProcessing1.Restore();\r
716   disableTimerProcessing2.Restore();\r
717   srcPanel.SetFocusToList();\r
718 }\r
719 \r
720 void CApp::OnSetSameFolder(int srcPanelIndex)\r
721 {\r
722   if (NumPanels <= 1)\r
723     return;\r
724   const CPanel &srcPanel = Panels[srcPanelIndex];\r
725   CPanel &destPanel = Panels[1 - srcPanelIndex];\r
726   destPanel.BindToPathAndRefresh(srcPanel._currentFolderPrefix);\r
727 }\r
728 \r
729 void CApp::OnSetSubFolder(int srcPanelIndex)\r
730 {\r
731   if (NumPanels <= 1)\r
732     return;\r
733   const CPanel &srcPanel = Panels[srcPanelIndex];\r
734   CPanel &destPanel = Panels[1 - srcPanelIndex];\r
735 \r
736   int focusedItem = srcPanel._listView.GetFocusedItem();\r
737   if (focusedItem < 0)\r
738     return;\r
739   int realIndex = srcPanel.GetRealItemIndex(focusedItem);\r
740   if (!srcPanel.IsItemFolder(realIndex))\r
741     return;\r
742 \r
743   // destPanel.BindToFolder(srcPanel._currentFolderPrefix + srcPanel.GetItemName(realIndex) + WCHAR_PATH_SEPARATOR);\r
744 \r
745   CMyComPtr<IFolderFolder> newFolder;\r
746   if (realIndex == kParentIndex)\r
747   {\r
748     if (srcPanel._folder->BindToParentFolder(&newFolder) != S_OK)\r
749       return;\r
750   }\r
751   else\r
752   {\r
753     if (srcPanel._folder->BindToFolder(realIndex, &newFolder) != S_OK)\r
754       return;\r
755   }\r
756   destPanel.CloseOpenFolders();\r
757   destPanel._folder = newFolder;\r
758   destPanel.RefreshListCtrl();\r
759 }\r
760 \r
761 /*\r
762 int CApp::GetFocusedPanelIndex() const\r
763 {\r
764   return LastFocusedPanel;\r
765   HWND hwnd = ::GetFocus();\r
766   for (;;)\r
767   {\r
768     if (hwnd == 0)\r
769       return 0;\r
770     for (int i = 0; i < kNumPanelsMax; i++)\r
771     {\r
772       if (PanelsCreated[i] &&\r
773           ((HWND)Panels[i] == hwnd || Panels[i]._listView == hwnd))\r
774         return i;\r
775     }\r
776     hwnd = GetParent(hwnd);\r
777   }\r
778 }\r
779 */\r
780 \r
781 static UString g_ToolTipBuffer;\r
782 static CSysString g_ToolTipBufferSys;\r
783 \r
784 void CApp::OnNotify(int /* ctrlID */, LPNMHDR pnmh)\r
785 {\r
786   {\r
787     if (pnmh->code == TTN_GETDISPINFO)\r
788     {\r
789       LPNMTTDISPINFO info = (LPNMTTDISPINFO)pnmh;\r
790       info->hinst = 0;\r
791       g_ToolTipBuffer.Empty();\r
792       SetButtonText((int)info->hdr.idFrom, g_ToolTipBuffer);\r
793       g_ToolTipBufferSys = GetSystemString(g_ToolTipBuffer);\r
794       info->lpszText = (LPTSTR)(LPCTSTR)g_ToolTipBufferSys;\r
795       return;\r
796     }\r
797     #ifndef _UNICODE\r
798     if (pnmh->code == TTN_GETDISPINFOW)\r
799     {\r
800       LPNMTTDISPINFOW info = (LPNMTTDISPINFOW)pnmh;\r
801       info->hinst = 0;\r
802       g_ToolTipBuffer.Empty();\r
803       SetButtonText((int)info->hdr.idFrom, g_ToolTipBuffer);\r
804       info->lpszText = (LPWSTR)(LPCWSTR)g_ToolTipBuffer;\r
805       return;\r
806     }\r
807     #endif\r
808   }\r
809 }\r
810 \r
811 void CApp::RefreshTitle(bool always)\r
812 {\r
813   UString path = GetFocusedPanel()._currentFolderPrefix;\r
814   if (path.IsEmpty())\r
815     path += LangString(IDS_APP_TITLE, 0x03000000);\r
816   if (!always && path == PrevTitle)\r
817     return;\r
818   PrevTitle = path;\r
819   NWindows::MySetWindowText(_window, path);\r
820 }\r
821 \r
822 void CApp::RefreshTitle(int panelIndex, bool always)\r
823 {\r
824   if (panelIndex != GetFocusedPanelIndex())\r
825     return;\r
826   RefreshTitle(always);\r
827 }\r