blob: 72b72c65d1802ffce4b853be359d61f2623aadc8 [file] [log] [blame]
// Panel.cpp
#include "StdAfx.h"
#include <windowsx.h>
#include "../../../Common/IntToString.h"
#include "../../../Common/StringConvert.h"
#include "../../../Windows/FileName.h"
#include "../../../Windows/ErrorMsg.h"
#include "../../../Windows/PropVariant.h"
#include "../../../Windows/Thread.h"
#include "../../PropID.h"
#include "resource.h"
#include "../GUI/ExtractRes.h"
#include "../Common/ArchiveName.h"
#include "../Common/CompressCall.h"
#include "../Common/ZipRegistry.h"
#include "../Agent/IFolderArchive.h"
#include "App.h"
#include "ExtractCallback.h"
#include "FSFolder.h"
#include "FormatUtils.h"
#include "LangUtils.h"
#include "Panel.h"
#include "RootFolder.h"
#include "PropertyNameRes.h"
using namespace NWindows;
using namespace NControl;
#ifndef _UNICODE
extern bool g_IsNT;
#endif
static const UINT_PTR kTimerID = 1;
static const UINT kTimerElapse = 1000;
static DWORD kStyles[4] = { LVS_ICON, LVS_SMALLICON, LVS_LIST, LVS_REPORT };
// static const int kCreateFolderID = 101;
extern HINSTANCE g_hInstance;
extern DWORD g_ComCtl32Version;
void CPanel::Release()
{
// It's for unloading COM dll's: don't change it.
CloseOpenFolders();
_sevenZipContextMenu.Release();
_systemContextMenu.Release();
}
CPanel::~CPanel()
{
CloseOpenFolders();
}
HWND CPanel::GetParent() const
{
const HWND h = CWindow2::GetParent();
return h ? h : _mainWindow;
}
#define kClassName L"7-Zip::Panel"
HRESULT CPanel::Create(HWND mainWindow, HWND parentWindow, UINT id,
const UString &currentFolderPrefix,
const UString &arcFormat,
CPanelCallback *panelCallback, CAppState *appState,
bool needOpenArc,
COpenResult &openRes)
{
_mainWindow = mainWindow;
_processTimer = true;
_processNotify = true;
_processStatusBar = true;
_panelCallback = panelCallback;
_appState = appState;
// _index = index;
_baseID = id;
_comboBoxID = _baseID + 3;
_statusBarID = _comboBoxID + 1;
UString cfp = currentFolderPrefix;
if (!currentFolderPrefix.IsEmpty())
if (currentFolderPrefix[0] == L'.')
{
FString cfpF;
if (NFile::NDir::MyGetFullPathName(us2fs(currentFolderPrefix), cfpF))
cfp = fs2us(cfpF);
}
RINOK(BindToPath(cfp, arcFormat, openRes))
if (needOpenArc && !openRes.ArchiveIsOpened)
return S_OK;
if (!CreateEx(0, kClassName, NULL, WS_CHILD | WS_VISIBLE,
0, 0, _xSize, 260,
parentWindow, (HMENU)(UINT_PTR)id, g_hInstance))
return E_FAIL;
PanelCreated = true;
return S_OK;
}
// extern UInt32 g_NumMessages;
LRESULT CPanel::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
{
// g_NumMessages++;
switch (message)
{
case kShiftSelectMessage:
OnShiftSelectMessage();
return 0;
case kReLoadMessage:
RefreshListCtrl(_selectedState);
return 0;
case kSetFocusToListView:
_listView.SetFocus();
return 0;
case kOpenItemChanged:
return OnOpenItemChanged(lParam);
case kRefresh_StatusBar:
if (_processStatusBar)
Refresh_StatusBar();
return 0;
#ifdef UNDER_CE
case kRefresh_HeaderComboBox:
LoadFullPathAndShow();
return 0;
#endif
case WM_TIMER:
OnTimer();
return 0;
case WM_CONTEXTMENU:
if (OnContextMenu(HANDLE(wParam), GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)))
return 0;
break;
/*
case WM_DROPFILES:
CompressDropFiles(HDROP(wParam));
return 0;
*/
}
return CWindow2::OnMessage(message, wParam, lParam);
}
LRESULT CMyListView::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_CHAR)
{
UINT scanCode = (UINT)((lParam >> 16) & 0xFF);
bool extended = ((lParam & 0x1000000) != 0);
UINT virtualKey = MapVirtualKey(scanCode, 1);
if (virtualKey == VK_MULTIPLY || virtualKey == VK_ADD ||
virtualKey == VK_SUBTRACT)
return 0;
if ((wParam == '/' && extended)
|| wParam == '\\' || wParam == '/')
{
_panel->OpenDrivesFolder();
return 0;
}
}
else if (message == WM_SYSCHAR)
{
// For Alt+Enter Beep disabling
UINT scanCode = (UINT)(lParam >> 16) & 0xFF;
UINT virtualKey = MapVirtualKey(scanCode, 1);
if (virtualKey == VK_RETURN || virtualKey == VK_MULTIPLY ||
virtualKey == VK_ADD || virtualKey == VK_SUBTRACT)
return 0;
}
/*
else if (message == WM_SYSKEYDOWN)
{
// return 0;
}
*/
else if (message == WM_KEYDOWN)
{
bool alt = IsKeyDown(VK_MENU);
bool ctrl = IsKeyDown(VK_CONTROL);
bool shift = IsKeyDown(VK_SHIFT);
switch (wParam)
{
/*
case VK_RETURN:
{
if (shift && !alt && !ctrl)
{
_panel->OpenSelectedItems(false);
return 0;
}
break;
}
*/
case VK_NEXT:
{
if (ctrl && !alt && !shift)
{
_panel->OpenFocusedItemAsInternal();
return 0;
}
break;
}
case VK_PRIOR:
if (ctrl && !alt && !shift)
{
_panel->OpenParentFolder();
return 0;
}
}
}
#ifdef UNDER_CE
else if (message == WM_KEYUP)
{
if (wParam == VK_F2) // it's VK_TSOFT2
{
// Activate Menu
::PostMessage(g_HWND, WM_SYSCOMMAND, SC_KEYMENU, 0);
return 0;
}
}
#endif
else if (message == WM_SETFOCUS)
{
_panel->_lastFocusedIsList = true;
_panel->_panelCallback->PanelWasFocused();
}
return CListView2::OnMessage(message, wParam, lParam);
}
/*
static LRESULT APIENTRY ComboBoxSubclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
CWindow tempDialog(hwnd);
CMyComboBox *w = (CMyComboBox *)(tempDialog.GetUserDataLongPtr());
if (w == NULL)
return 0;
return w->OnMessage(message, wParam, lParam);
}
LRESULT CMyComboBox::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
{
return CallWindowProc(_origWindowProc, *this, message, wParam, lParam);
}
*/
#ifndef UNDER_CE
static LRESULT APIENTRY ComboBoxEditSubclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
CWindow tempDialog(hwnd);
CMyComboBoxEdit *w = (CMyComboBoxEdit *)(tempDialog.GetUserDataLongPtr());
if (w == NULL)
return 0;
return w->OnMessage(message, wParam, lParam);
}
#endif
LRESULT CMyComboBoxEdit::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
{
// See MSDN / Subclassing a Combo Box / Creating a Combo-box Toolbar
switch (message)
{
case WM_SYSKEYDOWN:
switch (wParam)
{
case VK_F1:
case VK_F2:
{
// check ALT
if ((lParam & (1<<29)) == 0)
break;
bool alt = IsKeyDown(VK_MENU);
bool ctrl = IsKeyDown(VK_CONTROL);
bool shift = IsKeyDown(VK_SHIFT);
if (alt && !ctrl && !shift)
{
_panel->_panelCallback->SetFocusToPath(wParam == VK_F1 ? 0 : 1);
return 0;
}
break;
}
}
break;
case WM_KEYDOWN:
switch (wParam)
{
case VK_TAB:
// SendMessage(hwndMain, WM_ENTER, 0, 0);
_panel->SetFocusToList();
return 0;
case VK_F9:
{
bool alt = IsKeyDown(VK_MENU);
bool ctrl = IsKeyDown(VK_CONTROL);
bool shift = IsKeyDown(VK_SHIFT);
if (!alt && !ctrl && !shift)
{
g_App.SwitchOnOffOnePanel();
return 0;
}
break;
}
case 'W':
{
bool ctrl = IsKeyDown(VK_CONTROL);
if (ctrl)
{
PostMessage(g_HWND, WM_COMMAND, IDCLOSE, 0);
return 0;
}
break;
}
}
break;
case WM_CHAR:
switch (wParam)
{
case VK_TAB:
case VK_ESCAPE:
return 0;
}
}
#ifndef _UNICODE
if (g_IsNT)
return CallWindowProcW(_origWindowProc, *this, message, wParam, lParam);
else
#endif
return CallWindowProc(_origWindowProc, *this, message, wParam, lParam);
}
/*
REBARBANDINFO in vista (_WIN32_WINNT >= 0x0600) has additional fields
we want 2000/xp compatibility.
so we must use reduced structure, if we compile with (_WIN32_WINNT >= 0x0600)
Also there are additional fields, if (_WIN32_IE >= 0x0400).
but (_WIN32_IE >= 0x0400) is expected.
note:
in x64 (64-bit):
{
(108 == REBARBANDINFO_V6_SIZE)
(112 == sizeof(REBARBANDINFO) // for (_WIN32_WINNT < 0x0600)
(128 == sizeof(REBARBANDINFO) // for (_WIN32_WINNT >= 0x0600)
there is difference in sizes, because REBARBANDINFO size was
not aligned for 8-bytes in (_WIN32_WINNT < 0x0600).
We hope that WinVista+ support support both (108 and 112) sizes.
But does WinXP-x64 support (108 == REBARBANDINFO_V6_SIZE)?
{
96 LPARAM lParam;
104 UINT cxHeader;
#if (_WIN32_WINNT >= 0x0600)
108 RECT rcChevronLocation;
124 UINT uChevronState;
#endif
}
*/
#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) && defined(REBARBANDINFOA_V6_SIZE)
#define my_compatib_REBARBANDINFO_size REBARBANDINFO_V6_SIZE
#else
#define my_compatib_REBARBANDINFO_size sizeof(REBARBANDINFO)
#endif
bool CPanel::OnCreate(CREATESTRUCT * /* createStruct */)
{
// _virtualMode = false;
// _sortIndex = 0;
_sortID = kpidName;
_ascending = true;
_lastFocusedIsList = true;
DWORD style = WS_CHILD | WS_VISIBLE; // | WS_BORDER ; // | LVS_SHAREIMAGELISTS; // | LVS_SHOWSELALWAYS;
style |= LVS_SHAREIMAGELISTS;
// style |= LVS_AUTOARRANGE;
style |= WS_CLIPCHILDREN;
style |= WS_CLIPSIBLINGS;
const UInt32 kNumListModes = Z7_ARRAY_SIZE(kStyles);
if (_listViewMode >= kNumListModes)
_listViewMode = kNumListModes - 1;
style |= kStyles[_listViewMode]
| WS_TABSTOP
| LVS_EDITLABELS;
if (_mySelectMode)
style |= LVS_SINGLESEL;
/*
if (_virtualMode)
style |= LVS_OWNERDATA;
*/
DWORD exStyle;
exStyle = WS_EX_CLIENTEDGE;
if (!_listView.CreateEx(exStyle, style, 0, 0, 116, 260,
*this, (HMENU)(UINT_PTR)(_baseID + 1), g_hInstance, NULL))
return false;
_listView.SetUnicodeFormat();
_listView._panel = this;
_listView.SetWindowProc();
_listView.SetImageList(GetSysImageList(true), LVSIL_SMALL);
_listView.SetImageList(GetSysImageList(false), LVSIL_NORMAL);
// _exStyle |= LVS_EX_HEADERDRAGDROP;
// DWORD extendedStyle = _listView.GetExtendedListViewStyle();
// extendedStyle |= _exStyle;
// _listView.SetExtendedListViewStyle(extendedStyle);
SetExtendedStyle();
_listView.Show(SW_SHOW);
_listView.InvalidateRect(NULL, true);
_listView.Update();
// Ensure that the common control DLL is loaded.
INITCOMMONCONTROLSEX icex;
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_BAR_CLASSES;
InitCommonControlsEx(&icex);
const TBBUTTON tbb[] =
{
// {0, 0, TBSTATE_ENABLED, BTNS_SEP, 0L, 0},
{VIEW_PARENTFOLDER, kParentFolderID, TBSTATE_ENABLED, BTNS_BUTTON, { 0, 0 }, 0, 0 },
// {0, 0, TBSTATE_ENABLED, BTNS_SEP, 0L, 0},
// {VIEW_NEWFOLDER, kCreateFolderID, TBSTATE_ENABLED, BTNS_BUTTON, 0L, 0},
};
#ifndef UNDER_CE
if (g_ComCtl32Version >= MAKELONG(71, 4))
#endif
{
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_COOL_CLASSES | ICC_BAR_CLASSES;
InitCommonControlsEx(&icex);
// if there is no CCS_NOPARENTALIGN, there is space of some pixels after rebar (Incorrect GetWindowRect ?)
_headerReBar.Attach(::CreateWindowEx(WS_EX_TOOLWINDOW,
REBARCLASSNAME,
NULL, WS_VISIBLE | WS_BORDER | WS_CHILD |
WS_CLIPCHILDREN | WS_CLIPSIBLINGS
| CCS_NODIVIDER
| CCS_NOPARENTALIGN
| CCS_TOP
| RBS_VARHEIGHT
| RBS_BANDBORDERS
,0,0,0,0, *this, NULL, g_hInstance, NULL));
}
DWORD toolbarStyle = WS_CHILD | WS_VISIBLE ;
if (_headerReBar)
{
toolbarStyle |= 0
// | WS_CLIPCHILDREN
// | WS_CLIPSIBLINGS
| TBSTYLE_TOOLTIPS
| CCS_NODIVIDER
| CCS_NORESIZE
| TBSTYLE_FLAT
;
}
_headerToolBar.Attach(::CreateToolbarEx ((*this), toolbarStyle,
_baseID + 2, 11,
(HINSTANCE)HINST_COMMCTRL,
IDB_VIEW_SMALL_COLOR,
(LPCTBBUTTON)&tbb, Z7_ARRAY_SIZE(tbb),
0, 0, 0, 0, sizeof (TBBUTTON)));
#ifndef UNDER_CE
// Load ComboBoxEx class
icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
icex.dwICC = ICC_USEREX_CLASSES;
InitCommonControlsEx(&icex);
#endif
_headerComboBox.CreateEx(0,
#ifdef UNDER_CE
WC_COMBOBOXW
#else
WC_COMBOBOXEXW
#endif
, NULL,
WS_BORDER | WS_VISIBLE |WS_CHILD | CBS_DROPDOWN | CBS_AUTOHSCROLL,
0, 0, 100, 520,
(_headerReBar ? _headerToolBar : (HWND)*this),
(HMENU)(UINT_PTR)(_comboBoxID),
g_hInstance, NULL);
#ifndef UNDER_CE
_headerComboBox.SetUnicodeFormat(true);
_headerComboBox.SetImageList(GetSysImageList(true));
_headerComboBox.SetExtendedStyle(CBES_EX_PATHWORDBREAKPROC, CBES_EX_PATHWORDBREAKPROC);
/*
_headerComboBox.SetUserDataLongPtr(LONG_PTR(&_headerComboBox));
_headerComboBox._panel = this;
_headerComboBox._origWindowProc =
(WNDPROC)_headerComboBox.SetLongPtr(GWLP_WNDPROC,
LONG_PTR(ComboBoxSubclassProc));
*/
_comboBoxEdit.Attach(_headerComboBox.GetEditControl());
// _comboBoxEdit.SendMessage(CCM_SETUNICODEFORMAT, (WPARAM)(BOOL)TRUE, 0);
_comboBoxEdit.SetUserDataLongPtr(LONG_PTR(&_comboBoxEdit));
_comboBoxEdit._panel = this;
#ifndef _UNICODE
if (g_IsNT)
_comboBoxEdit._origWindowProc =
(WNDPROC)_comboBoxEdit.SetLongPtrW(GWLP_WNDPROC, LONG_PTR(ComboBoxEditSubclassProc));
else
#endif
_comboBoxEdit._origWindowProc =
(WNDPROC)_comboBoxEdit.SetLongPtr(GWLP_WNDPROC, LONG_PTR(ComboBoxEditSubclassProc));
#endif
if (_headerReBar)
{
REBARINFO rbi;
rbi.cbSize = sizeof(REBARINFO); // Required when using this struct.
rbi.fMask = 0;
rbi.himl = (HIMAGELIST)NULL;
_headerReBar.SetBarInfo(&rbi);
// Send the TB_BUTTONSTRUCTSIZE message, which is required for
// backward compatibility.
// _headerToolBar.SendMessage(TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
SIZE size;
_headerToolBar.GetMaxSize(&size);
REBARBANDINFO rbBand;
memset(&rbBand, 0, sizeof(rbBand));
// rbBand.cbSize = sizeof(rbBand); // for debug
// rbBand.cbSize = REBARBANDINFO_V3_SIZE; // for debug
rbBand.cbSize = my_compatib_REBARBANDINFO_size;
rbBand.fMask = RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE;
rbBand.fStyle = RBBS_NOGRIPPER;
rbBand.cxMinChild = (UINT)size.cx;
rbBand.cyMinChild = (UINT)size.cy;
rbBand.cyChild = (UINT)size.cy;
rbBand.cx = (UINT)size.cx;
rbBand.hwndChild = _headerToolBar;
_headerReBar.InsertBand(-1, &rbBand);
RECT rc;
::GetWindowRect(_headerComboBox, &rc);
rbBand.cxMinChild = 30;
rbBand.cyMinChild = (UINT)(rc.bottom - rc.top);
rbBand.cx = 1000;
rbBand.hwndChild = _headerComboBox;
_headerReBar.InsertBand(-1, &rbBand);
// _headerReBar.MaximizeBand(1, false);
}
_statusBar.Create(WS_CHILD | WS_VISIBLE, L"Status", (*this), _statusBarID);
// _statusBar2.Create(WS_CHILD | WS_VISIBLE, L"Status", (*this), _statusBarID + 1);
const int sizes[] = {220, 320, 420, -1};
_statusBar.SetParts(4, sizes);
// _statusBar2.SetParts(5, sizes);
/*
RECT rect;
GetClientRect(&rect);
OnSize(0, RECT_SIZE_X(rect), RECT_SIZE_Y(rect));
*/
SetTimer(kTimerID, kTimerElapse);
// InitListCtrl();
RefreshListCtrl();
return true;
}
void CPanel::OnDestroy()
{
SaveListViewInfo();
CWindow2::OnDestroy();
}
void CPanel::ChangeWindowSize(int xSize, int ySize)
{
if (!(HWND)*this)
return;
int kHeaderSize;
int kStatusBarSize;
// int kStatusBar2Size;
RECT rect;
if (_headerReBar)
_headerReBar.GetWindowRect(&rect);
else
_headerToolBar.GetWindowRect(&rect);
kHeaderSize = RECT_SIZE_Y(rect);
_statusBar.GetWindowRect(&rect);
kStatusBarSize = RECT_SIZE_Y(rect);
// _statusBar2.GetWindowRect(&rect);
// kStatusBar2Size = RECT_SIZE_Y(rect);
int yListViewSize = MyMax(ySize - kHeaderSize - kStatusBarSize, 0);
const int kStartXPos = 32;
if (_headerReBar)
{
}
else
{
_headerToolBar.Move(0, 0, xSize, 0);
_headerComboBox.Move(kStartXPos, 2,
MyMax(xSize - kStartXPos - 10, kStartXPos), 0);
}
_listView.Move(0, kHeaderSize, xSize, yListViewSize);
_statusBar.Move(0, kHeaderSize + yListViewSize, xSize, kStatusBarSize);
// _statusBar2.MoveWindow(0, kHeaderSize + yListViewSize + kStatusBarSize, xSize, kStatusBar2Size);
// _statusBar.MoveWindow(0, 100, xSize, kStatusBarSize);
// _statusBar2.MoveWindow(0, 200, xSize, kStatusBar2Size);
}
bool CPanel::OnSize(WPARAM /* wParam */, int xSize, int ySize)
{
if (!(HWND)*this)
return true;
if (_headerReBar)
_headerReBar.Move(0, 0, xSize, 0);
ChangeWindowSize(xSize, ySize);
return true;
}
bool CPanel::OnNotifyReBar(LPNMHDR header, LRESULT & /* result */)
{
switch (header->code)
{
case RBN_HEIGHTCHANGE:
{
RECT rect;
GetWindowRect(&rect);
ChangeWindowSize(RECT_SIZE_X(rect), RECT_SIZE_Y(rect));
return false;
}
}
return false;
}
/*
UInt32 g_OnNotify = 0;
UInt32 g_LVIF_TEXT = 0;
UInt32 g_Time = 0;
void Print_OnNotify(const char *name)
{
char s[256];
DWORD tim = GetTickCount();
sprintf(s,
"Time = %7u ms, Notify = %9u, TEXT = %9u, %s",
tim - g_Time,
g_OnNotify,
g_LVIF_TEXT,
name);
g_Time = tim;
OutputDebugStringA(s);
g_OnNotify = 0;
g_LVIF_TEXT = 0;
}
*/
bool CPanel::OnNotify(UINT /* controlID */, LPNMHDR header, LRESULT &result)
{
/*
g_OnNotify++;
if (header->hwndFrom == _listView)
{
if (header->code == LVN_GETDISPINFOW)
{
LV_DISPINFOW *dispInfo = (LV_DISPINFOW *)header;
if ((dispInfo->item.mask & LVIF_TEXT))
g_LVIF_TEXT++;
}
}
*/
if (!_processNotify)
return false;
if (header->hwndFrom == _headerComboBox)
return OnNotifyComboBox(header, result);
else if (header->hwndFrom == _headerReBar)
return OnNotifyReBar(header, result);
else if (header->hwndFrom == _listView)
return OnNotifyList(header, result);
else if (::GetParent(header->hwndFrom) == _listView)
{
// NMHDR:code is UINT
// NM_RCLICK is unsigned in windows sdk
// NM_RCLICK is int in MinGW
if (header->code == (UINT)NM_RCLICK)
return OnRightClick((MY_NMLISTVIEW_NMITEMACTIVATE *)header, result);
}
return false;
}
bool CPanel::OnCommand(unsigned code, unsigned itemID, LPARAM lParam, LRESULT &result)
{
if (itemID == kParentFolderID)
{
OpenParentFolder();
result = 0;
return true;
}
/*
if (itemID == kCreateFolderID)
{
CreateFolder();
result = 0;
return true;
}
*/
if (itemID == _comboBoxID)
{
if (OnComboBoxCommand(code, lParam, result))
return true;
}
return CWindow2::OnCommand(code, itemID, lParam, result);
}
/*
void CPanel::MessageBox_Info(LPCWSTR message, LPCWSTR caption) const
{ ::MessageBoxW((HWND)*this, message, caption, MB_OK); }
void CPanel::MessageBox_Warning(LPCWSTR message) const
{ ::MessageBoxW((HWND)*this, message, L"7-Zip", MB_OK | MB_ICONWARNING); }
*/
void CPanel::MessageBox_Error_Caption(LPCWSTR message, LPCWSTR caption) const
{ ::MessageBoxW((HWND)*this, message, caption, MB_OK | MB_ICONSTOP); }
void CPanel::MessageBox_Error(LPCWSTR message) const
{ MessageBox_Error_Caption(message, L"7-Zip"); }
static UString ErrorHResult_To_Message(HRESULT errorCode)
{
if (errorCode == 0)
errorCode = E_FAIL;
return HResultToMessage(errorCode);
}
void CPanel::MessageBox_Error_HRESULT_Caption(HRESULT errorCode, LPCWSTR caption) const
{
MessageBox_Error_Caption(ErrorHResult_To_Message(errorCode), caption);
}
void CPanel::MessageBox_Error_HRESULT(HRESULT errorCode) const
{ MessageBox_Error_HRESULT_Caption(errorCode, L"7-Zip"); }
void CPanel::MessageBox_Error_2Lines_Message_HRESULT(LPCWSTR message, HRESULT errorCode) const
{
UString m = message;
m.Add_LF();
m += ErrorHResult_To_Message(errorCode);
MessageBox_Error(m);
}
void CPanel::MessageBox_LastError(LPCWSTR caption) const
{ MessageBox_Error_HRESULT_Caption(GetLastError_noZero_HRESULT(), caption); }
void CPanel::MessageBox_LastError() const
{ MessageBox_LastError(L"7-Zip"); }
void CPanel::MessageBox_Error_LangID(UINT resourceID) const
{ MessageBox_Error(LangString(resourceID)); }
void CPanel::MessageBox_Error_UnsupportOperation() const
{ MessageBox_Error_LangID(IDS_OPERATION_IS_NOT_SUPPORTED); }
void CPanel::SetFocusToList()
{
_listView.SetFocus();
// SetCurrentPathText();
}
void CPanel::SetFocusToLastRememberedItem()
{
if (_lastFocusedIsList)
SetFocusToList();
else
_headerComboBox.SetFocus();
}
UString CPanel::GetFolderTypeID() const
{
{
NCOM::CPropVariant prop;
if (_folder->GetFolderProperty(kpidType, &prop) == S_OK)
if (prop.vt == VT_BSTR)
return (const wchar_t *)prop.bstrVal;
}
return UString();
}
bool CPanel::IsFolderTypeEqTo(const char *s) const
{
return StringsAreEqual_Ascii(GetFolderTypeID(), s);
}
bool CPanel::IsRootFolder() const { return IsFolderTypeEqTo("RootFolder"); }
bool CPanel::IsFSFolder() const { return IsFolderTypeEqTo("FSFolder"); }
bool CPanel::IsFSDrivesFolder() const { return IsFolderTypeEqTo("FSDrives"); }
bool CPanel::IsAltStreamsFolder() const { return IsFolderTypeEqTo("AltStreamsFolder"); }
bool CPanel::IsArcFolder() const
{
return GetFolderTypeID().IsPrefixedBy_Ascii_NoCase("7-Zip");
}
bool CPanel::IsHashFolder() const
{
if (_folder)
{
NCOM::CPropVariant prop;
if (_folder->GetFolderProperty(kpidIsHash, &prop) == S_OK)
if (prop.vt == VT_BOOL)
return VARIANT_BOOLToBool(prop.boolVal);
}
return false;
}
UString CPanel::GetFsPath() const
{
if (IsFSDrivesFolder() && !IsDeviceDrivesPrefix() && !IsSuperDrivesPrefix())
return UString();
return _currentFolderPrefix;
}
UString CPanel::GetDriveOrNetworkPrefix() const
{
if (!IsFSFolder())
return UString();
UString drive = GetFsPath();
drive.DeleteFrom(NFile::NName::GetRootPrefixSize(drive));
return drive;
}
void CPanel::SetListViewMode(UInt32 index)
{
if (index >= 4)
return;
_listViewMode = index;
const LONG_PTR oldStyle = _listView.GetStyle();
const DWORD newStyle = kStyles[index];
// DWORD tickCount1 = GetTickCount();
if ((oldStyle & LVS_TYPEMASK) != (LONG_PTR)newStyle)
_listView.SetStyle((oldStyle & ~(LONG_PTR)(DWORD)LVS_TYPEMASK) | (LONG_PTR)newStyle);
// RefreshListCtrlSaveFocused();
/*
DWORD tickCount2 = GetTickCount();
char s[256];
sprintf(s, "SetStyle = %5d",
tickCount2 - tickCount1
);
OutputDebugStringA(s);
*/
}
void CPanel::ChangeFlatMode()
{
_flatMode = !_flatMode;
if (_parentFolders.Size() > 0)
_flatModeForArc = _flatMode;
else
_flatModeForDisk = _flatMode;
RefreshListCtrl_SaveFocused();
}
/*
void CPanel::Change_ShowNtfsStrems_Mode()
{
_showNtfsStrems_Mode = !_showNtfsStrems_Mode;
if (_parentFolders.Size() > 0)
_showNtfsStrems_ModeForArc = _showNtfsStrems_Mode;
else
_showNtfsStrems_ModeForDisk = _showNtfsStrems_Mode;
RefreshListCtrlSaveFocused();
}
*/
void CPanel::Post_Refresh_StatusBar()
{
if (_processStatusBar)
PostMsg(kRefresh_StatusBar);
}
void CPanel::AddToArchive()
{
if (!Is_IO_FS_Folder())
{
MessageBox_Error_UnsupportOperation();
return;
}
CRecordVector<UInt32> indices;
Get_ItemIndices_Operated(indices);
if (indices.Size() == 0)
{
MessageBox_Error_LangID(IDS_SELECT_FILES);
return;
}
UString destCurDirPrefix = GetFsPath();
if (IsFSDrivesFolder())
destCurDirPrefix = ROOT_FS_FOLDER;
UStringVector names;
GetFilePaths(indices, names);
UString baseName;
const UString arcName = CreateArchiveName(names,
false, // isHash
NULL, // CFileInfo *fi
baseName);
const HRESULT res = CompressFiles(destCurDirPrefix, arcName, L"",
true, // addExtension
names,
false, // email
true, // showDialog
false); // waitFinish
if (res != S_OK)
{
if (destCurDirPrefix.Len() >= MAX_PATH)
MessageBox_Error_LangID(IDS_MESSAGE_UNSUPPORTED_OPERATION_FOR_LONG_PATH_FOLDER);
}
// KillSelection();
}
// function from ContextMenu.cpp
UString GetSubFolderNameForExtract(const UString &arcPath);
static UString GetSubFolderNameForExtract2(const UString &arcPath)
{
int slashPos = arcPath.ReverseFind_PathSepar();
UString s;
UString name = arcPath;
if (slashPos >= 0)
{
s = arcPath.Left((unsigned)(slashPos + 1));
name = arcPath.Ptr((unsigned)(slashPos + 1));
}
s += GetSubFolderNameForExtract(name);
return s;
}
int CPanel::FindDir_InOperatedList(const CRecordVector<UInt32> &operatedIndices) const
{
const bool *isDirVector = &_isDirVector.Front();
const UInt32 *indices = &operatedIndices.Front();
const unsigned numItems = operatedIndices.Size();
for (unsigned i = 0; i < numItems; i++)
if (isDirVector[indices[i]])
return (int)i;
return -1;
}
void CPanel::GetFilePaths(const CRecordVector<UInt32> &operatedIndices, UStringVector &paths) const
{
paths.ClearAndReserve(operatedIndices.Size());
UString path = GetFsPath();
const unsigned prefixLen = path.Len();
const UInt32 *indices = &operatedIndices.Front();
const unsigned numItems = operatedIndices.Size();
// for (unsigned y = 0; y < 10000; y++, paths.Clear())
for (unsigned i = 0; i < numItems; i++)
{
path.DeleteFrom(prefixLen);
Add_ItemRelPath2_To_String(indices[i], path);
// ODS_U(path)
paths.AddInReserved(path);
}
}
void CPanel::ExtractArchives()
{
if (_parentFolders.Size() > 0)
{
_panelCallback->OnCopy(false, false);
return;
}
CRecordVector<UInt32> indices;
Get_ItemIndices_Operated(indices);
if (indices.IsEmpty() || FindDir_InOperatedList(indices) != -1)
{
MessageBox_Error_LangID(IDS_SELECT_FILES);
return;
}
UStringVector paths;
GetFilePaths(indices, paths);
UString outFolder = GetFsPath();
if (indices.Size() == 1)
outFolder += GetSubFolderNameForExtract2(GetItemRelPath(indices[0]));
else
outFolder += '*';
outFolder.Add_PathSepar();
CContextMenuInfo ci;
ci.Load();
::ExtractArchives(paths, outFolder
, true // showDialog
, false // elimDup
, ci.WriteZone
);
}
/*
static void AddValuePair(UINT resourceID, UInt64 value, UString &s)
{
AddLangString(s, resourceID);
char sz[32];
s += ": ";
ConvertUInt64ToString(value, sz);
s += sz;
s.Add_LF();
}
// now we don't need CThreadTest, since now we call CopyTo for "test command
class CThreadTest: public CProgressThreadVirt
{
HRESULT ProcessVirt();
public:
CRecordVector<UInt32> Indices;
CExtractCallbackImp *ExtractCallbackSpec;
CMyComPtr<IFolderArchiveExtractCallback> ExtractCallback;
CMyComPtr<IArchiveFolder> ArchiveFolder;
};
HRESULT CThreadTest::ProcessVirt()
{
RINOK(ArchiveFolder->Extract(&Indices[0], Indices.Size(),
true, // includeAltStreams
false, // replaceAltStreamColon
NExtract::NPathMode::kFullPathnames,
NExtract::NOverwriteMode::kAskBefore,
NULL, // path
BoolToInt(true), // testMode
ExtractCallback));
if (ExtractCallbackSpec->IsOK())
{
UString s;
AddValuePair(IDS_PROP_FOLDERS, ExtractCallbackSpec->NumFolders, s);
AddValuePair(IDS_PROP_FILES, ExtractCallbackSpec->NumFiles, s);
// AddValuePair(IDS_PROP_SIZE, ExtractCallbackSpec->UnpackSize, s);
// AddSizePair(IDS_COMPRESSED_COLON, Stat.PackSize, s);
s.Add_LF();
AddLangString(s, IDS_MESSAGE_NO_ERRORS);
FinalMessage.OkMessage.Message = s;
}
return S_OK;
}
static void AddSizePair(UInt32 langID, UInt64 value, UString &s)
{
char sz[32];
AddLangString(s, langID);
s += L' ';
ConvertUInt64ToString(value, sz);
s += sz;
ConvertUInt64ToString(value >> 20, sz);
s += " (";
s += sz;
s += " MB)";
s.Add_LF();
}
*/
void CPanel::TestArchives()
{
CRecordVector<UInt32> indices;
Get_ItemIndices_OperSmart(indices);
CMyComPtr<IArchiveFolder> archiveFolder;
_folder.QueryInterface(IID_IArchiveFolder, &archiveFolder);
if (archiveFolder)
{
CCopyToOptions options;
options.streamMode = true;
options.showErrorMessages = true;
options.testMode = true;
UStringVector messages;
HRESULT res = CopyTo(options, indices, &messages);
if (res != S_OK)
{
if (res != E_ABORT)
MessageBox_Error_HRESULT(res);
}
return;
/*
{
CThreadTest extracter;
extracter.ArchiveFolder = archiveFolder;
extracter.ExtractCallbackSpec = new CExtractCallbackImp;
extracter.ExtractCallback = extracter.ExtractCallbackSpec;
extracter.ExtractCallbackSpec->ProgressDialog = &extracter.ProgressDialog;
if (!_parentFolders.IsEmpty())
{
const CFolderLink &fl = _parentFolders.Back();
extracter.ExtractCallbackSpec->PasswordIsDefined = fl.UsePassword;
extracter.ExtractCallbackSpec->Password = fl.Password;
}
if (indices.IsEmpty())
return;
extracter.Indices = indices;
const UString title = LangString(IDS_PROGRESS_TESTING);
extracter.ProgressDialog.CompressingMode = false;
extracter.ProgressDialog.MainWindow = GetParent();
extracter.ProgressDialog.MainTitle = "7-Zip"; // LangString(IDS_APP_TITLE);
extracter.ProgressDialog.MainAddTitle = title + L' ';
extracter.ExtractCallbackSpec->OverwriteMode = NExtract::NOverwriteMode::kAskBefore;
extracter.ExtractCallbackSpec->Init();
if (extracter.Create(title, GetParent()) != S_OK)
return;
}
RefreshTitleAlways();
return;
*/
}
if (!IsFSFolder())
{
MessageBox_Error_UnsupportOperation();
return;
}
UStringVector paths;
GetFilePaths(indices, paths);
if (paths.IsEmpty())
{
MessageBox_Error_LangID(IDS_SELECT_FILES);
return;
}
::TestArchives(paths);
}