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