| // 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; |
| } |