blob: 09d8a72d688fed8a41852e63eabe0c78b7a9ac10 [file] [log] [blame]
// SystemPage.cpp
#include "StdAfx.h"
#include "../../../Common/MyWindows.h"
#if defined(__MINGW32__) || defined(__MINGW64__)
#include <shlobj.h>
#else
#include <ShlObj.h>
#endif
#include "../../../Common/Defs.h"
#include "../../../Common/StringConvert.h"
#include "../../../Windows/DLL.h"
#include "../../../Windows/ErrorMsg.h"
#include "HelpUtils.h"
#include "IFolder.h"
#include "LangUtils.h"
#include "PropertyNameRes.h"
#include "SystemPage.h"
#include "SystemPageRes.h"
using namespace NWindows;
#ifndef _UNICODE
extern bool g_IsNT;
#endif
#ifdef Z7_LANG
static const UInt32 kLangIDs[] =
{
IDT_SYSTEM_ASSOCIATE
};
#endif
#define kSystemTopic "FM/options.htm#system"
CSysString CModifiedExtInfo::GetString() const
{
const char *s;
if (State == kExtState_7Zip)
s = "7-Zip";
else if (State == kExtState_Clear)
s = "";
else if (Other7Zip)
s = "[7-Zip]";
else
return ProgramKey;
return CSysString (s);
}
int CSystemPage::AddIcon(const UString &iconPath, int iconIndex)
{
if (iconPath.IsEmpty())
return -1;
if (iconIndex == -1)
iconIndex = 0;
HICON hicon;
#ifdef UNDER_CE
ExtractIconExW(iconPath, iconIndex, NULL, &hicon, 1);
if (!hicon)
#else
// we expand path from REG_EXPAND_SZ registry item.
UString path;
const DWORD size = MAX_PATH + 10;
const DWORD needLen = ::ExpandEnvironmentStringsW(iconPath, path.GetBuf(size + 2), size);
path.ReleaseBuf_CalcLen(size);
if (needLen == 0 || needLen >= size)
path = iconPath;
const UINT num = ExtractIconExW(path, iconIndex, NULL, &hicon, 1);
if (num != 1 || !hicon)
#endif
return -1;
_imageList.AddIcon(hicon);
DestroyIcon(hicon);
return (int)(_numIcons++);
}
void CSystemPage::RefreshListItem(unsigned group, unsigned listIndex)
{
const CAssoc &assoc = _items[GetRealIndex(listIndex)];
_listView.SetSubItem(listIndex, group + 1, assoc.Pair[group].GetString());
LVITEMW newItem;
memset(&newItem, 0, sizeof(newItem));
newItem.iItem = (int)listIndex;
newItem.mask = LVIF_IMAGE;
newItem.iImage = assoc.GetIconIndex();
_listView.SetItem(&newItem);
}
void CSystemPage::ChangeState(unsigned group, const CUIntVector &indices)
{
if (indices.IsEmpty())
return;
bool thereAreClearItems = false;
unsigned counters[3] = { 0, 0, 0 };
unsigned i;
for (i = 0; i < indices.Size(); i++)
{
const CModifiedExtInfo &mi = _items[GetRealIndex(indices[i])].Pair[group];
int state = kExtState_7Zip;
if (mi.State == kExtState_7Zip)
state = kExtState_Clear;
else if (mi.State == kExtState_Clear)
{
thereAreClearItems = true;
if (mi.Other)
state = kExtState_Other;
}
counters[state]++;
}
int state = kExtState_Clear;
if (counters[kExtState_Other] != 0)
state = kExtState_Other;
else if (counters[kExtState_7Zip] != 0)
state = kExtState_7Zip;
for (i = 0; i < indices.Size(); i++)
{
unsigned listIndex = indices[i];
CAssoc &assoc = _items[GetRealIndex(listIndex)];
CModifiedExtInfo &mi = assoc.Pair[group];
bool change = false;
switch (state)
{
case kExtState_Clear: change = true; break;
case kExtState_Other: change = mi.Other; break;
default: change = !(mi.Other && thereAreClearItems); break;
}
if (change)
{
mi.State = state;
RefreshListItem(group, listIndex);
}
}
_needSave = true;
Changed();
}
bool CSystemPage::OnInit()
{
_needSave = false;
#ifdef Z7_LANG
LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs));
#endif
_listView.Attach(GetItem(IDL_SYSTEM_ASSOCIATE));
_listView.SetUnicodeFormat();
DWORD newFlags = LVS_EX_FULLROWSELECT;
_listView.SetExtendedListViewStyle(newFlags, newFlags);
_numIcons = 0;
_imageList.Create(16, 16, ILC_MASK | ILC_COLOR32, 0, 0);
_listView.SetImageList(_imageList, LVSIL_SMALL);
_listView.InsertColumn(0, LangString(IDS_PROP_FILE_TYPE), 72);
UString s;
#if NUM_EXT_GROUPS == 1
s = "Program";
#else
#ifndef UNDER_CE
const unsigned kSize = 256;
BOOL res;
DWORD size = kSize;
#ifndef _UNICODE
if (!g_IsNT)
{
AString s2;
res = GetUserNameA(s2.GetBuf(size), &size);
s2.ReleaseBuf_CalcLen(MyMin((unsigned)size, kSize));
s = GetUnicodeString(s2);
}
else
#endif
{
res = GetUserNameW(s.GetBuf(size), &size);
s.ReleaseBuf_CalcLen(MyMin((unsigned)size, kSize));
}
if (!res)
#endif
s = "Current User";
#endif
LV_COLUMNW ci;
ci.mask = LVCF_TEXT | LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM;
ci.cx = 128;
ci.fmt = LVCFMT_CENTER;
ci.pszText = s.Ptr_non_const();
ci.iSubItem = 1;
_listView.InsertColumn(1, &ci);
#if NUM_EXT_GROUPS > 1
{
LangString(IDS_SYSTEM_ALL_USERS, s);
ci.pszText = s.Ptr_non_const();
ci.iSubItem = 2;
_listView.InsertColumn(2, &ci);
}
#endif
_extDB.Read();
_items.Clear();
FOR_VECTOR (i, _extDB.Exts)
{
const CExtPlugins &extInfo = _extDB.Exts[i];
LVITEMW item;
item.iItem = (int)i;
item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
item.lParam = (LPARAM)i;
item.iSubItem = 0;
// ListView always uses internal iImage that is 0 by default?
// so we always use LVIF_IMAGE.
item.iImage = -1;
item.pszText = extInfo.Ext.Ptr_non_const();
CAssoc assoc;
const CPluginToIcon &plug = extInfo.Plugins[0];
assoc.SevenZipImageIndex = AddIcon(plug.IconPath, plug.IconIndex);
CSysString texts[NUM_EXT_GROUPS];
unsigned g;
for (g = 0; g < NUM_EXT_GROUPS; g++)
{
CModifiedExtInfo &mi = assoc.Pair[g];
mi.ReadFromRegistry(GetHKey(g), GetSystemString(extInfo.Ext));
mi.SetState(plug.IconPath);
mi.ImageIndex = AddIcon(mi.IconPath, mi.IconIndex);
texts[g] = mi.GetString();
}
item.iImage = assoc.GetIconIndex();
const int itemIndex = _listView.InsertItem(&item);
for (g = 0; g < NUM_EXT_GROUPS; g++)
_listView.SetSubItem((unsigned)itemIndex, 1 + g, texts[g]);
_items.Add(assoc);
}
if (_listView.GetItemCount() > 0)
_listView.SetItemState(0, LVIS_FOCUSED, LVIS_FOCUSED);
return CPropertyPage::OnInit();
}
static UString GetProgramCommand()
{
UString s ('\"');
s += fs2us(NDLL::GetModuleDirPrefix());
s += "7zFM.exe\" \"%1\"";
return s;
}
LONG CSystemPage::OnApply()
{
if (!_needSave)
return PSNRET_NOERROR;
const UString command = GetProgramCommand();
LONG res = 0;
FOR_VECTOR (listIndex, _extDB.Exts)
{
unsigned realIndex = GetRealIndex(listIndex);
const CExtPlugins &extInfo = _extDB.Exts[realIndex];
CAssoc &assoc = _items[realIndex];
for (unsigned g = 0; g < NUM_EXT_GROUPS; g++)
{
CModifiedExtInfo &mi = assoc.Pair[g];
HKEY key = GetHKey(g);
if (mi.OldState != mi.State)
{
LONG res2 = 0;
if (mi.State == kExtState_7Zip)
{
UString title = extInfo.Ext;
title += " Archive";
const CPluginToIcon &plug = extInfo.Plugins[0];
res2 = NRegistryAssoc::AddShellExtensionInfo(key, GetSystemString(extInfo.Ext),
title, command, plug.IconPath, plug.IconIndex);
}
else if (mi.State == kExtState_Clear)
res2 = NRegistryAssoc::DeleteShellExtensionInfo(key, GetSystemString(extInfo.Ext));
if (res == 0)
res = res2;
if (res2 == 0)
mi.OldState = mi.State;
mi.State = mi.OldState;
RefreshListItem(g, listIndex);
}
}
}
#ifndef UNDER_CE
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
#endif
WasChanged = true;
_needSave = false;
if (res != 0)
MessageBoxW(*this, NError::MyFormatMessage(res), L"7-Zip", MB_ICONERROR);
return PSNRET_NOERROR;
}
void CSystemPage::OnNotifyHelp()
{
ShowHelpWindow(kSystemTopic);
}
bool CSystemPage::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
{
switch (buttonID)
{
/*
case IDC_SYSTEM_SELECT_ALL:
_listView.SelectAll();
return true;
*/
case IDB_SYSTEM_CURRENT:
case IDB_SYSTEM_ALL:
ChangeState(buttonID == IDB_SYSTEM_CURRENT ? 0 : 1);
return true;
}
return CPropertyPage::OnButtonClicked(buttonID, buttonHWND);
}
bool CSystemPage::OnNotify(UINT controlID, LPNMHDR lParam)
{
if (lParam->hwndFrom == HWND(_listView))
{
switch (lParam->code)
{
case NM_RETURN:
{
ChangeState(0);
return true;
}
case NM_CLICK:
{
#ifdef UNDER_CE
NMLISTVIEW *item = (NMLISTVIEW *)lParam;
#else
NMITEMACTIVATE *item = (NMITEMACTIVATE *)lParam;
if (item->uKeyFlags == 0)
#endif
{
if (item->iItem >= 0)
{
// unsigned realIndex = GetRealIndex(item->iItem);
if (item->iSubItem >= 1 && item->iSubItem <= 2)
{
CUIntVector indices;
indices.Add((unsigned)item->iItem);
ChangeState(item->iSubItem < 2 ? 0 : 1, indices);
}
}
}
break;
}
case LVN_KEYDOWN:
{
if (OnListKeyDown(LPNMLVKEYDOWN(lParam)))
return true;
break;
}
/*
case NM_RCLICK:
case NM_DBLCLK:
case LVN_BEGINRDRAG:
// PostMessage(kRefreshpluginsListMessage, 0);
PostMessage(kUpdateDatabase, 0);
break;
*/
}
}
return CPropertyPage::OnNotify(controlID, lParam);
}
void CSystemPage::ChangeState(unsigned group)
{
CUIntVector indices;
int itemIndex = -1;
while ((itemIndex = _listView.GetNextSelectedItem(itemIndex)) != -1)
indices.Add((unsigned)itemIndex);
if (indices.IsEmpty())
FOR_VECTOR (i, _items)
indices.Add(i);
ChangeState(group, indices);
}
bool CSystemPage::OnListKeyDown(LPNMLVKEYDOWN keyDownInfo)
{
bool ctrl = IsKeyDown(VK_CONTROL);
bool alt = IsKeyDown(VK_MENU);
if (alt)
return false;
if ((ctrl && keyDownInfo->wVKey == 'A')
|| (!ctrl && keyDownInfo->wVKey == VK_MULTIPLY))
{
_listView.SelectAll();
return true;
}
switch (keyDownInfo->wVKey)
{
case VK_SPACE:
case VK_ADD:
case VK_SUBTRACT:
case VK_SEPARATOR:
case VK_DIVIDE:
#ifndef UNDER_CE
case VK_OEM_PLUS:
case VK_OEM_MINUS:
#endif
if (!ctrl)
{
ChangeState(keyDownInfo->wVKey == VK_SPACE ? 0 : 1);
return true;
}
break;
}
return false;
}