xref: /aosp_15_r20/external/lzma/CPP/7zip/UI/FileManager/Panel.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // Panel.cpp
2 
3 #include "StdAfx.h"
4 
5 #include <windowsx.h>
6 
7 #include "../../../Common/IntToString.h"
8 #include "../../../Common/StringConvert.h"
9 
10 #include "../../../Windows/ErrorMsg.h"
11 #include "../../../Windows/FileName.h"
12 #include "../../../Windows/PropVariant.h"
13 #include "../../../Windows/Thread.h"
14 
15 #include "../../PropID.h"
16 
17 #include "resource.h"
18 #include "../GUI/ExtractRes.h"
19 
20 #include "../Common/ArchiveName.h"
21 #include "../Common/CompressCall.h"
22 #include "../Common/ZipRegistry.h"
23 
24 #include "../Agent/IFolderArchive.h"
25 
26 #include "App.h"
27 #include "ExtractCallback.h"
28 #include "FSFolder.h"
29 #include "FormatUtils.h"
30 #include "LangUtils.h"
31 #include "Panel.h"
32 #include "RootFolder.h"
33 
34 #include "PropertyNameRes.h"
35 
36 using namespace NWindows;
37 using namespace NControl;
38 
39 #ifndef _UNICODE
40 extern bool g_IsNT;
41 #endif
42 
43 static const UINT_PTR kTimerID = 1;
44 static const UINT kTimerElapse = 1000;
45 
46 static DWORD kStyles[4] = { LVS_ICON, LVS_SMALLICON, LVS_LIST, LVS_REPORT };
47 
48 // static const int kCreateFolderID = 101;
49 
50 extern HINSTANCE g_hInstance;
51 
ReleasePanel()52 void CPanel::ReleasePanel()
53 {
54   Disable_Processing_Timer_Notify_StatusBar();
55   // It's for unloading COM dll's: don't change it.
56   CloseOpenFolders();
57   _sevenZipContextMenu.Release();
58   _systemContextMenu.Release();
59 }
60 
~CPanel()61 CPanel::~CPanel()
62 {
63   CloseOpenFolders();
64 }
65 
GetParent() const66 HWND CPanel::GetParent() const
67 {
68   const HWND h = CWindow2::GetParent();
69   return h ? h : _mainWindow;
70 }
71 
72 #define kClassName L"7-Zip::Panel"
73 
74 
Create(HWND mainWindow,HWND parentWindow,UINT id,const UString & currentFolderPrefix,const UString & arcFormat,CPanelCallback * panelCallback,CAppState * appState,bool needOpenArc,COpenResult & openRes)75 HRESULT CPanel::Create(HWND mainWindow, HWND parentWindow, UINT id,
76     const UString &currentFolderPrefix,
77     const UString &arcFormat,
78     CPanelCallback *panelCallback, CAppState *appState,
79     bool needOpenArc,
80     COpenResult &openRes)
81 {
82   _mainWindow = mainWindow;
83   _processTimer = true;
84   _processNotify = true;
85   _processStatusBar = true;
86 
87   _panelCallback = panelCallback;
88   _appState = appState;
89   // _index = index;
90   _baseID = id;
91   _comboBoxID = _baseID + 3;
92   _statusBarID = _comboBoxID + 1;
93 
94   UString cfp = currentFolderPrefix;
95 
96   if (!currentFolderPrefix.IsEmpty())
97     if (currentFolderPrefix[0] == L'.')
98     {
99       FString cfpF;
100       if (NFile::NDir::MyGetFullPathName(us2fs(currentFolderPrefix), cfpF))
101         cfp = fs2us(cfpF);
102     }
103 
104   RINOK(BindToPath(cfp, arcFormat, openRes))
105 
106   if (needOpenArc && !openRes.ArchiveIsOpened)
107     return S_OK;
108 
109   if (!CreateEx(0, kClassName, NULL, WS_CHILD | WS_VISIBLE,
110       0, 0, _xSize, 260,
111       parentWindow, (HMENU)(UINT_PTR)id, g_hInstance))
112     return E_FAIL;
113   PanelCreated = true;
114 
115   return S_OK;
116 }
117 
118 // extern UInt32 g_NumMessages;
119 
OnMessage(UINT message,WPARAM wParam,LPARAM lParam)120 LRESULT CPanel::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
121 {
122   // g_NumMessages++;
123   switch (message)
124   {
125     case kShiftSelectMessage:
126       OnShiftSelectMessage();
127       return 0;
128     case kReLoadMessage:
129       RefreshListCtrl(_selectedState);
130       return 0;
131     case kSetFocusToListView:
132       _listView.SetFocus();
133       return 0;
134     case kOpenItemChanged:
135       return OnOpenItemChanged(lParam);
136     case kRefresh_StatusBar:
137       if (_processStatusBar)
138         Refresh_StatusBar();
139       return 0;
140     #ifdef UNDER_CE
141     case kRefresh_HeaderComboBox:
142       LoadFullPathAndShow();
143       return 0;
144     #endif
145     case WM_TIMER:
146       OnTimer();
147       return 0;
148     case WM_CONTEXTMENU:
149       if (OnContextMenu(HANDLE(wParam), GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)))
150         return 0;
151       break;
152     /*
153     case WM_DROPFILES:
154       CompressDropFiles(HDROP(wParam));
155       return 0;
156     */
157   }
158   return CWindow2::OnMessage(message, wParam, lParam);
159 }
160 
OnMessage(UINT message,WPARAM wParam,LPARAM lParam)161 LRESULT CMyListView::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
162 {
163   if (message == WM_CHAR)
164   {
165     UINT scanCode = (UINT)((lParam >> 16) & 0xFF);
166     bool extended = ((lParam & 0x1000000) != 0);
167     UINT virtualKey = MapVirtualKey(scanCode, 1);
168     if (virtualKey == VK_MULTIPLY || virtualKey == VK_ADD ||
169         virtualKey == VK_SUBTRACT)
170       return 0;
171     if ((wParam == '/' && extended)
172         || wParam == '\\' || wParam == '/')
173     {
174       _panel->OpenDrivesFolder();
175       return 0;
176     }
177   }
178   else if (message == WM_SYSCHAR)
179   {
180     // For Alt+Enter Beep disabling
181     UINT scanCode = (UINT)(lParam >> 16) & 0xFF;
182     UINT virtualKey = MapVirtualKey(scanCode, 1);
183     if (virtualKey == VK_RETURN || virtualKey == VK_MULTIPLY ||
184         virtualKey == VK_ADD || virtualKey == VK_SUBTRACT)
185       return 0;
186   }
187   /*
188   else if (message == WM_SYSKEYDOWN)
189   {
190     // return 0;
191   }
192   */
193   else if (message == WM_KEYDOWN)
194   {
195     bool alt = IsKeyDown(VK_MENU);
196     bool ctrl = IsKeyDown(VK_CONTROL);
197     bool shift = IsKeyDown(VK_SHIFT);
198     switch (wParam)
199     {
200       /*
201       case VK_RETURN:
202       {
203         if (shift && !alt && !ctrl)
204         {
205           _panel->OpenSelectedItems(false);
206           return 0;
207         }
208         break;
209       }
210       */
211       case VK_NEXT:
212       {
213         if (ctrl && !alt && !shift)
214         {
215           _panel->OpenFocusedItemAsInternal();
216           return 0;
217         }
218         break;
219       }
220       case VK_PRIOR:
221       if (ctrl && !alt && !shift)
222       {
223         _panel->OpenParentFolder();
224         return 0;
225       }
226     }
227   }
228   #ifdef UNDER_CE
229   else if (message == WM_KEYUP)
230   {
231     if (wParam == VK_F2) // it's VK_TSOFT2
232     {
233       // Activate Menu
234       ::PostMessage(g_HWND, WM_SYSCOMMAND, SC_KEYMENU, 0);
235       return 0;
236     }
237   }
238   #endif
239   else if (message == WM_SETFOCUS)
240   {
241     _panel->_lastFocusedIsList = true;
242     _panel->_panelCallback->PanelWasFocused();
243   }
244   return CListView2::OnMessage(message, wParam, lParam);
245 }
246 
247 /*
248 static LRESULT APIENTRY ComboBoxSubclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
249 {
250   CWindow tempDialog(hwnd);
251   CMyComboBox *w = (CMyComboBox *)(tempDialog.GetUserDataLongPtr());
252   if (w == NULL)
253     return 0;
254   return w->OnMessage(message, wParam, lParam);
255 }
256 
257 LRESULT CMyComboBox::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
258 {
259   return CallWindowProc(_origWindowProc, *this, message, wParam, lParam);
260 }
261 */
262 
263 #ifndef UNDER_CE
264 
ComboBoxEditSubclassProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)265 static LRESULT APIENTRY ComboBoxEditSubclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
266 {
267   CWindow tempDialog(hwnd);
268   CMyComboBoxEdit *w = (CMyComboBoxEdit *)(tempDialog.GetUserDataLongPtr());
269   if (w == NULL)
270     return 0;
271   return w->OnMessage(message, wParam, lParam);
272 }
273 
274 #endif
275 
OnMessage(UINT message,WPARAM wParam,LPARAM lParam)276 LRESULT CMyComboBoxEdit::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
277 {
278   // See MSDN / Subclassing a Combo Box / Creating a Combo-box Toolbar
279   switch (message)
280   {
281     case WM_SYSKEYDOWN:
282       switch (wParam)
283       {
284         case VK_F1:
285         case VK_F2:
286         {
287           // check ALT
288           if ((lParam & (1<<29)) == 0)
289             break;
290           bool alt = IsKeyDown(VK_MENU);
291           bool ctrl = IsKeyDown(VK_CONTROL);
292           bool shift = IsKeyDown(VK_SHIFT);
293           if (alt && !ctrl && !shift)
294           {
295             _panel->_panelCallback->SetFocusToPath(wParam == VK_F1 ? 0 : 1);
296             return 0;
297           }
298           break;
299         }
300       }
301       break;
302     case WM_KEYDOWN:
303       switch (wParam)
304       {
305         case VK_TAB:
306           // SendMessage(hwndMain, WM_ENTER, 0, 0);
307           _panel->SetFocusToList();
308           return 0;
309         case VK_F9:
310         {
311           bool alt = IsKeyDown(VK_MENU);
312           bool ctrl = IsKeyDown(VK_CONTROL);
313           bool shift = IsKeyDown(VK_SHIFT);
314           if (!alt && !ctrl && !shift)
315           {
316             g_App.SwitchOnOffOnePanel();
317             return 0;
318           }
319           break;
320         }
321         case 'W':
322         {
323           bool ctrl = IsKeyDown(VK_CONTROL);
324           if (ctrl)
325           {
326             PostMessage(g_HWND, WM_COMMAND, IDCLOSE, 0);
327             return 0;
328           }
329           break;
330         }
331       }
332       break;
333     case WM_CHAR:
334       switch (wParam)
335       {
336         case VK_TAB:
337         case VK_ESCAPE:
338           return 0;
339       }
340   }
341   #ifndef _UNICODE
342   if (g_IsNT)
343     return CallWindowProcW(_origWindowProc, *this, message, wParam, lParam);
344   else
345   #endif
346     return CallWindowProc(_origWindowProc, *this, message, wParam, lParam);
347 }
348 
349 
350 /*
351   REBARBANDINFO in vista (_WIN32_WINNT >= 0x0600) has additional fields
352   we want 2000/xp compatibility.
353   so we must use reduced structure, if we compile with (_WIN32_WINNT >= 0x0600)
354   Also there are additional fields, if (_WIN32_IE >= 0x0400).
355     but (_WIN32_IE >= 0x0400) is expected.
356   note:
357   in x64 (64-bit):
358   {
359     (108 == REBARBANDINFO_V6_SIZE)
360     (112 == sizeof(REBARBANDINFO) // for (_WIN32_WINNT <  0x0600)
361     (128 == sizeof(REBARBANDINFO) // for (_WIN32_WINNT >= 0x0600)
362     there is difference in sizes, because REBARBANDINFO size was
363     not aligned for 8-bytes in (_WIN32_WINNT < 0x0600).
364     We hope that WinVista+ support support both (108 and 112) sizes.
365     But does WinXP-x64 support (108 == REBARBANDINFO_V6_SIZE)?
366     {
367          96   LPARAM  lParam;
368         104   UINT    cxHeader;
369       #if (_WIN32_WINNT >= 0x0600)
370         108   RECT    rcChevronLocation;
371         124   UINT    uChevronState;
372       #endif
373     }
374 */
375 
376 #if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) && defined(REBARBANDINFOA_V6_SIZE)
377   #define my_compatib_REBARBANDINFO_size  REBARBANDINFO_V6_SIZE
378 #else
379   #define my_compatib_REBARBANDINFO_size  sizeof(REBARBANDINFO)
380 #endif
381 
382 
OnCreate(CREATESTRUCT *)383 bool CPanel::OnCreate(CREATESTRUCT * /* createStruct */)
384 {
385   // _virtualMode = false;
386   // _sortIndex = 0;
387   _sortID = kpidName;
388   _ascending = true;
389   _lastFocusedIsList = true;
390 
391   DWORD style = WS_CHILD | WS_VISIBLE; //  | WS_BORDER ; // | LVS_SHAREIMAGELISTS; //  | LVS_SHOWSELALWAYS;
392 
393   style |= LVS_SHAREIMAGELISTS;
394   // style  |= LVS_AUTOARRANGE;
395   style |= WS_CLIPCHILDREN;
396   style |= WS_CLIPSIBLINGS;
397 
398   const UInt32 kNumListModes = Z7_ARRAY_SIZE(kStyles);
399   if (_listViewMode >= kNumListModes)
400     _listViewMode = kNumListModes - 1;
401 
402   style |= kStyles[_listViewMode]
403     | WS_TABSTOP
404     | LVS_EDITLABELS;
405   if (_mySelectMode)
406     style |= LVS_SINGLESEL;
407 
408   /*
409   if (_virtualMode)
410     style |= LVS_OWNERDATA;
411   */
412 
413   DWORD exStyle;
414   exStyle = WS_EX_CLIENTEDGE;
415 
416   if (!_listView.CreateEx(exStyle, style, 0, 0, 116, 260,
417       *this, (HMENU)(UINT_PTR)(_baseID + 1), g_hInstance, NULL))
418     return false;
419 
420   _listView.SetUnicodeFormat();
421   _listView._panel = this;
422   _listView.SetWindowProc();
423 
424   _listView.SetImageList(Shell_Get_SysImageList_smallIcons(true), LVSIL_SMALL);
425   _listView.SetImageList(Shell_Get_SysImageList_smallIcons(false), LVSIL_NORMAL);
426 
427   // _exStyle |= LVS_EX_HEADERDRAGDROP;
428   // DWORD extendedStyle = _listView.GetExtendedListViewStyle();
429   // extendedStyle |= _exStyle;
430   //  _listView.SetExtendedListViewStyle(extendedStyle);
431   SetExtendedStyle();
432 
433   _listView.Show(SW_SHOW);
434   _listView.InvalidateRect(NULL, true);
435   _listView.Update();
436 
437   // Ensure that the common control DLL is loaded.
438   INITCOMMONCONTROLSEX icex;
439 
440   icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
441   icex.dwICC  = ICC_BAR_CLASSES;
442   InitCommonControlsEx(&icex);
443 
444   const TBBUTTON tbb[] =
445   {
446     // {0, 0, TBSTATE_ENABLED, BTNS_SEP, 0L, 0},
447     {VIEW_PARENTFOLDER, kParentFolderID, TBSTATE_ENABLED, BTNS_BUTTON, { 0, 0 }, 0, 0 },
448     // {0, 0, TBSTATE_ENABLED, BTNS_SEP, 0L, 0},
449     // {VIEW_NEWFOLDER, kCreateFolderID, TBSTATE_ENABLED, BTNS_BUTTON, 0L, 0},
450   };
451 
452 #ifdef Z7_USE_DYN_ComCtl32Version
453   if (g_ComCtl32Version >= MAKELONG(71, 4))
454 #endif
455   {
456     icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
457     icex.dwICC  = ICC_COOL_CLASSES | ICC_BAR_CLASSES;
458     InitCommonControlsEx(&icex);
459 
460     // if there is no CCS_NOPARENTALIGN, there is space of some pixels after rebar (Incorrect GetWindowRect ?)
461 
462     _headerReBar.Attach(::CreateWindowEx(WS_EX_TOOLWINDOW,
463       REBARCLASSNAME,
464       NULL, WS_VISIBLE | WS_BORDER | WS_CHILD |
465       WS_CLIPCHILDREN | WS_CLIPSIBLINGS
466       | CCS_NODIVIDER
467       | CCS_NOPARENTALIGN
468       | CCS_TOP
469       | RBS_VARHEIGHT
470       | RBS_BANDBORDERS
471       ,0,0,0,0, *this, NULL, g_hInstance, NULL));
472   }
473 
474   DWORD toolbarStyle =  WS_CHILD | WS_VISIBLE ;
475   if (_headerReBar)
476   {
477     toolbarStyle |= 0
478       // | WS_CLIPCHILDREN
479       // | WS_CLIPSIBLINGS
480 
481       | TBSTYLE_TOOLTIPS
482       | CCS_NODIVIDER
483       | CCS_NORESIZE
484       | TBSTYLE_FLAT
485       ;
486   }
487 
488   _headerToolBar.Attach(::CreateToolbarEx ((*this), toolbarStyle,
489       _baseID + 2, 11,
490       (HINSTANCE)HINST_COMMCTRL,
491       IDB_VIEW_SMALL_COLOR,
492       (LPCTBBUTTON)&tbb, Z7_ARRAY_SIZE(tbb),
493       0, 0, 0, 0, sizeof (TBBUTTON)));
494 
495   #ifndef UNDER_CE
496   // Load ComboBoxEx class
497   icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
498   icex.dwICC = ICC_USEREX_CLASSES;
499   InitCommonControlsEx(&icex);
500   #endif
501 
502   _headerComboBox.CreateEx(0,
503       #ifdef UNDER_CE
504       WC_COMBOBOXW
505       #else
506       WC_COMBOBOXEXW
507       #endif
508       , NULL,
509     WS_BORDER | WS_VISIBLE |WS_CHILD | CBS_DROPDOWN | CBS_AUTOHSCROLL,
510       0, 0, 100, 620,
511       (_headerReBar ? _headerToolBar : (HWND)*this),
512       (HMENU)(UINT_PTR)(_comboBoxID),
513       g_hInstance, NULL);
514 
515 #ifndef UNDER_CE
516   _headerComboBox.SetUnicodeFormat(true);
517   _headerComboBox.SetImageList(Shell_Get_SysImageList_smallIcons(true));
518   _headerComboBox.SetExtendedStyle(CBES_EX_PATHWORDBREAKPROC, CBES_EX_PATHWORDBREAKPROC);
519   /*
520   _headerComboBox.SetUserDataLongPtr(LONG_PTR(&_headerComboBox));
521   _headerComboBox._panel = this;
522   _headerComboBox._origWindowProc =
523       (WNDPROC)_headerComboBox.SetLongPtr(GWLP_WNDPROC,
524       LONG_PTR(ComboBoxSubclassProc));
525   */
526   _comboBoxEdit.Attach(_headerComboBox.GetEditControl());
527   // _comboBoxEdit.SendMessage(CCM_SETUNICODEFORMAT, (WPARAM)(BOOL)TRUE, 0);
528   _comboBoxEdit.SetUserDataLongPtr(LONG_PTR(&_comboBoxEdit));
529   _comboBoxEdit._panel = this;
530    #ifndef _UNICODE
531    if (g_IsNT)
532      _comboBoxEdit._origWindowProc =
533       (WNDPROC)_comboBoxEdit.SetLongPtrW(GWLP_WNDPROC, LONG_PTR(ComboBoxEditSubclassProc));
534    else
535    #endif
536      _comboBoxEdit._origWindowProc =
537       (WNDPROC)_comboBoxEdit.SetLongPtr(GWLP_WNDPROC, LONG_PTR(ComboBoxEditSubclassProc));
538 #endif
539 
540   if (_headerReBar)
541   {
542     REBARINFO     rbi;
543     rbi.cbSize = sizeof(REBARINFO);  // Required when using this struct.
544     rbi.fMask  = 0;
545     rbi.himl   = (HIMAGELIST)NULL;
546     _headerReBar.SetBarInfo(&rbi);
547 
548     // Send the TB_BUTTONSTRUCTSIZE message, which is required for
549     // backward compatibility.
550     // _headerToolBar.SendMessage(TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
551     SIZE size;
552     _headerToolBar.GetMaxSize(&size);
553 
554     REBARBANDINFO rbBand;
555     memset(&rbBand, 0, sizeof(rbBand));
556     // rbBand.cbSize = sizeof(rbBand);  // for debug
557     // rbBand.cbSize = REBARBANDINFO_V3_SIZE; // for debug
558     rbBand.cbSize = my_compatib_REBARBANDINFO_size;
559     rbBand.fMask = RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE;
560     rbBand.fStyle = RBBS_NOGRIPPER;
561     rbBand.cxMinChild = (UINT)size.cx;
562     rbBand.cyMinChild = (UINT)size.cy;
563     rbBand.cyChild = (UINT)size.cy;
564     rbBand.cx = (UINT)size.cx;
565     rbBand.hwndChild  = _headerToolBar;
566     _headerReBar.InsertBand(-1, &rbBand);
567 
568     RECT rc;
569     ::GetWindowRect(_headerComboBox, &rc);
570     rbBand.cxMinChild = 30;
571     rbBand.cyMinChild = (UINT)(rc.bottom - rc.top);
572     rbBand.cx = 1000;
573     rbBand.hwndChild  = _headerComboBox;
574     _headerReBar.InsertBand(-1, &rbBand);
575     // _headerReBar.MaximizeBand(1, false);
576   }
577 
578   _statusBar.Create(WS_CHILD | WS_VISIBLE, L"Status", (*this), _statusBarID);
579   // _statusBar2.Create(WS_CHILD | WS_VISIBLE, L"Status", (*this), _statusBarID + 1);
580 
581   const int sizes[] = {220, 320, 420, -1};
582   _statusBar.SetParts(4, sizes);
583   // _statusBar2.SetParts(5, sizes);
584 
585   /*
586   RECT rect;
587   GetClientRect(&rect);
588   OnSize(0, RECT_SIZE_X(rect), RECT_SIZE_Y(rect));
589   */
590 
591   SetTimer(kTimerID, kTimerElapse);
592 
593   // InitListCtrl();
594   RefreshListCtrl();
595 
596   return true;
597 }
598 
OnDestroy()599 void CPanel::OnDestroy()
600 {
601   SaveListViewInfo();
602   CWindow2::OnDestroy();
603 }
604 
ChangeWindowSize(int xSize,int ySize)605 void CPanel::ChangeWindowSize(int xSize, int ySize)
606 {
607   if (!(HWND)*this)
608     return;
609   int kHeaderSize;
610   int kStatusBarSize;
611   // int kStatusBar2Size;
612   RECT rect;
613   if (_headerReBar)
614     _headerReBar.GetWindowRect(&rect);
615   else
616     _headerToolBar.GetWindowRect(&rect);
617 
618   kHeaderSize = RECT_SIZE_Y(rect);
619 
620   _statusBar.GetWindowRect(&rect);
621   kStatusBarSize = RECT_SIZE_Y(rect);
622 
623   // _statusBar2.GetWindowRect(&rect);
624   // kStatusBar2Size = RECT_SIZE_Y(rect);
625 
626   int yListViewSize = MyMax(ySize - kHeaderSize - kStatusBarSize, 0);
627   const int kStartXPos = 32;
628   if (_headerReBar)
629   {
630   }
631   else
632   {
633     _headerToolBar.Move(0, 0, xSize, 0);
634     _headerComboBox.Move(kStartXPos, 2,
635         MyMax(xSize - kStartXPos - 10, kStartXPos), 0);
636   }
637   _listView.Move(0, kHeaderSize, xSize, yListViewSize);
638   _statusBar.Move(0, kHeaderSize + yListViewSize, xSize, kStatusBarSize);
639   // _statusBar2.MoveWindow(0, kHeaderSize + yListViewSize + kStatusBarSize, xSize, kStatusBar2Size);
640   // _statusBar.MoveWindow(0, 100, xSize, kStatusBarSize);
641   // _statusBar2.MoveWindow(0, 200, xSize, kStatusBar2Size);
642 }
643 
OnSize(WPARAM,int xSize,int ySize)644 bool CPanel::OnSize(WPARAM /* wParam */, int xSize, int ySize)
645 {
646   if (!(HWND)*this)
647     return true;
648   if (_headerReBar)
649     _headerReBar.Move(0, 0, xSize, 0);
650   ChangeWindowSize(xSize, ySize);
651   return true;
652 }
653 
OnNotifyReBar(LPNMHDR header,LRESULT &)654 bool CPanel::OnNotifyReBar(LPNMHDR header, LRESULT & /* result */)
655 {
656   switch (header->code)
657   {
658     case RBN_HEIGHTCHANGE:
659     {
660       RECT rect;
661       GetWindowRect(&rect);
662       ChangeWindowSize(RECT_SIZE_X(rect), RECT_SIZE_Y(rect));
663       return false;
664     }
665   }
666   return false;
667 }
668 
669 /*
670 UInt32 g_OnNotify = 0;
671 UInt32 g_LVIF_TEXT = 0;
672 UInt32 g_Time = 0;
673 
674 void Print_OnNotify(const char *name)
675 {
676   char s[256];
677   DWORD tim = GetTickCount();
678   sprintf(s,
679       "Time = %7u ms, Notify = %9u, TEXT = %9u, %s",
680       tim - g_Time,
681       g_OnNotify,
682       g_LVIF_TEXT,
683       name);
684   g_Time = tim;
685   OutputDebugStringA(s);
686   g_OnNotify = 0;
687   g_LVIF_TEXT = 0;
688 }
689 */
690 
OnNotify(UINT,LPNMHDR header,LRESULT & result)691 bool CPanel::OnNotify(UINT /* controlID */, LPNMHDR header, LRESULT &result)
692 {
693   /*
694   g_OnNotify++;
695 
696   if (header->hwndFrom == _listView)
697   {
698     if (header->code == LVN_GETDISPINFOW)
699     {
700       LV_DISPINFOW *dispInfo = (LV_DISPINFOW *)header;
701         if ((dispInfo->item.mask & LVIF_TEXT))
702           g_LVIF_TEXT++;
703     }
704   }
705   */
706 
707   if (!_processNotify)
708     return false;
709 
710   if (header->hwndFrom == _headerComboBox)
711     return OnNotifyComboBox(header, result);
712   else if (header->hwndFrom == _headerReBar)
713     return OnNotifyReBar(header, result);
714   else if (header->hwndFrom == _listView)
715     return OnNotifyList(header, result);
716   else if (::GetParent(header->hwndFrom) == _listView)
717   {
718     // NMHDR:code is UINT
719     // NM_RCLICK is unsigned in windows sdk
720     // NM_RCLICK is int      in MinGW
721     if (header->code == (UINT)NM_RCLICK)
722       return OnRightClick((MY_NMLISTVIEW_NMITEMACTIVATE *)header, result);
723   }
724   return false;
725 }
726 
OnCommand(unsigned code,unsigned itemID,LPARAM lParam,LRESULT & result)727 bool CPanel::OnCommand(unsigned code, unsigned itemID, LPARAM lParam, LRESULT &result)
728 {
729   if (itemID == kParentFolderID)
730   {
731     OpenParentFolder();
732     result = 0;
733     return true;
734   }
735   /*
736   if (itemID == kCreateFolderID)
737   {
738     CreateFolder();
739     result = 0;
740     return true;
741   }
742   */
743   if (itemID == _comboBoxID)
744   {
745     if (OnComboBoxCommand(code, lParam, result))
746       return true;
747   }
748   return CWindow2::OnCommand(code, itemID, lParam, result);
749 }
750 
751 
752 
753 /*
754 void CPanel::MessageBox_Info(LPCWSTR message, LPCWSTR caption) const
755   { ::MessageBoxW((HWND)*this, message, caption, MB_OK); }
756 void CPanel::MessageBox_Warning(LPCWSTR message) const
757   { ::MessageBoxW((HWND)*this, message, L"7-Zip", MB_OK | MB_ICONWARNING); }
758 */
759 
MessageBox_Error_Caption(LPCWSTR message,LPCWSTR caption) const760 void CPanel::MessageBox_Error_Caption(LPCWSTR message, LPCWSTR caption) const
761   { ::MessageBoxW((HWND)*this, message, caption, MB_OK | MB_ICONSTOP); }
762 
MessageBox_Error(LPCWSTR message) const763 void CPanel::MessageBox_Error(LPCWSTR message) const
764   { MessageBox_Error_Caption(message, L"7-Zip"); }
765 
ErrorHResult_To_Message(HRESULT errorCode)766 static UString ErrorHResult_To_Message(HRESULT errorCode)
767 {
768   if (errorCode == 0)
769     errorCode = E_FAIL;
770   return HResultToMessage(errorCode);
771 }
772 
MessageBox_Error_HRESULT_Caption(HRESULT errorCode,LPCWSTR caption) const773 void CPanel::MessageBox_Error_HRESULT_Caption(HRESULT errorCode, LPCWSTR caption) const
774 {
775   MessageBox_Error_Caption(ErrorHResult_To_Message(errorCode), caption);
776 }
777 
MessageBox_Error_HRESULT(HRESULT errorCode) const778 void CPanel::MessageBox_Error_HRESULT(HRESULT errorCode) const
779   { MessageBox_Error_HRESULT_Caption(errorCode, L"7-Zip"); }
780 
MessageBox_Error_2Lines_Message_HRESULT(LPCWSTR message,HRESULT errorCode) const781 void CPanel::MessageBox_Error_2Lines_Message_HRESULT(LPCWSTR message, HRESULT errorCode) const
782 {
783   UString m = message;
784   m.Add_LF();
785   m += ErrorHResult_To_Message(errorCode);
786   MessageBox_Error(m);
787 }
788 
MessageBox_LastError(LPCWSTR caption) const789 void CPanel::MessageBox_LastError(LPCWSTR caption) const
790   { MessageBox_Error_HRESULT_Caption(GetLastError_noZero_HRESULT(), caption); }
791 
MessageBox_LastError() const792 void CPanel::MessageBox_LastError() const
793   { MessageBox_LastError(L"7-Zip"); }
794 
MessageBox_Error_LangID(UINT resourceID) const795 void CPanel::MessageBox_Error_LangID(UINT resourceID) const
796   { MessageBox_Error(LangString(resourceID)); }
797 
MessageBox_Error_UnsupportOperation() const798 void CPanel::MessageBox_Error_UnsupportOperation() const
799   { MessageBox_Error_LangID(IDS_OPERATION_IS_NOT_SUPPORTED); }
800 
801 
802 
803 
SetFocusToList()804 void CPanel::SetFocusToList()
805 {
806   _listView.SetFocus();
807   // SetCurrentPathText();
808 }
809 
SetFocusToLastRememberedItem()810 void CPanel::SetFocusToLastRememberedItem()
811 {
812   if (_lastFocusedIsList)
813     SetFocusToList();
814   else
815     _headerComboBox.SetFocus();
816 }
817 
GetFolderTypeID() const818 UString CPanel::GetFolderTypeID() const
819 {
820   {
821     NCOM::CPropVariant prop;
822     if (_folder->GetFolderProperty(kpidType, &prop) == S_OK)
823       if (prop.vt == VT_BSTR)
824         return (const wchar_t *)prop.bstrVal;
825   }
826   return UString();
827 }
828 
IsFolderTypeEqTo(const char * s) const829 bool CPanel::IsFolderTypeEqTo(const char *s) const
830 {
831   return StringsAreEqual_Ascii(GetFolderTypeID(), s);
832 }
833 
IsRootFolder() const834 bool CPanel::IsRootFolder() const { return IsFolderTypeEqTo("RootFolder"); }
IsFSFolder() const835 bool CPanel::IsFSFolder() const { return IsFolderTypeEqTo("FSFolder"); }
IsFSDrivesFolder() const836 bool CPanel::IsFSDrivesFolder() const { return IsFolderTypeEqTo("FSDrives"); }
IsAltStreamsFolder() const837 bool CPanel::IsAltStreamsFolder() const { return IsFolderTypeEqTo("AltStreamsFolder"); }
IsArcFolder() const838 bool CPanel::IsArcFolder() const
839 {
840   return GetFolderTypeID().IsPrefixedBy_Ascii_NoCase("7-Zip");
841 }
842 
IsHashFolder() const843 bool CPanel::IsHashFolder() const
844 {
845   if (_folder)
846   {
847     NCOM::CPropVariant prop;
848     if (_folder->GetFolderProperty(kpidIsHash, &prop) == S_OK)
849       if (prop.vt == VT_BOOL)
850         return VARIANT_BOOLToBool(prop.boolVal);
851   }
852   return false;
853 }
854 
GetFsPath() const855 UString CPanel::GetFsPath() const
856 {
857   if (IsFSDrivesFolder() && !IsDeviceDrivesPrefix() && !IsSuperDrivesPrefix())
858     return UString();
859   return _currentFolderPrefix;
860 }
861 
GetDriveOrNetworkPrefix() const862 UString CPanel::GetDriveOrNetworkPrefix() const
863 {
864   if (!IsFSFolder())
865     return UString();
866   UString drive = GetFsPath();
867   drive.DeleteFrom(NFile::NName::GetRootPrefixSize(drive));
868   return drive;
869 }
870 
SetListViewMode(UInt32 index)871 void CPanel::SetListViewMode(UInt32 index)
872 {
873   if (index >= 4)
874     return;
875   _listViewMode = index;
876   const LONG_PTR oldStyle = _listView.GetStyle();
877   const DWORD newStyle = kStyles[index];
878 
879   // DWORD tickCount1 = GetTickCount();
880   if ((oldStyle & LVS_TYPEMASK) != (LONG_PTR)newStyle)
881     _listView.SetStyle((oldStyle & ~(LONG_PTR)(DWORD)LVS_TYPEMASK) | (LONG_PTR)newStyle);
882   // RefreshListCtrlSaveFocused();
883   /*
884   DWORD tickCount2 = GetTickCount();
885   char s[256];
886   sprintf(s, "SetStyle = %5d",
887       tickCount2 - tickCount1
888       );
889   OutputDebugStringA(s);
890   */
891 
892 }
893 
ChangeFlatMode()894 void CPanel::ChangeFlatMode()
895 {
896   _flatMode = !_flatMode;
897   if (!_parentFolders.IsEmpty())
898     _flatModeForArc = _flatMode;
899   else
900     _flatModeForDisk = _flatMode;
901   RefreshListCtrl_SaveFocused();
902 }
903 
904 /*
905 void CPanel::Change_ShowNtfsStrems_Mode()
906 {
907   _showNtfsStrems_Mode = !_showNtfsStrems_Mode;
908   if (!_parentFolders.IsEmpty())
909     _showNtfsStrems_ModeForArc = _showNtfsStrems_Mode;
910   else
911     _showNtfsStrems_ModeForDisk = _showNtfsStrems_Mode;
912   RefreshListCtrlSaveFocused();
913 }
914 */
915 
Post_Refresh_StatusBar()916 void CPanel::Post_Refresh_StatusBar()
917 {
918   if (_processStatusBar)
919     PostMsg(kRefresh_StatusBar);
920 }
921 
AddToArchive()922 void CPanel::AddToArchive()
923 {
924   if (!Is_IO_FS_Folder())
925   {
926     MessageBox_Error_UnsupportOperation();
927     return;
928   }
929   CRecordVector<UInt32> indices;
930   Get_ItemIndices_Operated(indices);
931   if (indices.Size() == 0)
932   {
933     MessageBox_Error_LangID(IDS_SELECT_FILES);
934     return;
935   }
936   UString destCurDirPrefix = GetFsPath();
937   if (IsFSDrivesFolder())
938     destCurDirPrefix = ROOT_FS_FOLDER;
939   UStringVector names;
940   GetFilePaths(indices, names);
941   UString baseName;
942   const UString arcName = CreateArchiveName(names,
943       false, // isHash
944       NULL,  // CFileInfo *fi
945       baseName);
946   const HRESULT res = CompressFiles(destCurDirPrefix, arcName, L"",
947       true,   // addExtension
948       names,
949       false,  // email
950       true,   // showDialog
951       false); // waitFinish
952   if (res != S_OK)
953   {
954     if (destCurDirPrefix.Len() >= MAX_PATH)
955       MessageBox_Error_LangID(IDS_MESSAGE_UNSUPPORTED_OPERATION_FOR_LONG_PATH_FOLDER);
956   }
957   // KillSelection();
958 }
959 
960 // function from ContextMenu.cpp
961 UString GetSubFolderNameForExtract(const UString &arcPath);
962 
GetSubFolderNameForExtract2(const UString & arcPath)963 static UString GetSubFolderNameForExtract2(const UString &arcPath)
964 {
965   int slashPos = arcPath.ReverseFind_PathSepar();
966   UString s;
967   UString name = arcPath;
968   if (slashPos >= 0)
969   {
970     s = arcPath.Left((unsigned)(slashPos + 1));
971     name = arcPath.Ptr((unsigned)(slashPos + 1));
972   }
973   s += GetSubFolderNameForExtract(name);
974   return s;
975 }
976 
977 
FindDir_InOperatedList(const CRecordVector<UInt32> & operatedIndices) const978 int CPanel::FindDir_InOperatedList(const CRecordVector<UInt32> &operatedIndices) const
979 {
980   const bool *isDirVector = _isDirVector.ConstData();
981   const UInt32 *indices = operatedIndices.ConstData();
982   const unsigned numItems = operatedIndices.Size();
983   for (unsigned i = 0; i < numItems; i++)
984     if (isDirVector[indices[i]])
985       return (int)i;
986   return -1;
987 }
988 
989 
GetFilePaths(const CRecordVector<UInt32> & operatedIndices,UStringVector & paths) const990 void CPanel::GetFilePaths(const CRecordVector<UInt32> &operatedIndices, UStringVector &paths) const
991 {
992   paths.ClearAndReserve(operatedIndices.Size());
993   UString path = GetFsPath();
994   const unsigned prefixLen = path.Len();
995   const UInt32 *indices = operatedIndices.ConstData();
996   const unsigned numItems = operatedIndices.Size();
997   // for (unsigned y = 0; y < 10000; y++, paths.Clear())
998   for (unsigned i = 0; i < numItems; i++)
999   {
1000     path.DeleteFrom(prefixLen);
1001     Add_ItemRelPath2_To_String(indices[i], path);
1002     // ODS_U(path)
1003     paths.AddInReserved(path);
1004   }
1005 }
1006 
1007 
ExtractArchives()1008 void CPanel::ExtractArchives()
1009 {
1010   if (!_parentFolders.IsEmpty())
1011   {
1012     _panelCallback->OnCopy(false, false);
1013     return;
1014   }
1015   CRecordVector<UInt32> indices;
1016   Get_ItemIndices_Operated(indices);
1017   if (indices.IsEmpty() || FindDir_InOperatedList(indices) != -1)
1018   {
1019     MessageBox_Error_LangID(IDS_SELECT_FILES);
1020     return;
1021   }
1022   UStringVector paths;
1023   GetFilePaths(indices, paths);
1024   UString outFolder = GetFsPath();
1025   if (indices.Size() == 1)
1026     outFolder += GetSubFolderNameForExtract2(GetItemRelPath(indices[0]));
1027   else
1028     outFolder.Add_Char('*');
1029   outFolder.Add_PathSepar();
1030 
1031   CContextMenuInfo ci;
1032   ci.Load();
1033 
1034   ::ExtractArchives(paths, outFolder
1035       , true   // showDialog
1036       , false  // elimDup
1037       , ci.WriteZone
1038       );
1039 }
1040 
1041 /*
1042 static void AddValuePair(UINT resourceID, UInt64 value, UString &s)
1043 {
1044   AddLangString(s, resourceID);
1045   char sz[32];
1046   s += ": ";
1047   ConvertUInt64ToString(value, sz);
1048   s += sz;
1049   s.Add_LF();
1050 }
1051 
1052 // now we don't need CThreadTest, since now we call CopyTo for "test command
1053 
1054 class CThreadTest: public CProgressThreadVirt
1055 {
1056   HRESULT ProcessVirt();
1057 public:
1058   CRecordVector<UInt32> Indices;
1059   CExtractCallbackImp *ExtractCallbackSpec;
1060   CMyComPtr<IFolderArchiveExtractCallback> ExtractCallback;
1061   CMyComPtr<IArchiveFolder> ArchiveFolder;
1062 };
1063 
1064 HRESULT CThreadTest::ProcessVirt()
1065 {
1066   RINOK(ArchiveFolder->Extract(&Indices[0], Indices.Size(),
1067       true, // includeAltStreams
1068       false, // replaceAltStreamColon
1069       NExtract::NPathMode::kFullPathnames,
1070       NExtract::NOverwriteMode::kAskBefore,
1071       NULL, // path
1072       BoolToInt(true), // testMode
1073       ExtractCallback));
1074   if (ExtractCallbackSpec->IsOK())
1075   {
1076     UString s;
1077     AddValuePair(IDS_PROP_FOLDERS, ExtractCallbackSpec->NumFolders, s);
1078     AddValuePair(IDS_PROP_FILES, ExtractCallbackSpec->NumFiles, s);
1079     // AddValuePair(IDS_PROP_SIZE, ExtractCallbackSpec->UnpackSize, s);
1080     // AddSizePair(IDS_COMPRESSED_COLON, Stat.PackSize, s);
1081     s.Add_LF();
1082     AddLangString(s, IDS_MESSAGE_NO_ERRORS);
1083     FinalMessage.OkMessage.Message = s;
1084   }
1085   return S_OK;
1086 }
1087 
1088 static void AddSizePair(UInt32 langID, UInt64 value, UString &s)
1089 {
1090   char sz[32];
1091   AddLangString(s, langID);
1092   s += L' ';
1093   ConvertUInt64ToString(value, sz);
1094   s += sz;
1095   ConvertUInt64ToString(value >> 20, sz);
1096   s += " (";
1097   s += sz;
1098   s += " MB)";
1099   s.Add_LF();
1100 }
1101 */
1102 
TestArchives()1103 void CPanel::TestArchives()
1104 {
1105   CRecordVector<UInt32> indices;
1106   Get_ItemIndices_OperSmart(indices);
1107   CMyComPtr<IArchiveFolder> archiveFolder;
1108   _folder.QueryInterface(IID_IArchiveFolder, &archiveFolder);
1109   if (archiveFolder)
1110   {
1111     CCopyToOptions options;
1112     options.streamMode = true;
1113     options.showErrorMessages = true;
1114     options.testMode = true;
1115 
1116     UStringVector messages;
1117     HRESULT res = CopyTo(options, indices, &messages);
1118     if (res != S_OK)
1119     {
1120       if (res != E_ABORT)
1121         MessageBox_Error_HRESULT(res);
1122     }
1123     return;
1124 
1125     /*
1126     {
1127     CThreadTest extracter;
1128 
1129     extracter.ArchiveFolder = archiveFolder;
1130     extracter.ExtractCallbackSpec = new CExtractCallbackImp;
1131     extracter.ExtractCallback = extracter.ExtractCallbackSpec;
1132     extracter.ExtractCallbackSpec->ProgressDialog = &extracter.ProgressDialog;
1133     if (!_parentFolders.IsEmpty())
1134     {
1135       const CFolderLink &fl = _parentFolders.Back();
1136       extracter.ExtractCallbackSpec->PasswordIsDefined = fl.UsePassword;
1137       extracter.ExtractCallbackSpec->Password = fl.Password;
1138     }
1139 
1140     if (indices.IsEmpty())
1141       return;
1142 
1143     extracter.Indices = indices;
1144 
1145     const UString title = LangString(IDS_PROGRESS_TESTING);
1146 
1147     extracter.ProgressDialog.CompressingMode = false;
1148     extracter.ProgressDialog.MainWindow = GetParent();
1149     extracter.ProgressDialog.MainTitle = "7-Zip"; // LangString(IDS_APP_TITLE);
1150     extracter.ProgressDialog.MainAddTitle = title + L' ';
1151 
1152     extracter.ExtractCallbackSpec->OverwriteMode = NExtract::NOverwriteMode::kAskBefore;
1153     extracter.ExtractCallbackSpec->Init();
1154 
1155     if (extracter.Create(title, GetParent()) != S_OK)
1156       return;
1157 
1158     }
1159     RefreshTitleAlways();
1160     return;
1161     */
1162   }
1163 
1164   if (!IsFSFolder())
1165   {
1166     MessageBox_Error_UnsupportOperation();
1167     return;
1168   }
1169   UStringVector paths;
1170   GetFilePaths(indices, paths);
1171   if (paths.IsEmpty())
1172   {
1173     MessageBox_Error_LangID(IDS_SELECT_FILES);
1174     return;
1175   }
1176   ::TestArchives(paths);
1177 }
1178