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