Imported Upstream version 9.20
[platform/upstream/7zip.git] / CPP / 7zip / UI / FileManager / Panel.cpp
1 // Panel.cpp\r
2 \r
3 #include "StdAfx.h"\r
4 \r
5 #include <Windowsx.h>\r
6 \r
7 #include "Common/Defs.h"\r
8 #include "Common/IntToString.h"\r
9 #include "Common/StringConvert.h"\r
10 \r
11 #include "Windows/Error.h"\r
12 #include "Windows/PropVariant.h"\r
13 #include "Windows/Thread.h"\r
14 \r
15 #include "../../PropID.h"\r
16 \r
17 #include "resource.h"\r
18 #include "../GUI/ExtractRes.h"\r
19 \r
20 #include "../Common/ArchiveName.h"\r
21 #include "../Common/CompressCall.h"\r
22 \r
23 #include "../Agent/IFolderArchive.h"\r
24 \r
25 #include "App.h"\r
26 #include "ExtractCallback.h"\r
27 #include "FSFolder.h"\r
28 #include "FormatUtils.h"\r
29 #include "Panel.h"\r
30 #include "RootFolder.h"\r
31 \r
32 \r
33 using namespace NWindows;\r
34 using namespace NControl;\r
35 \r
36 #ifndef _UNICODE\r
37 extern bool g_IsNT;\r
38 #endif\r
39 \r
40 static const UINT_PTR kTimerID = 1;\r
41 static const UINT kTimerElapse = 1000;\r
42 \r
43 static DWORD kStyles[4] = { LVS_ICON, LVS_SMALLICON, LVS_LIST, LVS_REPORT };\r
44 \r
45 // static const int kCreateFolderID = 101;\r
46 // static const UINT kFileChangeNotifyMessage = WM_APP;\r
47 \r
48 extern HINSTANCE g_hInstance;\r
49 extern DWORD g_ComCtl32Version;\r
50 \r
51 void CPanel::Release()\r
52 {\r
53   // It's for unloading COM dll's: don't change it.\r
54   CloseOpenFolders();\r
55   _sevenZipContextMenu.Release();\r
56   _systemContextMenu.Release();\r
57 }\r
58 \r
59 CPanel::~CPanel()\r
60 {\r
61   CloseOpenFolders();\r
62 }\r
63 \r
64 HWND CPanel::GetParent()\r
65 {\r
66   HWND h = CWindow2::GetParent();\r
67   return (h == 0) ? _mainWindow : h;\r
68 }\r
69 \r
70 static LPCWSTR kClassName = L"7-Zip::Panel";\r
71 \r
72 \r
73 HRESULT CPanel::Create(HWND mainWindow, HWND parentWindow, UINT id,\r
74     const UString &currentFolderPrefix,\r
75     const UString &arcFormat,\r
76     CPanelCallback *panelCallback, CAppState *appState,\r
77     bool &archiveIsOpened, bool &encrypted)\r
78 {\r
79   _mainWindow = mainWindow;\r
80   _processTimer = true;\r
81   _processNotify = true;\r
82 \r
83   _panelCallback = panelCallback;\r
84   _appState = appState;\r
85   // _index = index;\r
86   _baseID = id;\r
87   _comboBoxID = _baseID + 3;\r
88   _statusBarID = _comboBoxID + 1;\r
89 \r
90   UString cfp = currentFolderPrefix;\r
91 \r
92   if (!currentFolderPrefix.IsEmpty())\r
93     if (currentFolderPrefix[0] == L'.')\r
94       if (!NFile::NDirectory::MyGetFullPathName(currentFolderPrefix, cfp))\r
95         cfp = currentFolderPrefix;\r
96   RINOK(BindToPath(cfp, arcFormat, archiveIsOpened, encrypted));\r
97 \r
98   if (!CreateEx(0, kClassName, 0, WS_CHILD | WS_VISIBLE,\r
99       0, 0, _xSize, 260,\r
100       parentWindow, (HMENU)(UINT_PTR)id, g_hInstance))\r
101     return E_FAIL;\r
102   return S_OK;\r
103 }\r
104 \r
105 LRESULT CPanel::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)\r
106 {\r
107   switch(message)\r
108   {\r
109     case kShiftSelectMessage:\r
110       OnShiftSelectMessage();\r
111       return 0;\r
112     case kReLoadMessage:\r
113       RefreshListCtrl(_selectedState);\r
114       return 0;\r
115     case kSetFocusToListView:\r
116       _listView.SetFocus();\r
117       return 0;\r
118     case kOpenItemChanged:\r
119       return OnOpenItemChanged(lParam);\r
120     case kRefreshStatusBar:\r
121       OnRefreshStatusBar();\r
122       return 0;\r
123     case kRefreshHeaderComboBox:\r
124       LoadFullPathAndShow();\r
125       return 0;\r
126     case WM_TIMER:\r
127       OnTimer();\r
128       return 0;\r
129     case WM_CONTEXTMENU:\r
130       if (OnContextMenu(HANDLE(wParam), GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)))\r
131         return 0;\r
132       break;\r
133     /*\r
134     case WM_DROPFILES:\r
135       CompressDropFiles(HDROP(wParam));\r
136       return 0;\r
137     */\r
138   }\r
139   return CWindow2::OnMessage(message, wParam, lParam);\r
140 }\r
141 \r
142 static LRESULT APIENTRY ListViewSubclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)\r
143 {\r
144   CWindow tempDialog(hwnd);\r
145   CMyListView *w = (CMyListView *)(tempDialog.GetUserDataLongPtr());\r
146   if (w == NULL)\r
147     return 0;\r
148   return w->OnMessage(message, wParam, lParam);\r
149 }\r
150 \r
151 LRESULT CMyListView::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)\r
152 {\r
153   if (message == WM_CHAR)\r
154   {\r
155     UINT scanCode = (UINT)((lParam >> 16) & 0xFF);\r
156     bool extended = ((lParam & 0x1000000) != 0);\r
157     UINT virtualKey = MapVirtualKey(scanCode, 1);\r
158     if (virtualKey == VK_MULTIPLY || virtualKey == VK_ADD ||\r
159         virtualKey == VK_SUBTRACT)\r
160       return 0;\r
161     if ((wParam == '/' && extended)\r
162         || wParam == '\\' || wParam == '/')\r
163     {\r
164       _panel->OpenDrivesFolder();\r
165       return 0;\r
166     }\r
167   }\r
168   else if (message == WM_SYSCHAR)\r
169   {\r
170     // For Alt+Enter Beep disabling\r
171     UINT scanCode = (UINT)(lParam >> 16) & 0xFF;\r
172     UINT virtualKey = MapVirtualKey(scanCode, 1);\r
173     if (virtualKey == VK_RETURN || virtualKey == VK_MULTIPLY ||\r
174         virtualKey == VK_ADD || virtualKey == VK_SUBTRACT)\r
175       return 0;\r
176   }\r
177   /*\r
178   else if (message == WM_SYSKEYDOWN)\r
179   {\r
180     // return 0;\r
181   }\r
182   */\r
183   else if (message == WM_KEYDOWN)\r
184   {\r
185     bool alt = (::GetKeyState(VK_MENU) & 0x8000) != 0;\r
186     bool ctrl = (::GetKeyState(VK_CONTROL) & 0x8000) != 0;\r
187     // bool leftCtrl = (::GetKeyState(VK_LCONTROL) & 0x8000) != 0;\r
188     // bool RightCtrl = (::GetKeyState(VK_RCONTROL) & 0x8000) != 0;\r
189     bool shift = (::GetKeyState(VK_SHIFT) & 0x8000) != 0;\r
190     switch(wParam)\r
191     {\r
192       /*\r
193       case VK_RETURN:\r
194       {\r
195         if (shift && !alt && !ctrl)\r
196         {\r
197           _panel->OpenSelectedItems(false);\r
198           return 0;\r
199         }\r
200         break;\r
201       }\r
202       */\r
203       case VK_NEXT:\r
204       {\r
205         if (ctrl && !alt && !shift)\r
206         {\r
207           _panel->OpenFocusedItemAsInternal();\r
208           return 0;\r
209         }\r
210         break;\r
211       }\r
212       case VK_PRIOR:\r
213       if (ctrl && !alt && !shift)\r
214       {\r
215         _panel->OpenParentFolder();\r
216         return 0;\r
217       }\r
218     }\r
219   }\r
220   #ifdef UNDER_CE\r
221   else if (message == WM_KEYUP)\r
222   {\r
223     if (wParam == VK_F2) // it's VK_TSOFT2\r
224     {\r
225       // Activate Menu\r
226       ::PostMessage(g_HWND, WM_SYSCOMMAND, SC_KEYMENU, 0);\r
227       return 0;\r
228     }\r
229   }\r
230   #endif\r
231   else if (message == WM_SETFOCUS)\r
232   {\r
233     _panel->_lastFocusedIsList = true;\r
234     _panel->_panelCallback->PanelWasFocused();\r
235   }\r
236   #ifndef _UNICODE\r
237   if (g_IsNT)\r
238     return CallWindowProcW(_origWindowProc, *this, message, wParam, lParam);\r
239   else\r
240   #endif\r
241     return CallWindowProc(_origWindowProc, *this, message, wParam, lParam);\r
242 }\r
243 \r
244 /*\r
245 static LRESULT APIENTRY ComboBoxSubclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)\r
246 {\r
247   CWindow tempDialog(hwnd);\r
248   CMyComboBox *w = (CMyComboBox *)(tempDialog.GetUserDataLongPtr());\r
249   if (w == NULL)\r
250     return 0;\r
251   return w->OnMessage(message, wParam, lParam);\r
252 }\r
253 \r
254 LRESULT CMyComboBox::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)\r
255 {\r
256   return CallWindowProc(_origWindowProc, *this, message, wParam, lParam);\r
257 }\r
258 */\r
259 static LRESULT APIENTRY ComboBoxEditSubclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)\r
260 {\r
261   CWindow tempDialog(hwnd);\r
262   CMyComboBoxEdit *w = (CMyComboBoxEdit *)(tempDialog.GetUserDataLongPtr());\r
263   if (w == NULL)\r
264     return 0;\r
265   return w->OnMessage(message, wParam, lParam);\r
266 }\r
267 \r
268 LRESULT CMyComboBoxEdit::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)\r
269 {\r
270   // See MSDN / Subclassing a Combo Box / Creating a Combo-box Toolbar\r
271   switch (message)\r
272   {\r
273     case WM_SYSKEYDOWN:\r
274       switch (wParam)\r
275       {\r
276         case VK_F1:\r
277         case VK_F2:\r
278         {\r
279           // check ALT\r
280           if ((lParam & (1<<29)) == 0)\r
281             break;\r
282           bool alt = (::GetKeyState(VK_MENU) & 0x8000) != 0;\r
283           bool ctrl = (::GetKeyState(VK_CONTROL) & 0x8000) != 0;\r
284           bool shift = (::GetKeyState(VK_SHIFT) & 0x8000) != 0;\r
285           if (alt && !ctrl && !shift)\r
286           {\r
287             _panel->_panelCallback->SetFocusToPath(wParam == VK_F1 ? 0 : 1);\r
288             return 0;\r
289           }\r
290           break;\r
291         }\r
292       }\r
293       break;\r
294     case WM_KEYDOWN:\r
295       switch (wParam)\r
296       {\r
297         case VK_TAB:\r
298           // SendMessage(hwndMain, WM_ENTER, 0, 0);\r
299           _panel->SetFocusToList();\r
300           return 0;\r
301         case VK_F9:\r
302         {\r
303           bool alt = (::GetKeyState(VK_MENU) & 0x8000) != 0;\r
304           bool ctrl = (::GetKeyState(VK_CONTROL) & 0x8000) != 0;\r
305           bool shift = (::GetKeyState(VK_SHIFT) & 0x8000) != 0;\r
306           if (!alt && !ctrl && !shift)\r
307           {\r
308             g_App.SwitchOnOffOnePanel();;\r
309             return 0;\r
310           }\r
311           break;\r
312         }\r
313       }\r
314       break;\r
315     case WM_CHAR:\r
316       switch (wParam)\r
317       {\r
318         case VK_TAB:\r
319         case VK_ESCAPE:\r
320           return 0;\r
321       }\r
322   }\r
323   #ifndef _UNICODE\r
324   if (g_IsNT)\r
325     return CallWindowProcW(_origWindowProc, *this, message, wParam, lParam);\r
326   else\r
327   #endif\r
328     return CallWindowProc(_origWindowProc, *this, message, wParam, lParam);\r
329 }\r
330 \r
331 bool CPanel::OnCreate(CREATESTRUCT * /* createStruct */)\r
332 {\r
333   // _virtualMode = false;\r
334   // _sortIndex = 0;\r
335   _sortID = kpidName;\r
336   _ascending = true;\r
337   _lastFocusedIsList = true;\r
338 \r
339   DWORD style = WS_CHILD | WS_VISIBLE; //  | WS_BORDER ; // | LVS_SHAREIMAGELISTS; //  | LVS_SHOWSELALWAYS;;\r
340 \r
341   style |= LVS_SHAREIMAGELISTS;\r
342   // style  |= LVS_AUTOARRANGE;\r
343   style |= WS_CLIPCHILDREN;\r
344   style |= WS_CLIPSIBLINGS;\r
345 \r
346   const UInt32 kNumListModes = sizeof(kStyles) / sizeof(kStyles[0]);\r
347   if (_ListViewMode >= kNumListModes)\r
348     _ListViewMode = kNumListModes - 1;\r
349 \r
350   style |= kStyles[_ListViewMode]\r
351     | WS_TABSTOP\r
352     | LVS_EDITLABELS;\r
353   if (_mySelectMode)\r
354     style |= LVS_SINGLESEL;\r
355 \r
356   /*\r
357   if (_virtualMode)\r
358     style |= LVS_OWNERDATA;\r
359   */\r
360 \r
361   DWORD exStyle;\r
362   exStyle = WS_EX_CLIENTEDGE;\r
363 \r
364   if (!_listView.CreateEx(exStyle, style, 0, 0, 116, 260,\r
365       HWND(*this), (HMENU)(UINT_PTR)(_baseID + 1), g_hInstance, NULL))\r
366     return false;\r
367 \r
368   #ifndef UNDER_CE\r
369   _listView.SetUnicodeFormat(true);\r
370   #endif\r
371 \r
372   _listView.SetUserDataLongPtr(LONG_PTR(&_listView));\r
373   _listView._panel = this;\r
374 \r
375    #ifndef _UNICODE\r
376    if(g_IsNT)\r
377      _listView._origWindowProc =\r
378       (WNDPROC)_listView.SetLongPtrW(GWLP_WNDPROC, LONG_PTR(ListViewSubclassProc));\r
379    else\r
380    #endif\r
381      _listView._origWindowProc =\r
382       (WNDPROC)_listView.SetLongPtr(GWLP_WNDPROC, LONG_PTR(ListViewSubclassProc));\r
383 \r
384   _listView.SetImageList(GetSysImageList(true), LVSIL_SMALL);\r
385   _listView.SetImageList(GetSysImageList(false), LVSIL_NORMAL);\r
386 \r
387   // _exStyle |= LVS_EX_HEADERDRAGDROP;\r
388   // DWORD extendedStyle = _listView.GetExtendedListViewStyle();\r
389   // extendedStyle |= _exStyle;\r
390   //  _listView.SetExtendedListViewStyle(extendedStyle);\r
391   SetExtendedStyle();\r
392 \r
393   _listView.Show(SW_SHOW);\r
394   _listView.InvalidateRect(NULL, true);\r
395   _listView.Update();\r
396   \r
397   // Ensure that the common control DLL is loaded.\r
398   INITCOMMONCONTROLSEX icex;\r
399 \r
400   icex.dwSize = sizeof(INITCOMMONCONTROLSEX);\r
401   icex.dwICC  = ICC_BAR_CLASSES;\r
402   InitCommonControlsEx(&icex);\r
403 \r
404   TBBUTTON tbb [ ] =\r
405   {\r
406     // {0, 0, TBSTATE_ENABLED, BTNS_SEP, 0L, 0},\r
407     {VIEW_PARENTFOLDER, kParentFolderID, TBSTATE_ENABLED, BTNS_BUTTON, 0L, 0},\r
408     // {0, 0, TBSTATE_ENABLED, BTNS_SEP, 0L, 0},\r
409     // {VIEW_NEWFOLDER, kCreateFolderID, TBSTATE_ENABLED, BTNS_BUTTON, 0L, 0},\r
410   };\r
411 \r
412   #ifndef UNDER_CE\r
413   if (g_ComCtl32Version >= MAKELONG(71, 4))\r
414   #endif\r
415   {\r
416     icex.dwSize = sizeof(INITCOMMONCONTROLSEX);\r
417     icex.dwICC  = ICC_COOL_CLASSES | ICC_BAR_CLASSES;\r
418     InitCommonControlsEx(&icex);\r
419     \r
420     _headerReBar.Attach(::CreateWindowEx(WS_EX_TOOLWINDOW,\r
421       REBARCLASSNAME,\r
422       NULL, WS_VISIBLE | WS_BORDER | WS_CHILD |\r
423       WS_CLIPCHILDREN | WS_CLIPSIBLINGS\r
424       | CCS_NODIVIDER\r
425       // | CCS_NOPARENTALIGN\r
426       | CCS_TOP\r
427       | RBS_VARHEIGHT\r
428       | RBS_BANDBORDERS\r
429       ,0,0,0,0, HWND(*this), NULL, g_hInstance, NULL));\r
430   }\r
431 \r
432   DWORD toolbarStyle =  WS_CHILD | WS_VISIBLE ;\r
433   if (_headerReBar)\r
434   {\r
435     toolbarStyle |= 0\r
436       // | WS_CLIPCHILDREN\r
437       // | WS_CLIPSIBLINGS\r
438 \r
439       | TBSTYLE_TOOLTIPS\r
440       | CCS_NODIVIDER\r
441       | CCS_NORESIZE\r
442       | TBSTYLE_FLAT\r
443       ;\r
444   }\r
445 \r
446   _headerToolBar.Attach(::CreateToolbarEx ((*this), toolbarStyle,\r
447       _baseID + 2, 11,\r
448       (HINSTANCE)HINST_COMMCTRL,\r
449       IDB_VIEW_SMALL_COLOR,\r
450       (LPCTBBUTTON)&tbb, sizeof(tbb) / sizeof(tbb[0]),\r
451       0, 0, 0, 0, sizeof (TBBUTTON)));\r
452 \r
453   #ifndef UNDER_CE\r
454   // Load ComboBoxEx class\r
455   icex.dwSize = sizeof(INITCOMMONCONTROLSEX);\r
456   icex.dwICC = ICC_USEREX_CLASSES;\r
457   InitCommonControlsEx(&icex);\r
458   #endif\r
459   \r
460   _headerComboBox.CreateEx(0,\r
461       #ifdef UNDER_CE\r
462       WC_COMBOBOXW\r
463       #else\r
464       WC_COMBOBOXEXW\r
465       #endif\r
466       , NULL,\r
467     WS_BORDER | WS_VISIBLE |WS_CHILD | CBS_DROPDOWN | CBS_AUTOHSCROLL,\r
468       0, 0, 100, 520,\r
469       ((_headerReBar == 0) ? HWND(*this) : _headerToolBar),\r
470       (HMENU)(UINT_PTR)(_comboBoxID),\r
471       g_hInstance, NULL);\r
472   #ifndef UNDER_CE\r
473   _headerComboBox.SetUnicodeFormat(true);\r
474 \r
475   _headerComboBox.SetImageList(GetSysImageList(true));\r
476 \r
477   _headerComboBox.SetExtendedStyle(CBES_EX_PATHWORDBREAKPROC, CBES_EX_PATHWORDBREAKPROC);\r
478 \r
479   /*\r
480   _headerComboBox.SetUserDataLongPtr(LONG_PTR(&_headerComboBox));\r
481   _headerComboBox._panel = this;\r
482   _headerComboBox._origWindowProc =\r
483       (WNDPROC)_headerComboBox.SetLongPtr(GWLP_WNDPROC,\r
484       LONG_PTR(ComboBoxSubclassProc));\r
485   */\r
486   _comboBoxEdit.Attach(_headerComboBox.GetEditControl());\r
487 \r
488   // _comboBoxEdit.SendMessage(CCM_SETUNICODEFORMAT, (WPARAM)(BOOL)TRUE, 0);\r
489 \r
490   _comboBoxEdit.SetUserDataLongPtr(LONG_PTR(&_comboBoxEdit));\r
491   _comboBoxEdit._panel = this;\r
492    #ifndef _UNICODE\r
493    if(g_IsNT)\r
494      _comboBoxEdit._origWindowProc =\r
495       (WNDPROC)_comboBoxEdit.SetLongPtrW(GWLP_WNDPROC, LONG_PTR(ComboBoxEditSubclassProc));\r
496    else\r
497    #endif\r
498      _comboBoxEdit._origWindowProc =\r
499       (WNDPROC)_comboBoxEdit.SetLongPtr(GWLP_WNDPROC, LONG_PTR(ComboBoxEditSubclassProc));\r
500 \r
501   #endif\r
502 \r
503   if (_headerReBar)\r
504   {\r
505     REBARINFO     rbi;\r
506     rbi.cbSize = sizeof(REBARINFO);  // Required when using this struct.\r
507     rbi.fMask  = 0;\r
508     rbi.himl   = (HIMAGELIST)NULL;\r
509     _headerReBar.SetBarInfo(&rbi);\r
510     \r
511     // Send the TB_BUTTONSTRUCTSIZE message, which is required for\r
512     // backward compatibility.\r
513     // _headerToolBar.SendMessage(TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);\r
514     SIZE size;\r
515     _headerToolBar.GetMaxSize(&size);\r
516     \r
517     REBARBANDINFO rbBand;\r
518     rbBand.cbSize = sizeof(REBARBANDINFO);  // Required\r
519     rbBand.fMask = RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE;\r
520     rbBand.fStyle = RBBS_NOGRIPPER;\r
521     rbBand.cxMinChild = size.cx;\r
522     rbBand.cyMinChild = size.cy;\r
523     rbBand.cyChild = size.cy;\r
524     rbBand.cx = size.cx;\r
525     rbBand.hwndChild  = _headerToolBar;\r
526     _headerReBar.InsertBand(-1, &rbBand);\r
527 \r
528     RECT rc;\r
529     ::GetWindowRect(_headerComboBox, &rc);\r
530     rbBand.cxMinChild = 30;\r
531     rbBand.cyMinChild = rc.bottom - rc.top;\r
532     rbBand.cx = 1000;\r
533     rbBand.hwndChild  = _headerComboBox;\r
534     _headerReBar.InsertBand(-1, &rbBand);\r
535     // _headerReBar.MaximizeBand(1, false);\r
536   }\r
537 \r
538   _statusBar.Create(WS_CHILD | WS_VISIBLE, L"Status", (*this), _statusBarID);\r
539   // _statusBar2.Create(WS_CHILD | WS_VISIBLE, L"Status", (*this), _statusBarID + 1);\r
540 \r
541   int sizes[] = {150, 250, 350, -1};\r
542   _statusBar.SetParts(4, sizes);\r
543   // _statusBar2.SetParts(5, sizes);\r
544 \r
545   /*\r
546   RECT rect;\r
547   GetClientRect(&rect);\r
548   OnSize(0, rect.right - rect.left, rect.top - rect.bottom);\r
549   */\r
550 \r
551   SetTimer(kTimerID, kTimerElapse);\r
552 \r
553   // InitListCtrl();\r
554   RefreshListCtrl();\r
555   RefreshStatusBar();\r
556   \r
557   return true;\r
558 }\r
559 \r
560 void CPanel::OnDestroy()\r
561 {\r
562   SaveListViewInfo();\r
563   CWindow2::OnDestroy();\r
564 }\r
565 \r
566 void CPanel::ChangeWindowSize(int xSize, int ySize)\r
567 {\r
568   if ((HWND)*this == 0)\r
569     return;\r
570   int kHeaderSize;\r
571   int kStatusBarSize;\r
572   // int kStatusBar2Size;\r
573   RECT rect;\r
574   if (_headerReBar)\r
575     _headerReBar.GetWindowRect(&rect);\r
576   else\r
577     _headerToolBar.GetWindowRect(&rect);\r
578 \r
579   kHeaderSize = rect.bottom - rect.top;\r
580 \r
581   _statusBar.GetWindowRect(&rect);\r
582   kStatusBarSize = rect.bottom - rect.top;\r
583   \r
584   // _statusBar2.GetWindowRect(&rect);\r
585   // kStatusBar2Size = rect.bottom - rect.top;\r
586  \r
587   int yListViewSize = MyMax(ySize - kHeaderSize - kStatusBarSize, 0);\r
588   const int kStartXPos = 32;\r
589   if (_headerReBar)\r
590   {\r
591   }\r
592   else\r
593   {\r
594     _headerToolBar.Move(0, 0, xSize, 0);\r
595     _headerComboBox.Move(kStartXPos, 2,\r
596         MyMax(xSize - kStartXPos - 10, kStartXPos), 0);\r
597   }\r
598   _listView.Move(0, kHeaderSize, xSize, yListViewSize);\r
599   _statusBar.Move(0, kHeaderSize + yListViewSize, xSize, kStatusBarSize);\r
600   // _statusBar2.MoveWindow(0, kHeaderSize + yListViewSize + kStatusBarSize, xSize, kStatusBar2Size);\r
601   // _statusBar.MoveWindow(0, 100, xSize, kStatusBarSize);\r
602   // _statusBar2.MoveWindow(0, 200, xSize, kStatusBar2Size);\r
603 }\r
604 \r
605 bool CPanel::OnSize(WPARAM /* wParam */, int xSize, int ySize)\r
606 {\r
607   if ((HWND)*this == 0)\r
608     return true;\r
609   if (_headerReBar)\r
610     _headerReBar.Move(0, 0, xSize, 0);\r
611   ChangeWindowSize(xSize, ySize);\r
612   return true;\r
613 }\r
614 \r
615 bool CPanel::OnNotifyReBar(LPNMHDR header, LRESULT & /* result */)\r
616 {\r
617   switch(header->code)\r
618   {\r
619     case RBN_HEIGHTCHANGE:\r
620     {\r
621       RECT rect;\r
622       GetWindowRect(&rect);\r
623       ChangeWindowSize(rect.right - rect.left, rect.bottom - rect.top);\r
624       return false;\r
625     }\r
626   }\r
627   return false;\r
628 }\r
629 \r
630 bool CPanel::OnNotify(UINT /* controlID */, LPNMHDR header, LRESULT &result)\r
631 {\r
632   if (!_processNotify)\r
633     return false;\r
634   if (header->hwndFrom == _headerComboBox)\r
635     return OnNotifyComboBox(header, result);\r
636   else if (header->hwndFrom == _headerReBar)\r
637     return OnNotifyReBar(header, result);\r
638   // if (header->hwndFrom == _listView)\r
639   else if (header->hwndFrom == _listView)\r
640     return OnNotifyList(header, result);\r
641   else if (::GetParent(header->hwndFrom) == _listView &&\r
642       header->code == NM_RCLICK)\r
643     return OnRightClick((MY_NMLISTVIEW_NMITEMACTIVATE *)header, result);\r
644   return false;\r
645 }\r
646 \r
647 bool CPanel::OnCommand(int code, int itemID, LPARAM lParam, LRESULT &result)\r
648 {\r
649   if (itemID == kParentFolderID)\r
650   {\r
651     OpenParentFolder();\r
652     result = 0;\r
653     return true;\r
654   }\r
655   /*\r
656   if (itemID == kCreateFolderID)\r
657   {\r
658     CreateFolder();\r
659     result = 0;\r
660     return true;\r
661   }\r
662   */\r
663   if (itemID == _comboBoxID)\r
664   {\r
665     if (OnComboBoxCommand(code, lParam, result))\r
666       return true;\r
667   }\r
668   return CWindow2::OnCommand(code, itemID, lParam, result);\r
669 }\r
670 \r
671 void CPanel::MessageBoxInfo(LPCWSTR message, LPCWSTR caption)\r
672   { ::MessageBoxW(HWND(*this), message, caption, MB_OK); }\r
673 void CPanel::MessageBox(LPCWSTR message, LPCWSTR caption)\r
674   { ::MessageBoxW(HWND(*this), message, caption, MB_OK | MB_ICONSTOP); }\r
675 void CPanel::MessageBox(LPCWSTR message)\r
676   { MessageBox(message, L"7-Zip"); }\r
677 void CPanel::MessageBoxMyError(LPCWSTR message)\r
678   { MessageBox(message, L"Error"); }\r
679 \r
680 \r
681 void CPanel::MessageBoxError(HRESULT errorCode, LPCWSTR caption)\r
682 {\r
683   MessageBox(HResultToMessage(errorCode), caption);\r
684 }\r
685 \r
686 void CPanel::MessageBoxError(HRESULT errorCode)\r
687   { MessageBoxError(errorCode, L"7-Zip"); }\r
688 void CPanel::MessageBoxLastError(LPCWSTR caption)\r
689   { MessageBoxError(::GetLastError(), caption); }\r
690 void CPanel::MessageBoxLastError()\r
691   { MessageBoxLastError(L"Error"); }\r
692 \r
693 void CPanel::MessageBoxErrorLang(UINT resourceID, UInt32 langID)\r
694   { MessageBox(LangString(resourceID, langID)); }\r
695 \r
696 \r
697 void CPanel::SetFocusToList()\r
698 {\r
699   _listView.SetFocus();\r
700   // SetCurrentPathText();\r
701 }\r
702 \r
703 void CPanel::SetFocusToLastRememberedItem()\r
704 {\r
705   if (_lastFocusedIsList)\r
706     SetFocusToList();\r
707   else\r
708     _headerComboBox.SetFocus();\r
709 }\r
710 \r
711 UString CPanel::GetFolderTypeID() const\r
712 {\r
713   NCOM::CPropVariant prop;\r
714   if (_folder->GetFolderProperty(kpidType, &prop) == S_OK)\r
715     if (prop.vt == VT_BSTR)\r
716       return (const wchar_t *)prop.bstrVal;\r
717   return L"";\r
718 }\r
719 \r
720 bool CPanel::IsFolderTypeEqTo(const wchar_t *s) const\r
721 {\r
722   return GetFolderTypeID() == s;\r
723 }\r
724 \r
725 bool CPanel::IsRootFolder() const { return IsFolderTypeEqTo(L"RootFolder"); }\r
726 bool CPanel::IsFSFolder() const { return IsFolderTypeEqTo(L"FSFolder"); }\r
727 bool CPanel::IsFSDrivesFolder() const { return IsFolderTypeEqTo(L"FSDrives"); }\r
728 bool CPanel::IsArcFolder() const\r
729 {\r
730   UString s = GetFolderTypeID();\r
731   return s.Left(5) == L"7-Zip";\r
732 }\r
733 \r
734 UString CPanel::GetFsPath() const\r
735 {\r
736   if (IsFSDrivesFolder() && !IsDeviceDrivesPrefix())\r
737     return UString();\r
738   return _currentFolderPrefix;\r
739 }\r
740 \r
741 UString CPanel::GetDriveOrNetworkPrefix() const\r
742 {\r
743   if (!IsFSFolder())\r
744     return UString();\r
745   UString drive = GetFsPath();\r
746   if (drive.Length() < 3)\r
747     return UString();\r
748   if (drive[0] == L'\\' && drive[1] == L'\\')\r
749   {\r
750     // if network\r
751     int pos = drive.Find(L'\\', 2);\r
752     if (pos < 0)\r
753       return UString();\r
754     pos = drive.Find(L'\\', pos + 1);\r
755     if (pos < 0)\r
756       return UString();\r
757     return drive.Left(pos + 1);\r
758   }\r
759   if (drive[1] != L':' || drive[2] != L'\\')\r
760     return UString();\r
761   return drive.Left(3);\r
762 }\r
763 \r
764 bool CPanel::DoesItSupportOperations() const\r
765 {\r
766   CMyComPtr<IFolderOperations> folderOperations;\r
767   return _folder.QueryInterface(IID_IFolderOperations, &folderOperations) == S_OK;\r
768 }\r
769 \r
770 void CPanel::SetListViewMode(UInt32 index)\r
771 {\r
772   if (index >= 4)\r
773     return;\r
774   _ListViewMode = index;\r
775   DWORD oldStyle = (DWORD)_listView.GetStyle();\r
776   DWORD newStyle = kStyles[index];\r
777   if ((oldStyle & LVS_TYPEMASK) != newStyle)\r
778     _listView.SetStyle((oldStyle & ~LVS_TYPEMASK) | newStyle);\r
779   // RefreshListCtrlSaveFocused();\r
780 }\r
781 \r
782 void CPanel::ChangeFlatMode()\r
783 {\r
784   _flatMode = !_flatMode;\r
785   if (_parentFolders.Size() > 0)\r
786     _flatModeForArc = _flatMode;\r
787   else\r
788     _flatModeForDisk = _flatMode;\r
789   RefreshListCtrlSaveFocused();\r
790 }\r
791 \r
792 \r
793 void CPanel::RefreshStatusBar()\r
794 {\r
795   PostMessage(kRefreshStatusBar);\r
796 }\r
797 \r
798 void CPanel::AddToArchive()\r
799 {\r
800   CRecordVector<UInt32> indices;\r
801   GetOperatedItemIndices(indices);\r
802   if (!IsFsOrDrivesFolder())\r
803   {\r
804     MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);\r
805     return;\r
806   }\r
807   if (indices.Size() == 0)\r
808   {\r
809     MessageBoxErrorLang(IDS_SELECT_FILES, 0x03020A03);\r
810     return;\r
811   }\r
812   UStringVector names;\r
813 \r
814   UString curPrefix = _currentFolderPrefix;\r
815   UString destCurDirPrefix = _currentFolderPrefix;\r
816   if (IsFSDrivesFolder())\r
817   {\r
818     destCurDirPrefix = ROOT_FS_FOLDER;\r
819     if (!IsDeviceDrivesPrefix())\r
820       curPrefix.Empty();\r
821   }\r
822 \r
823   for (int i = 0; i < indices.Size(); i++)\r
824     names.Add(curPrefix + GetItemRelPath(indices[i]));\r
825   const UString archiveName = CreateArchiveName(names.Front(), (names.Size() > 1), false);\r
826   HRESULT res = CompressFiles(destCurDirPrefix, archiveName, L"", names, false, true, false);\r
827   if (res != S_OK)\r
828   {\r
829     if (destCurDirPrefix.Length() >= MAX_PATH)\r
830       MessageBoxErrorLang(IDS_MESSAGE_UNSUPPORTED_OPERATION_FOR_LONG_PATH_FOLDER, 0x03020A01);\r
831   }\r
832   // KillSelection();\r
833 }\r
834 \r
835 static UString GetSubFolderNameForExtract(const UString &archiveName)\r
836 {\r
837   int slashPos = archiveName.ReverseFind(WCHAR_PATH_SEPARATOR);\r
838   int dotPos = archiveName.ReverseFind(L'.');\r
839   if (dotPos < 0 || slashPos > dotPos)\r
840     return archiveName + UString(L"~");\r
841   UString res = archiveName.Left(dotPos);\r
842   res.TrimRight();\r
843   return res;\r
844 }\r
845 \r
846 void CPanel::GetFilePaths(const CRecordVector<UInt32> &indices, UStringVector &paths)\r
847 {\r
848   for (int i = 0; i < indices.Size(); i++)\r
849   {\r
850     int index = indices[i];\r
851     if (IsItemFolder(index))\r
852     {\r
853       paths.Clear();\r
854       break;\r
855     }\r
856     paths.Add(GetItemFullPath(index));\r
857   }\r
858   if (paths.Size() == 0)\r
859   {\r
860     MessageBoxErrorLang(IDS_SELECT_FILES, 0x03020A03);\r
861     return;\r
862   }\r
863 }\r
864 \r
865 void CPanel::ExtractArchives()\r
866 {\r
867   if (_parentFolders.Size() > 0)\r
868   {\r
869     _panelCallback->OnCopy(false, false);\r
870     return;\r
871   }\r
872   CRecordVector<UInt32> indices;\r
873   GetOperatedItemIndices(indices);\r
874   UStringVector paths;\r
875   GetFilePaths(indices, paths);\r
876   if (paths.IsEmpty())\r
877     return;\r
878   UString folderName;\r
879   if (indices.Size() == 1)\r
880     folderName = GetSubFolderNameForExtract(GetItemRelPath(indices[0]));\r
881   else\r
882     folderName = L"*";\r
883   ::ExtractArchives(paths, _currentFolderPrefix + folderName + UString(WCHAR_PATH_SEPARATOR), true);\r
884 }\r
885 \r
886 static void AddValuePair(UINT resourceID, UInt32 langID, UInt64 value, UString &s)\r
887 {\r
888   wchar_t sz[32];\r
889   s += LangString(resourceID, langID);\r
890   s += L' ';\r
891   ConvertUInt64ToString(value, sz);\r
892   s += sz;\r
893   s += L'\n';\r
894 }\r
895 \r
896 class CThreadTest: public CProgressThreadVirt\r
897 {\r
898   HRESULT ProcessVirt();\r
899 public:\r
900   CRecordVector<UInt32> Indices;\r
901   CExtractCallbackImp *ExtractCallbackSpec;\r
902   CMyComPtr<IFolderArchiveExtractCallback> ExtractCallback;\r
903   CMyComPtr<IArchiveFolder> ArchiveFolder;\r
904 };\r
905 \r
906 HRESULT CThreadTest::ProcessVirt()\r
907 {\r
908   RINOK(ArchiveFolder->Extract(&Indices[0], Indices.Size(),\r
909       NExtract::NPathMode::kFullPathnames, NExtract::NOverwriteMode::kAskBefore,\r
910       NULL, BoolToInt(true), ExtractCallback));\r
911   if (ExtractCallbackSpec->IsOK())\r
912   {\r
913     UString s;\r
914     AddValuePair(IDS_FOLDERS_COLON, 0x02000321, ExtractCallbackSpec->NumFolders, s);\r
915     AddValuePair(IDS_FILES_COLON, 0x02000320, ExtractCallbackSpec->NumFiles, s);\r
916     // AddSizePair(IDS_SIZE_COLON, 0x02000322, Stat.UnpackSize, s);\r
917     // AddSizePair(IDS_COMPRESSED_COLON, 0x02000323, Stat.PackSize, s);\r
918     s += L'\n';\r
919     s += LangString(IDS_MESSAGE_NO_ERRORS, 0x02000608);\r
920     OkMessage = s;\r
921   }\r
922   return S_OK;\r
923 }\r
924 \r
925 /*\r
926 static void AddSizePair(UINT resourceID, UInt32 langID, UInt64 value, UString &s)\r
927 {\r
928   wchar_t sz[32];\r
929   s += LangString(resourceID, langID);\r
930   s += L" ";\r
931   ConvertUInt64ToString(value, sz);\r
932   s += sz;\r
933   ConvertUInt64ToString(value >> 20, sz);\r
934   s += L" (";\r
935   s += sz;\r
936   s += L" MB)";\r
937   s += L'\n';\r
938 }\r
939 */\r
940 \r
941 void CPanel::TestArchives()\r
942 {\r
943   CRecordVector<UInt32> indices;\r
944   GetOperatedIndicesSmart(indices);\r
945   CMyComPtr<IArchiveFolder> archiveFolder;\r
946   _folder.QueryInterface(IID_IArchiveFolder, &archiveFolder);\r
947   if (archiveFolder)\r
948   {\r
949     {\r
950     CThreadTest extracter;\r
951 \r
952     extracter.ArchiveFolder = archiveFolder;\r
953     extracter.ExtractCallbackSpec = new CExtractCallbackImp;\r
954     extracter.ExtractCallback = extracter.ExtractCallbackSpec;\r
955     extracter.ExtractCallbackSpec->ProgressDialog = &extracter.ProgressDialog;\r
956 \r
957     if (indices.IsEmpty())\r
958       return;\r
959 \r
960     extracter.Indices = indices;\r
961     \r
962     UString title = LangString(IDS_PROGRESS_TESTING, 0x02000F90);\r
963     UString progressWindowTitle = LangString(IDS_APP_TITLE, 0x03000000);\r
964     \r
965     extracter.ProgressDialog.CompressingMode = false;\r
966     extracter.ProgressDialog.MainWindow = GetParent();\r
967     extracter.ProgressDialog.MainTitle = progressWindowTitle;\r
968     extracter.ProgressDialog.MainAddTitle = title + L" ";\r
969     \r
970     extracter.ExtractCallbackSpec->OverwriteMode = NExtract::NOverwriteMode::kAskBefore;\r
971     extracter.ExtractCallbackSpec->Init();\r
972     \r
973     if (extracter.Create(title, GetParent()) != S_OK)\r
974       return;\r
975     \r
976     }\r
977     RefreshTitleAlways();\r
978     return;\r
979   }\r
980 \r
981   if (!IsFSFolder())\r
982   {\r
983     MessageBoxErrorLang(IDS_OPERATION_IS_NOT_SUPPORTED, 0x03020208);\r
984     return;\r
985   }\r
986   UStringVector paths;\r
987   GetFilePaths(indices, paths);\r
988   if (paths.IsEmpty())\r
989     return;\r
990   ::TestArchives(paths);\r
991 }\r