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 ¤tFolderPrefix,
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