From 1979fd80424d16b2e489f9b57d01d9c7811d25a2 Mon Sep 17 00:00:00 2001 From: dartraiden Date: Mon, 2 Jan 2023 21:10:29 +0300 Subject: Update copyrights --- plugins/QuickSearch/src/main.cpp | 376 +++---- plugins/QuickSearch/src/options.cpp | 1038 +++++++++--------- plugins/QuickSearch/src/stdafx.cxx | 34 +- plugins/QuickSearch/src/utils.cpp | 1112 ++++++++++---------- plugins/QuickSearch/src/version.h | 2 +- plugins/QuickSearch/src/window.cpp | 1752 +++++++++++++++---------------- plugins/QuickSearch/src/window_misc.cpp | 1750 +++++++++++++++--------------- plugins/QuickSearch/src/window_row.cpp | 448 ++++---- 8 files changed, 3256 insertions(+), 3256 deletions(-) (limited to 'plugins/QuickSearch/src') diff --git a/plugins/QuickSearch/src/main.cpp b/plugins/QuickSearch/src/main.cpp index cf068d7561..632bfb2aff 100644 --- a/plugins/QuickSearch/src/main.cpp +++ b/plugins/QuickSearch/src/main.cpp @@ -1,188 +1,188 @@ -/* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "stdafx.h" - -CMPlugin g_plugin; - -HANDLE hTTBButton; - -bool g_bVarsInstalled, g_bTipperInstalled, g_bFingerInstalled; - -int OnOptInit(WPARAM, LPARAM); - -///////////////////////////////////////////////////////////////////////////////////////// - -PLUGININFOEX pluginInfoEx = { - sizeof(PLUGININFOEX), - __PLUGIN_NAME, - PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), - __DESCRIPTION, - __AUTHOR, - __COPYRIGHT, - __AUTHORWEB, - UNICODE_AWARE, - // {49BD9F2A-3111-4EB9-87E3-71E69CD97F7C} - {0x49bd9f2a, 0x3111, 0x4eb9, {0x87, 0xe3, 0x71, 0xe6, 0x9c, 0xd9, 0x7f, 0x7c}} -}; - -CMPlugin::CMPlugin() : - PLUGIN(MODULENAME, pluginInfoEx), - m_columns(1) -{ -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static int OnTTBLoaded(WPARAM, LPARAM) -{ - TTBButton ttb = {}; - ttb.dwFlags = TTBBF_VISIBLE; - ttb.pszService = QS_SHOWSERVICE; - ttb.hIconHandleDn = ttb.hIconHandleUp = g_plugin.getIconHandle(IDI_QS); - ttb.name = MODULENAME; - ttb.pszTooltipUp = ttb.pszTooltipDn = LPGEN("Quick Search"); - hTTBButton = g_plugin.addTTB(&ttb); - return 0; -} - -static INT_PTR OpenSearchWindow(WPARAM wParam, LPARAM) -{ - OpenSrWindow((wchar_t *)wParam); - return 0; -} - -static int OnCheckPlugins(WPARAM, LPARAM) -{ - g_bVarsInstalled = ServiceExists(MS_VARS_FORMATSTRING); - g_bTipperInstalled = ServiceExists(MS_TIPPER_SHOWTIPW); - g_bFingerInstalled = ServiceExists(MS_FP_GETCLIENTICONW); - - return 0; -} - -static int OnModulesLoaded(WPARAM, LPARAM) -{ - HookEvent(ME_TTB_MODULELOADED, OnTTBLoaded); - - CreateServiceFunction(QS_SHOWSERVICE, OpenSearchWindow); - - // add menu item - CMenuItem mi(&g_plugin); - SET_UID(mi, 0x98C2A92A, 0xD93D, 0x43E8, 0x91, 0xC3, 0x3B, 0xB6, 0xBE, 0x43, 0x44, 0xF0); - mi.name.a = LPGEN("Quick Search"); - mi.position = 500050000; - mi.pszService = QS_SHOWSERVICE; - mi.hIcolibItem = g_plugin.getIconHandle(IDI_QS); - Menu_AddMainMenuItem(&mi); - - // register hotkey - HOTKEYDESC hkd = {}; - hkd.pszName = "QS_Global"; - hkd.szDescription.a = LPGEN("Open Quick Search window"); - hkd.szSection.a = LPGEN("Quick Search"); - hkd.pszService = QS_SHOWSERVICE; - hkd.DefHotKey = HOTKEYCODE(HOTKEYF_ALT, VK_F3); - g_plugin.addHotkey(&hkd); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static IconItem iconList[] = -{ - { LPGEN("Quick Search"), "QS", IDI_QS }, - { LPGEN("New Column"), "New", IDI_NEW }, - { LPGEN("Column Up"), "Up", IDI_UP }, - { LPGEN("Column Down"), "Down", IDI_DOWN }, - { LPGEN("Delete Column"), "Delete", IDI_DELETE }, - { LPGEN("Default"), "Default", IDI_DEFAULT}, - { LPGEN("Reload"), "Reload", IDI_RELOAD }, - { LPGEN("Male"), "Male", IDI_MALE }, - { LPGEN("Female"), "Female", IDI_FEMALE }, -}; - -struct -{ - COLORREF defValue; - const char *szSetting, *szDescr; -} -static sttColors[color_max] = { - { 0x00FFFFFF, "back_norm", LPGEN("Normal background") }, - { 0x00000000, "fore_norm", LPGEN("Normal foreground") }, - { 0x00EBE6DE, "back_odd" , LPGEN("Odd background") }, - { 0x00000000, "fore_odd" , LPGEN("Odd foreground") }, - { 0x008080FF, "back_dis" , LPGEN("Disabled account background") }, - { 0x00000000, "fore_dis" , LPGEN("Disabled account foreground") }, - { 0x008000FF, "back_del" , LPGEN("Deleted account background") }, - { 0x00000000, "fore_del" , LPGEN("Deleted account foreground") }, - { 0x0080FFFF, "back_hid" , LPGEN("Hidden contact background") }, - { 0x00000000, "fore_hid" , LPGEN("Hidden contact foreground") }, - { 0x00BAE699, "back_meta", LPGEN("Metacontact background") }, - { 0x00000000, "fore_meta", LPGEN("Metacontact foreground") }, - { 0x00B3CCC1, "back_sub" , LPGEN("Subcontact background") }, - { 0x00000000, "fore_sub" , LPGEN("Subcontact foreground") }, -}; - -static int OnColorReload(WPARAM, LPARAM) -{ - for (int i = 0; i < color_max; i++) - g_plugin.m_colors[i] = Colour_Get(MODULENAME, sttColors[i].szDescr); - return 0; -} - -int CMPlugin::Load() -{ - g_plugin.registerIcon(MODULENAME, iconList); - - ColourID colourid = {}; - strncpy_s(colourid.group, MODULENAME, _TRUNCATE); - strncpy_s(colourid.dbSettingsGroup, MODULENAME, _TRUNCATE); - - for (auto &it : sttColors) { - strncpy_s(colourid.name, it.szDescr, _TRUNCATE); - strncpy_s(colourid.setting, it.szSetting, _TRUNCATE); - colourid.defcolour = it.defValue; - colourid.order = int(&it - sttColors); - g_plugin.addColor(&colourid); - } - OnColorReload(0, 0); - OnCheckPlugins(0, 0); - - HookEvent(ME_COLOUR_RELOAD, OnColorReload); - HookEvent(ME_OPT_INITIALISE, OnOptInit); - HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded); - HookEvent(ME_SYSTEM_MODULELOAD, OnCheckPlugins); - HookEvent(ME_SYSTEM_MODULEUNLOAD, OnCheckPlugins); - - if (!LoadColumns(m_columns)) - LoadDefaultColumns(m_columns); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -int CMPlugin::Unload() -{ - if (hTTBButton) { - CallService(MS_TTB_REMOVEBUTTON, (WPARAM)hTTBButton, 0); - hTTBButton = 0; - } - - CloseSrWindow(); - return 0; -} +/* +Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "stdafx.h" + +CMPlugin g_plugin; + +HANDLE hTTBButton; + +bool g_bVarsInstalled, g_bTipperInstalled, g_bFingerInstalled; + +int OnOptInit(WPARAM, LPARAM); + +///////////////////////////////////////////////////////////////////////////////////////// + +PLUGININFOEX pluginInfoEx = { + sizeof(PLUGININFOEX), + __PLUGIN_NAME, + PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), + __DESCRIPTION, + __AUTHOR, + __COPYRIGHT, + __AUTHORWEB, + UNICODE_AWARE, + // {49BD9F2A-3111-4EB9-87E3-71E69CD97F7C} + {0x49bd9f2a, 0x3111, 0x4eb9, {0x87, 0xe3, 0x71, 0xe6, 0x9c, 0xd9, 0x7f, 0x7c}} +}; + +CMPlugin::CMPlugin() : + PLUGIN(MODULENAME, pluginInfoEx), + m_columns(1) +{ +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static int OnTTBLoaded(WPARAM, LPARAM) +{ + TTBButton ttb = {}; + ttb.dwFlags = TTBBF_VISIBLE; + ttb.pszService = QS_SHOWSERVICE; + ttb.hIconHandleDn = ttb.hIconHandleUp = g_plugin.getIconHandle(IDI_QS); + ttb.name = MODULENAME; + ttb.pszTooltipUp = ttb.pszTooltipDn = LPGEN("Quick Search"); + hTTBButton = g_plugin.addTTB(&ttb); + return 0; +} + +static INT_PTR OpenSearchWindow(WPARAM wParam, LPARAM) +{ + OpenSrWindow((wchar_t *)wParam); + return 0; +} + +static int OnCheckPlugins(WPARAM, LPARAM) +{ + g_bVarsInstalled = ServiceExists(MS_VARS_FORMATSTRING); + g_bTipperInstalled = ServiceExists(MS_TIPPER_SHOWTIPW); + g_bFingerInstalled = ServiceExists(MS_FP_GETCLIENTICONW); + + return 0; +} + +static int OnModulesLoaded(WPARAM, LPARAM) +{ + HookEvent(ME_TTB_MODULELOADED, OnTTBLoaded); + + CreateServiceFunction(QS_SHOWSERVICE, OpenSearchWindow); + + // add menu item + CMenuItem mi(&g_plugin); + SET_UID(mi, 0x98C2A92A, 0xD93D, 0x43E8, 0x91, 0xC3, 0x3B, 0xB6, 0xBE, 0x43, 0x44, 0xF0); + mi.name.a = LPGEN("Quick Search"); + mi.position = 500050000; + mi.pszService = QS_SHOWSERVICE; + mi.hIcolibItem = g_plugin.getIconHandle(IDI_QS); + Menu_AddMainMenuItem(&mi); + + // register hotkey + HOTKEYDESC hkd = {}; + hkd.pszName = "QS_Global"; + hkd.szDescription.a = LPGEN("Open Quick Search window"); + hkd.szSection.a = LPGEN("Quick Search"); + hkd.pszService = QS_SHOWSERVICE; + hkd.DefHotKey = HOTKEYCODE(HOTKEYF_ALT, VK_F3); + g_plugin.addHotkey(&hkd); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static IconItem iconList[] = +{ + { LPGEN("Quick Search"), "QS", IDI_QS }, + { LPGEN("New Column"), "New", IDI_NEW }, + { LPGEN("Column Up"), "Up", IDI_UP }, + { LPGEN("Column Down"), "Down", IDI_DOWN }, + { LPGEN("Delete Column"), "Delete", IDI_DELETE }, + { LPGEN("Default"), "Default", IDI_DEFAULT}, + { LPGEN("Reload"), "Reload", IDI_RELOAD }, + { LPGEN("Male"), "Male", IDI_MALE }, + { LPGEN("Female"), "Female", IDI_FEMALE }, +}; + +struct +{ + COLORREF defValue; + const char *szSetting, *szDescr; +} +static sttColors[color_max] = { + { 0x00FFFFFF, "back_norm", LPGEN("Normal background") }, + { 0x00000000, "fore_norm", LPGEN("Normal foreground") }, + { 0x00EBE6DE, "back_odd" , LPGEN("Odd background") }, + { 0x00000000, "fore_odd" , LPGEN("Odd foreground") }, + { 0x008080FF, "back_dis" , LPGEN("Disabled account background") }, + { 0x00000000, "fore_dis" , LPGEN("Disabled account foreground") }, + { 0x008000FF, "back_del" , LPGEN("Deleted account background") }, + { 0x00000000, "fore_del" , LPGEN("Deleted account foreground") }, + { 0x0080FFFF, "back_hid" , LPGEN("Hidden contact background") }, + { 0x00000000, "fore_hid" , LPGEN("Hidden contact foreground") }, + { 0x00BAE699, "back_meta", LPGEN("Metacontact background") }, + { 0x00000000, "fore_meta", LPGEN("Metacontact foreground") }, + { 0x00B3CCC1, "back_sub" , LPGEN("Subcontact background") }, + { 0x00000000, "fore_sub" , LPGEN("Subcontact foreground") }, +}; + +static int OnColorReload(WPARAM, LPARAM) +{ + for (int i = 0; i < color_max; i++) + g_plugin.m_colors[i] = Colour_Get(MODULENAME, sttColors[i].szDescr); + return 0; +} + +int CMPlugin::Load() +{ + g_plugin.registerIcon(MODULENAME, iconList); + + ColourID colourid = {}; + strncpy_s(colourid.group, MODULENAME, _TRUNCATE); + strncpy_s(colourid.dbSettingsGroup, MODULENAME, _TRUNCATE); + + for (auto &it : sttColors) { + strncpy_s(colourid.name, it.szDescr, _TRUNCATE); + strncpy_s(colourid.setting, it.szSetting, _TRUNCATE); + colourid.defcolour = it.defValue; + colourid.order = int(&it - sttColors); + g_plugin.addColor(&colourid); + } + OnColorReload(0, 0); + OnCheckPlugins(0, 0); + + HookEvent(ME_COLOUR_RELOAD, OnColorReload); + HookEvent(ME_OPT_INITIALISE, OnOptInit); + HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded); + HookEvent(ME_SYSTEM_MODULELOAD, OnCheckPlugins); + HookEvent(ME_SYSTEM_MODULEUNLOAD, OnCheckPlugins); + + if (!LoadColumns(m_columns)) + LoadDefaultColumns(m_columns); + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +int CMPlugin::Unload() +{ + if (hTTBButton) { + CallService(MS_TTB_REMOVEBUTTON, (WPARAM)hTTBButton, 0); + hTTBButton = 0; + } + + CloseSrWindow(); + return 0; +} diff --git a/plugins/QuickSearch/src/options.cpp b/plugins/QuickSearch/src/options.cpp index d827416ecc..d74cf745aa 100644 --- a/plugins/QuickSearch/src/options.cpp +++ b/plugins/QuickSearch/src/options.cpp @@ -1,519 +1,519 @@ -/* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "stdafx.h" - -class COptionsDlg : public CDlgBase -{ - OBJLIST m_columns; - - void AddColumn(int idx, ColumnItem *pCol) - { - LVITEM lvi = {}; - lvi.mask = LVIF_PARAM; - lvi.iItem = idx; - lvi.lParam = LPARAM(pCol); - m_list.InsertItem(&lvi); - } - - void CheckDirection(int iItem) - { - btnUp.Enable(iItem > 0); - btnDown.Enable(iItem < m_list.GetItemCount()-1); - } - - void ClearScreen() - { - // setting - ShowWindow(GetDlgItem(m_hwnd, IDC_S_DATATYPE), SW_HIDE); - ShowWindow(GetDlgItem(m_hwnd, IDC_C_DATATYPE), SW_HIDE); - ShowWindow(GetDlgItem(m_hwnd, IDC_S_MODULE), SW_HIDE); - ShowWindow(GetDlgItem(m_hwnd, IDC_E_MODULE), SW_HIDE); - ShowWindow(GetDlgItem(m_hwnd, IDC_S_SETTING), SW_HIDE); - ShowWindow(GetDlgItem(m_hwnd, IDC_E_SETTING), SW_HIDE); - - // contact info - ShowWindow(GetDlgItem(m_hwnd, IDC_S_CNFTYPE), SW_HIDE); - ShowWindow(GetDlgItem(m_hwnd, IDC_C_CNFTYPE), SW_HIDE); - - // others - ShowWindow(GetDlgItem(m_hwnd, IDC_C_OTHER), SW_HIDE); - } - - void DisplayCurInfo(const ColumnItem *pCol) - { - ClearScreen(); - SetupScreen(pCol->setting_type); - - editTitle.SetText(pCol->title); - cmbVarType.SelectData(pCol->setting_type); - - switch (pCol->setting_type) { - case QST_SETTING: - cmbDataType.SelectData(pCol->datatype); - editModule.SetTextA(pCol->module); - editSetting.SetTextA(pCol->setting); - break; - - case QST_SCRIPT: - SetDlgItemTextW(m_hwnd, IDC_E_SCRIPT, pCol->script); - break; - - case QST_CONTACTINFO: - cmbCnfType.SelectData(pCol->cnftype); - break; - - case QST_OTHER: - cmbOther.SelectData(pCol->other); - break; - } - } - - void FillTableLine(int item, ColumnItem *pColumn) - { - m_list.SetItemText(item, 1, pColumn->title); - - switch (pColumn->setting_type) { - case QST_SETTING: - m_list.SetItemText(item, 2, _A2T(pColumn->module)); - m_list.SetItemText(item, 3, _A2T(pColumn->setting)); - break; - - case QST_SCRIPT: - m_list.SetItemText(item, 2, TranslateT("Script")); - break; - - case QST_SERVICE: - m_list.SetItemText(item, 2, TranslateT("Service")); - m_list.SetItemText(item, 3, _A2T(pColumn->svc.service)); - break; - - case QST_CONTACTINFO: - m_list.SetItemText(item, 2, TranslateT("Contact info")); - m_list.SetItemText(item, 3, cnf2str(pColumn->cnftype)); - break; - - case QST_OTHER: - m_list.SetItemText(item, 2, TranslateT("Other")); - if (pColumn->other == QSTO_METACONTACT) - m_list.SetItemText(item, 3, TranslateT("Metacontact")); - break; - } - } - - void InitScreen() - { - // setting - cmbDataType.SetCurSel(0); - editModule.SetText(L""); - editSetting.SetText(L""); - - // contact info - cmbCnfType.SetCurSel(0); - - // others - cmbOther.SetCurSel(0); - } - - void ResizeControl(int id, int width) - { - HWND hwnd = GetDlgItem(m_hwnd, id); - RECT rc; - ::GetWindowRect(hwnd, &rc); - ::SetWindowPos(hwnd, 0, 0, 0, width, rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER | SWP_SHOWWINDOW); - } - - void SetupScreen(int type) - { - if (!IsWindowVisible(GetDlgItem(m_hwnd, IDC_E_TITLE))) - return; - - // setting - int cmd = (type == QST_SETTING) ? SW_SHOW : SW_HIDE; - ShowWindow(GetDlgItem(m_hwnd, IDC_S_DATATYPE), cmd); - ShowWindow(GetDlgItem(m_hwnd, IDC_C_DATATYPE), cmd); - ShowWindow(GetDlgItem(m_hwnd, IDC_S_MODULE), cmd); - editModule.Show(cmd == SW_SHOW); - ShowWindow(GetDlgItem(m_hwnd, IDC_S_SETTING), cmd); - editSetting.Show(cmd == SW_SHOW); - - // contact info - cmd = (type == QST_CONTACTINFO) ? SW_SHOW : SW_HIDE; - ShowWindow(GetDlgItem(m_hwnd, IDC_S_CNFTYPE), cmd); - ShowWindow(GetDlgItem(m_hwnd, IDC_C_CNFTYPE), cmd); - - // script - cmd = (type == QST_SCRIPT) ? SW_SHOW : SW_HIDE; - ShowWindow(GetDlgItem(m_hwnd, IDC_E_SCRIPT), cmd); - - // others - cmd = (type == QST_OTHER) ? SW_SHOW : SW_HIDE; - ShowWindow(GetDlgItem(m_hwnd, IDC_C_OTHER), cmd); - } - - void UpdateList() - { - m_list.DeleteAllItems(); - - int cnt = 0; - for (auto &it : m_columns) { - AddColumn(cnt, it); - FillTableLine(cnt, it); - m_list.SetCheckState(cnt, it->bEnabled); - cnt++; - } - - m_list.SetCurSel(0); - } - - CCtrlEdit editTitle, editModule, editSetting; - CCtrlCheck chkSortStatus, chkAutoClose, chkUseToolstyle, chkDrawGrid, chkSavePattern, chkClientIcons; - CCtrlCombo cmbVarType, cmbDataType, cmbOther, cmbCnfType; - CCtrlListView m_list; - CCtrlButton btnSave, btnResize; - CCtrlMButton btnNew, btnUp, btnDown, btnDelete, btnDefault, btnReload; - -public: - COptionsDlg() : - CDlgBase(g_plugin, IDD_OPTIONS), - m_columns(1), - m_list(this, IDC_LIST), - btnSave(this, IDC_SETITEM), - btnResize(this, IDC_B_RESIZE), - btnUp(this, IDC_UP, g_plugin.getIcon(IDI_UP), LPGEN("Up")), - btnNew(this, IDC_NEW, g_plugin.getIcon(IDI_NEW), LPGEN("New")), - btnDown(this, IDC_DN, g_plugin.getIcon(IDI_DOWN), LPGEN("Down")), - btnDelete(this, IDC_DELETE, g_plugin.getIcon(IDI_DELETE), LPGEN("Delete")), - btnReload(this, IDC_RELOAD, g_plugin.getIcon(IDI_RELOAD), LPGEN("Reload")), - btnDefault(this, IDC_DEFAULT, g_plugin.getIcon(IDI_DEFAULT), LPGEN("Default")), - editTitle(this, IDC_E_TITLE), - editModule(this, IDC_E_MODULE), - editSetting(this, IDC_E_SETTING), - cmbOther(this, IDC_C_OTHER), - cmbCnfType(this, IDC_C_CNFTYPE), - cmbVarType(this, IDC_C_VARTYPE), - cmbDataType(this, IDC_C_DATATYPE), - chkDrawGrid(this, IDC_CH_DRAWGRID), - chkAutoClose(this, IDC_CH_AUTOCLOSE), - chkSortStatus(this, IDC_CH_SORTSTATUS), - chkSavePattern(this, IDC_CH_SAVEPATTERN), - chkClientIcons(this, IDC_CH_CLIENTICONS), - chkUseToolstyle(this, IDC_CH_USETOOLSTYLE) - { - m_list.OnItemChanged = Callback(this, &COptionsDlg::onItemChanged_List); - - btnUp.OnClick = Callback(this, &COptionsDlg::onClick_Up); - btnNew.OnClick = Callback(this, &COptionsDlg::onClick_New); - btnDown.OnClick = Callback(this, &COptionsDlg::onClick_Down); - btnSave.OnClick = Callback(this, &COptionsDlg::onClick_Save); - btnDelete.OnClick = Callback(this, &COptionsDlg::onClick_Delete); - btnReload.OnClick = Callback(this, &COptionsDlg::onClick_Reload); - btnResize.OnClick = Callback(this, &COptionsDlg::onClick_Resize); - btnDefault.OnClick = Callback(this, &COptionsDlg::onClick_Default); - - cmbVarType.OnSelChanged = Callback(this, &COptionsDlg::onSelChanged_Var); - } - - bool OnInitDialog() override - { - editTitle.SetSilent(); editModule.SetSilent(); editSetting.SetSilent(); - cmbOther.SetSilent(); cmbCnfType.SetSilent(); cmbVarType.SetSilent(); cmbDataType.SetSilent(); - - m_list.SetExtendedListViewStyle(m_list.GetExtendedListViewStyle() | LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES); - m_list.AddColumn(0, L"#", 20); - m_list.AddColumn(1, TranslateT("Title"), g_plugin.getWord("col1", 95)); - m_list.AddColumn(2, TranslateT("Module/Info type"), g_plugin.getWord("col2", 105)); - m_list.AddColumn(3, TranslateT("Setting"), g_plugin.getWord("col3", 85)); - - cmbVarType.AddString(TranslateT("Database setting"), QST_SETTING); - cmbVarType.AddString(TranslateT("Script"), QST_SCRIPT); - cmbVarType.AddString(TranslateT("Contact info"), QST_CONTACTINFO); - cmbVarType.AddString(TranslateT("Other"), QST_OTHER); - cmbVarType.SetCurSel(0); - - cmbDataType.AddString(TranslateT("Byte"), QSTS_BYTE); - cmbDataType.AddString(TranslateT("Word"), QSTS_WORD); - cmbDataType.AddString(TranslateT("Dword"), QSTS_DWORD); - cmbDataType.AddString(TranslateT("Signed"), QSTS_SIGNED); - cmbDataType.AddString(TranslateT("Hexadecimal"), QSTS_HEXNUM); - cmbDataType.AddString(TranslateT("String"), QSTS_STRING); - cmbDataType.AddString(TranslateT("Timestamp"), QSTS_TIMESTAMP); - cmbDataType.SetCurSel(0); - - cmbOther.AddString(TranslateT("Last seen"), QSTO_LASTSEEN); - cmbOther.AddString(TranslateT("Last event"), QSTO_LASTEVENT); - cmbOther.AddString(TranslateT("Metacontact"), QSTO_METACONTACT); - cmbOther.AddString(TranslateT("Event count"), QSTO_EVENTCOUNT); - cmbOther.AddString(TranslateT("Display name"), QSTO_DISPLAYNAME); - cmbOther.AddString(TranslateT("Account name"), QSTO_ACCOUNT); - cmbOther.SetCurSel(0); - - for (int i = CNF_FIRSTNAME; i < CNF_MAX; i++) - if (auto *pwszText = cnf2str(i)) - cmbCnfType.AddString(pwszText, i); - cmbCnfType.SetCurSel(0); - - chkDrawGrid.SetState((g_plugin.m_flags & QSO_DRAWGRID) != 0); - chkAutoClose.SetState((g_plugin.m_flags & QSO_AUTOCLOSE) != 0); - chkSortStatus.SetState((g_plugin.m_flags & QSO_SORTBYSTATUS) != 0); - chkClientIcons.SetState((g_plugin.m_flags & QSO_CLIENTICONS) != 0); - chkSavePattern.SetState((g_plugin.m_flags & QSO_SAVEPATTERN) != 0); - chkUseToolstyle.SetState((g_plugin.m_flags & QSO_TOOLSTYLE) != 0); - - // make local copy of column descriptions - for (auto &it : g_plugin.m_columns) - m_columns.insert(new ColumnItem(*it)); - - UpdateList(); - onClick_Resize(0); - if (m_columns.getCount()) - DisplayCurInfo(&m_columns[0]); - return true; - } - - bool OnApply() override - { - // checkboxes - g_plugin.m_flags &= ~QSO_MAINOPTIONS; - if (chkDrawGrid.IsChecked()) g_plugin.m_flags |= QSO_DRAWGRID; - if (chkAutoClose.IsChecked()) g_plugin.m_flags |= QSO_AUTOCLOSE; - if (chkSortStatus.IsChecked()) g_plugin.m_flags |= QSO_SORTBYSTATUS; - if (chkClientIcons.IsChecked()) g_plugin.m_flags |= QSO_CLIENTICONS; - if (chkSavePattern.IsChecked()) g_plugin.m_flags |= QSO_SAVEPATTERN; - if (chkUseToolstyle.IsChecked()) g_plugin.m_flags |= QSO_TOOLSTYLE; - - int tmpbool = CloseSrWindow(false); - - g_plugin.m_columns.destroy(); - int nCount = m_list.GetItemCount(); - for (int i = 0; i < nCount; i++) { - auto *pCol = (ColumnItem *)m_list.GetItemData(i); - pCol->bEnabled = m_list.GetCheckState(i) != 0; - g_plugin.m_columns.insert(new ColumnItem(*pCol)); - } - - g_plugin.SaveOptions(); - - if (tmpbool) - OpenSrWindow(0); - return true; - } - - void OnDestroy() override - { - m_columns.destroy(); - - g_plugin.setWord("col1", m_list.GetColumnWidth(1)); - g_plugin.setWord("col2", m_list.GetColumnWidth(2)); - g_plugin.setWord("col3", m_list.GetColumnWidth(3)); - } - - void onClick_New(CCtrlButton *) - { - int idx = m_list.GetSelectionMark()+1; - auto *pNew = new ColumnItem(TranslateT("New column")); - m_columns.insert(pNew); - - AddColumn(idx, pNew); - m_list.EnsureVisible(idx, FALSE); - m_list.SetCurSel(idx); - InitScreen(); - CheckDirection(idx); - btnDelete.Enable(); - NotifyChange(); - } - - void onClick_Delete(CCtrlButton *) - { - int idx = m_list.GetSelectionMark(); - auto *pCol = (ColumnItem *)m_list.GetItemData(idx); - - m_list.DeleteItem(idx); - m_columns.remove(pCol); - - int nCount = m_list.GetItemCount(); - if (nCount == 0) { - m_list.Disable(); - InitScreen(); - } - else { - if (nCount == idx) - idx--; - m_list.SetCurSel(idx); - } - CheckDirection(idx); - NotifyChange(); - } - - void onClick_Up(CCtrlButton *) - { - int idx = m_list.GetSelectionMark(); - if (idx > 0) { - CheckDirection(m_list.MoveItem(idx, -1)); - NotifyChange(); - } - } - - void onClick_Down(CCtrlButton *) - { - int idx = m_list.GetSelectionMark(); - if (idx < m_list.GetItemCount() - 1) { - CheckDirection(m_list.MoveItem(idx, 1)); - NotifyChange(); - } - } - - void onClick_Reload(CCtrlButton *) - { - g_plugin.LoadColumns(m_columns); - UpdateList(); - } - - void onClick_Default(CCtrlButton *) - { - LoadDefaultColumns(m_columns); - UpdateList(); - NotifyChange(); - } - - void onClick_Save(CCtrlButton *) - { - if (m_list.GetItemCount() == 0) { - AddColumn(0, new ColumnItem(TranslateT("New column"))); - m_list.SetCurSel(0); - btnDelete.Enable(); - } - - int idx = m_list.GetSelectionMark(); - auto *pCol = (ColumnItem *)m_list.GetItemData(idx); - pCol->dwFlags = 0; - if (m_list.GetCheckState(idx)) - pCol->bEnabled = pCol->bFilter = true; - pCol->setting_type = cmbVarType.GetItemData(cmbVarType.GetCurSel()); - replaceStrW(pCol->title, editTitle.GetText()); - - switch (pCol->setting_type) { - case QST_SETTING: - pCol->datatype = cmbDataType.GetItemData(cmbDataType.GetCurSel()); - pCol->module = mir_u2a(ptrW(editModule.GetText())); - pCol->setting = mir_u2a(ptrW(editSetting.GetText())); - break; - - case QST_CONTACTINFO: - pCol->cnftype = cmbCnfType.GetItemData(cmbCnfType.GetCurSel()); - break; - - case QST_OTHER: - pCol->other = cmbCnfType.GetItemData(cmbCnfType.GetCurSel()); - break; - } - - FillTableLine(idx, pCol); - NotifyChange(); - } - - void onClick_Resize(CCtrlButton *) - { - wchar_t *pcw; - int dx, rside; - - RECT rc, rc1; - GetClientRect(m_hwnd, &rc); - GetWindowRect(btnResize.GetHwnd(), &rc1); - - POINT pt = { rc1.left, 0 }; - ScreenToClient(m_hwnd, &pt); - if (pt.x < (rc.right - 50)) { - rside = SW_HIDE; - dx = rc.right - (rc1.right - rc1.left) - 4; - pcw = L"<"; - } - else { - rside = SW_SHOW; - - GetWindowRect(GetDlgItem(m_hwnd, IDC_S_COLSETTING), &rc); - pt.x = rc.left; - pt.y = 0; - ScreenToClient(m_hwnd, &pt); - dx = pt.x - (rc1.right - rc1.left) - 4; - pcw = L">"; - } - - btnResize.SetText(pcw); - - // move separator button - SetWindowPos(btnResize.GetHwnd(), 0, dx + 2, 2, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW); - - // resize left side controls - ResizeControl(IDC_LIST, dx); - ResizeControl(IDC_CH_GROUP, dx); - - ResizeControl(IDC_CH_USETOOLSTYLE, dx - 8); - ResizeControl(IDC_CH_DRAWGRID, dx - 8); - ResizeControl(IDC_CH_SAVEPATTERN, dx - 8); - ResizeControl(IDC_CH_AUTOCLOSE, dx - 8); - ResizeControl(IDC_CH_SORTSTATUS, dx - 8); - ResizeControl(IDC_CH_CLIENTICONS, dx - 8); - - // show/hide setting block (ugly, i know!) - ShowWindow(GetDlgItem(m_hwnd, IDC_S_COLSETTING), rside); - ShowWindow(GetDlgItem(m_hwnd, IDC_S_LINE), rside); - ShowWindow(GetDlgItem(m_hwnd, IDC_S_TITLE), rside); - ShowWindow(GetDlgItem(m_hwnd, IDC_E_TITLE), rside); - ShowWindow(GetDlgItem(m_hwnd, IDC_E_SCRIPT), rside); - ShowWindow(GetDlgItem(m_hwnd, IDC_E_MODULE), rside); - ShowWindow(GetDlgItem(m_hwnd, IDC_E_SETTING), rside); - ShowWindow(GetDlgItem(m_hwnd, IDC_S_VARTYPE), rside); - ShowWindow(GetDlgItem(m_hwnd, IDC_C_VARTYPE), rside); - ShowWindow(GetDlgItem(m_hwnd, IDC_C_OTHER), rside); - ShowWindow(GetDlgItem(m_hwnd, IDC_C_CNFTYPE), rside); - ShowWindow(GetDlgItem(m_hwnd, IDC_C_DATATYPE), rside); - ShowWindow(GetDlgItem(m_hwnd, IDC_SETITEM), rside); - - ClearScreen(); - if (rside == SW_SHOW) - SetupScreen(cmbVarType.GetItemData(cmbVarType.GetCurSel())); - } - - void onItemChanged_List(CCtrlListView::TEventInfo *ev) - { - auto *nmlv = ev->nmlv; - // we got new focus - if ((nmlv->uOldState & LVNI_FOCUSED) < (nmlv->uNewState & LVNI_FOCUSED)) { - CheckDirection(nmlv->iItem); - InitScreen(); - DisplayCurInfo((ColumnItem*)nmlv->lParam); - } - } - - void onSelChanged_Var(CCtrlCombo *pCombo) - { - SetupScreen(pCombo->GetItemData(pCombo->GetCurSel())); - } -}; - -int OnOptInit(WPARAM wParam, LPARAM) -{ - OPTIONSDIALOGPAGE odp = {}; - odp.flags = ODPF_BOLDGROUPS; - odp.szGroup.a = LPGEN("Contacts"); - odp.szTitle.a = LPGEN("Quick Search"); - odp.position = 900003000; - odp.pDialog = new COptionsDlg(); - g_plugin.addOptions(wParam, &odp); - return 0; -} +/* +Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "stdafx.h" + +class COptionsDlg : public CDlgBase +{ + OBJLIST m_columns; + + void AddColumn(int idx, ColumnItem *pCol) + { + LVITEM lvi = {}; + lvi.mask = LVIF_PARAM; + lvi.iItem = idx; + lvi.lParam = LPARAM(pCol); + m_list.InsertItem(&lvi); + } + + void CheckDirection(int iItem) + { + btnUp.Enable(iItem > 0); + btnDown.Enable(iItem < m_list.GetItemCount()-1); + } + + void ClearScreen() + { + // setting + ShowWindow(GetDlgItem(m_hwnd, IDC_S_DATATYPE), SW_HIDE); + ShowWindow(GetDlgItem(m_hwnd, IDC_C_DATATYPE), SW_HIDE); + ShowWindow(GetDlgItem(m_hwnd, IDC_S_MODULE), SW_HIDE); + ShowWindow(GetDlgItem(m_hwnd, IDC_E_MODULE), SW_HIDE); + ShowWindow(GetDlgItem(m_hwnd, IDC_S_SETTING), SW_HIDE); + ShowWindow(GetDlgItem(m_hwnd, IDC_E_SETTING), SW_HIDE); + + // contact info + ShowWindow(GetDlgItem(m_hwnd, IDC_S_CNFTYPE), SW_HIDE); + ShowWindow(GetDlgItem(m_hwnd, IDC_C_CNFTYPE), SW_HIDE); + + // others + ShowWindow(GetDlgItem(m_hwnd, IDC_C_OTHER), SW_HIDE); + } + + void DisplayCurInfo(const ColumnItem *pCol) + { + ClearScreen(); + SetupScreen(pCol->setting_type); + + editTitle.SetText(pCol->title); + cmbVarType.SelectData(pCol->setting_type); + + switch (pCol->setting_type) { + case QST_SETTING: + cmbDataType.SelectData(pCol->datatype); + editModule.SetTextA(pCol->module); + editSetting.SetTextA(pCol->setting); + break; + + case QST_SCRIPT: + SetDlgItemTextW(m_hwnd, IDC_E_SCRIPT, pCol->script); + break; + + case QST_CONTACTINFO: + cmbCnfType.SelectData(pCol->cnftype); + break; + + case QST_OTHER: + cmbOther.SelectData(pCol->other); + break; + } + } + + void FillTableLine(int item, ColumnItem *pColumn) + { + m_list.SetItemText(item, 1, pColumn->title); + + switch (pColumn->setting_type) { + case QST_SETTING: + m_list.SetItemText(item, 2, _A2T(pColumn->module)); + m_list.SetItemText(item, 3, _A2T(pColumn->setting)); + break; + + case QST_SCRIPT: + m_list.SetItemText(item, 2, TranslateT("Script")); + break; + + case QST_SERVICE: + m_list.SetItemText(item, 2, TranslateT("Service")); + m_list.SetItemText(item, 3, _A2T(pColumn->svc.service)); + break; + + case QST_CONTACTINFO: + m_list.SetItemText(item, 2, TranslateT("Contact info")); + m_list.SetItemText(item, 3, cnf2str(pColumn->cnftype)); + break; + + case QST_OTHER: + m_list.SetItemText(item, 2, TranslateT("Other")); + if (pColumn->other == QSTO_METACONTACT) + m_list.SetItemText(item, 3, TranslateT("Metacontact")); + break; + } + } + + void InitScreen() + { + // setting + cmbDataType.SetCurSel(0); + editModule.SetText(L""); + editSetting.SetText(L""); + + // contact info + cmbCnfType.SetCurSel(0); + + // others + cmbOther.SetCurSel(0); + } + + void ResizeControl(int id, int width) + { + HWND hwnd = GetDlgItem(m_hwnd, id); + RECT rc; + ::GetWindowRect(hwnd, &rc); + ::SetWindowPos(hwnd, 0, 0, 0, width, rc.bottom - rc.top, SWP_NOMOVE | SWP_NOZORDER | SWP_SHOWWINDOW); + } + + void SetupScreen(int type) + { + if (!IsWindowVisible(GetDlgItem(m_hwnd, IDC_E_TITLE))) + return; + + // setting + int cmd = (type == QST_SETTING) ? SW_SHOW : SW_HIDE; + ShowWindow(GetDlgItem(m_hwnd, IDC_S_DATATYPE), cmd); + ShowWindow(GetDlgItem(m_hwnd, IDC_C_DATATYPE), cmd); + ShowWindow(GetDlgItem(m_hwnd, IDC_S_MODULE), cmd); + editModule.Show(cmd == SW_SHOW); + ShowWindow(GetDlgItem(m_hwnd, IDC_S_SETTING), cmd); + editSetting.Show(cmd == SW_SHOW); + + // contact info + cmd = (type == QST_CONTACTINFO) ? SW_SHOW : SW_HIDE; + ShowWindow(GetDlgItem(m_hwnd, IDC_S_CNFTYPE), cmd); + ShowWindow(GetDlgItem(m_hwnd, IDC_C_CNFTYPE), cmd); + + // script + cmd = (type == QST_SCRIPT) ? SW_SHOW : SW_HIDE; + ShowWindow(GetDlgItem(m_hwnd, IDC_E_SCRIPT), cmd); + + // others + cmd = (type == QST_OTHER) ? SW_SHOW : SW_HIDE; + ShowWindow(GetDlgItem(m_hwnd, IDC_C_OTHER), cmd); + } + + void UpdateList() + { + m_list.DeleteAllItems(); + + int cnt = 0; + for (auto &it : m_columns) { + AddColumn(cnt, it); + FillTableLine(cnt, it); + m_list.SetCheckState(cnt, it->bEnabled); + cnt++; + } + + m_list.SetCurSel(0); + } + + CCtrlEdit editTitle, editModule, editSetting; + CCtrlCheck chkSortStatus, chkAutoClose, chkUseToolstyle, chkDrawGrid, chkSavePattern, chkClientIcons; + CCtrlCombo cmbVarType, cmbDataType, cmbOther, cmbCnfType; + CCtrlListView m_list; + CCtrlButton btnSave, btnResize; + CCtrlMButton btnNew, btnUp, btnDown, btnDelete, btnDefault, btnReload; + +public: + COptionsDlg() : + CDlgBase(g_plugin, IDD_OPTIONS), + m_columns(1), + m_list(this, IDC_LIST), + btnSave(this, IDC_SETITEM), + btnResize(this, IDC_B_RESIZE), + btnUp(this, IDC_UP, g_plugin.getIcon(IDI_UP), LPGEN("Up")), + btnNew(this, IDC_NEW, g_plugin.getIcon(IDI_NEW), LPGEN("New")), + btnDown(this, IDC_DN, g_plugin.getIcon(IDI_DOWN), LPGEN("Down")), + btnDelete(this, IDC_DELETE, g_plugin.getIcon(IDI_DELETE), LPGEN("Delete")), + btnReload(this, IDC_RELOAD, g_plugin.getIcon(IDI_RELOAD), LPGEN("Reload")), + btnDefault(this, IDC_DEFAULT, g_plugin.getIcon(IDI_DEFAULT), LPGEN("Default")), + editTitle(this, IDC_E_TITLE), + editModule(this, IDC_E_MODULE), + editSetting(this, IDC_E_SETTING), + cmbOther(this, IDC_C_OTHER), + cmbCnfType(this, IDC_C_CNFTYPE), + cmbVarType(this, IDC_C_VARTYPE), + cmbDataType(this, IDC_C_DATATYPE), + chkDrawGrid(this, IDC_CH_DRAWGRID), + chkAutoClose(this, IDC_CH_AUTOCLOSE), + chkSortStatus(this, IDC_CH_SORTSTATUS), + chkSavePattern(this, IDC_CH_SAVEPATTERN), + chkClientIcons(this, IDC_CH_CLIENTICONS), + chkUseToolstyle(this, IDC_CH_USETOOLSTYLE) + { + m_list.OnItemChanged = Callback(this, &COptionsDlg::onItemChanged_List); + + btnUp.OnClick = Callback(this, &COptionsDlg::onClick_Up); + btnNew.OnClick = Callback(this, &COptionsDlg::onClick_New); + btnDown.OnClick = Callback(this, &COptionsDlg::onClick_Down); + btnSave.OnClick = Callback(this, &COptionsDlg::onClick_Save); + btnDelete.OnClick = Callback(this, &COptionsDlg::onClick_Delete); + btnReload.OnClick = Callback(this, &COptionsDlg::onClick_Reload); + btnResize.OnClick = Callback(this, &COptionsDlg::onClick_Resize); + btnDefault.OnClick = Callback(this, &COptionsDlg::onClick_Default); + + cmbVarType.OnSelChanged = Callback(this, &COptionsDlg::onSelChanged_Var); + } + + bool OnInitDialog() override + { + editTitle.SetSilent(); editModule.SetSilent(); editSetting.SetSilent(); + cmbOther.SetSilent(); cmbCnfType.SetSilent(); cmbVarType.SetSilent(); cmbDataType.SetSilent(); + + m_list.SetExtendedListViewStyle(m_list.GetExtendedListViewStyle() | LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES); + m_list.AddColumn(0, L"#", 20); + m_list.AddColumn(1, TranslateT("Title"), g_plugin.getWord("col1", 95)); + m_list.AddColumn(2, TranslateT("Module/Info type"), g_plugin.getWord("col2", 105)); + m_list.AddColumn(3, TranslateT("Setting"), g_plugin.getWord("col3", 85)); + + cmbVarType.AddString(TranslateT("Database setting"), QST_SETTING); + cmbVarType.AddString(TranslateT("Script"), QST_SCRIPT); + cmbVarType.AddString(TranslateT("Contact info"), QST_CONTACTINFO); + cmbVarType.AddString(TranslateT("Other"), QST_OTHER); + cmbVarType.SetCurSel(0); + + cmbDataType.AddString(TranslateT("Byte"), QSTS_BYTE); + cmbDataType.AddString(TranslateT("Word"), QSTS_WORD); + cmbDataType.AddString(TranslateT("Dword"), QSTS_DWORD); + cmbDataType.AddString(TranslateT("Signed"), QSTS_SIGNED); + cmbDataType.AddString(TranslateT("Hexadecimal"), QSTS_HEXNUM); + cmbDataType.AddString(TranslateT("String"), QSTS_STRING); + cmbDataType.AddString(TranslateT("Timestamp"), QSTS_TIMESTAMP); + cmbDataType.SetCurSel(0); + + cmbOther.AddString(TranslateT("Last seen"), QSTO_LASTSEEN); + cmbOther.AddString(TranslateT("Last event"), QSTO_LASTEVENT); + cmbOther.AddString(TranslateT("Metacontact"), QSTO_METACONTACT); + cmbOther.AddString(TranslateT("Event count"), QSTO_EVENTCOUNT); + cmbOther.AddString(TranslateT("Display name"), QSTO_DISPLAYNAME); + cmbOther.AddString(TranslateT("Account name"), QSTO_ACCOUNT); + cmbOther.SetCurSel(0); + + for (int i = CNF_FIRSTNAME; i < CNF_MAX; i++) + if (auto *pwszText = cnf2str(i)) + cmbCnfType.AddString(pwszText, i); + cmbCnfType.SetCurSel(0); + + chkDrawGrid.SetState((g_plugin.m_flags & QSO_DRAWGRID) != 0); + chkAutoClose.SetState((g_plugin.m_flags & QSO_AUTOCLOSE) != 0); + chkSortStatus.SetState((g_plugin.m_flags & QSO_SORTBYSTATUS) != 0); + chkClientIcons.SetState((g_plugin.m_flags & QSO_CLIENTICONS) != 0); + chkSavePattern.SetState((g_plugin.m_flags & QSO_SAVEPATTERN) != 0); + chkUseToolstyle.SetState((g_plugin.m_flags & QSO_TOOLSTYLE) != 0); + + // make local copy of column descriptions + for (auto &it : g_plugin.m_columns) + m_columns.insert(new ColumnItem(*it)); + + UpdateList(); + onClick_Resize(0); + if (m_columns.getCount()) + DisplayCurInfo(&m_columns[0]); + return true; + } + + bool OnApply() override + { + // checkboxes + g_plugin.m_flags &= ~QSO_MAINOPTIONS; + if (chkDrawGrid.IsChecked()) g_plugin.m_flags |= QSO_DRAWGRID; + if (chkAutoClose.IsChecked()) g_plugin.m_flags |= QSO_AUTOCLOSE; + if (chkSortStatus.IsChecked()) g_plugin.m_flags |= QSO_SORTBYSTATUS; + if (chkClientIcons.IsChecked()) g_plugin.m_flags |= QSO_CLIENTICONS; + if (chkSavePattern.IsChecked()) g_plugin.m_flags |= QSO_SAVEPATTERN; + if (chkUseToolstyle.IsChecked()) g_plugin.m_flags |= QSO_TOOLSTYLE; + + int tmpbool = CloseSrWindow(false); + + g_plugin.m_columns.destroy(); + int nCount = m_list.GetItemCount(); + for (int i = 0; i < nCount; i++) { + auto *pCol = (ColumnItem *)m_list.GetItemData(i); + pCol->bEnabled = m_list.GetCheckState(i) != 0; + g_plugin.m_columns.insert(new ColumnItem(*pCol)); + } + + g_plugin.SaveOptions(); + + if (tmpbool) + OpenSrWindow(0); + return true; + } + + void OnDestroy() override + { + m_columns.destroy(); + + g_plugin.setWord("col1", m_list.GetColumnWidth(1)); + g_plugin.setWord("col2", m_list.GetColumnWidth(2)); + g_plugin.setWord("col3", m_list.GetColumnWidth(3)); + } + + void onClick_New(CCtrlButton *) + { + int idx = m_list.GetSelectionMark()+1; + auto *pNew = new ColumnItem(TranslateT("New column")); + m_columns.insert(pNew); + + AddColumn(idx, pNew); + m_list.EnsureVisible(idx, FALSE); + m_list.SetCurSel(idx); + InitScreen(); + CheckDirection(idx); + btnDelete.Enable(); + NotifyChange(); + } + + void onClick_Delete(CCtrlButton *) + { + int idx = m_list.GetSelectionMark(); + auto *pCol = (ColumnItem *)m_list.GetItemData(idx); + + m_list.DeleteItem(idx); + m_columns.remove(pCol); + + int nCount = m_list.GetItemCount(); + if (nCount == 0) { + m_list.Disable(); + InitScreen(); + } + else { + if (nCount == idx) + idx--; + m_list.SetCurSel(idx); + } + CheckDirection(idx); + NotifyChange(); + } + + void onClick_Up(CCtrlButton *) + { + int idx = m_list.GetSelectionMark(); + if (idx > 0) { + CheckDirection(m_list.MoveItem(idx, -1)); + NotifyChange(); + } + } + + void onClick_Down(CCtrlButton *) + { + int idx = m_list.GetSelectionMark(); + if (idx < m_list.GetItemCount() - 1) { + CheckDirection(m_list.MoveItem(idx, 1)); + NotifyChange(); + } + } + + void onClick_Reload(CCtrlButton *) + { + g_plugin.LoadColumns(m_columns); + UpdateList(); + } + + void onClick_Default(CCtrlButton *) + { + LoadDefaultColumns(m_columns); + UpdateList(); + NotifyChange(); + } + + void onClick_Save(CCtrlButton *) + { + if (m_list.GetItemCount() == 0) { + AddColumn(0, new ColumnItem(TranslateT("New column"))); + m_list.SetCurSel(0); + btnDelete.Enable(); + } + + int idx = m_list.GetSelectionMark(); + auto *pCol = (ColumnItem *)m_list.GetItemData(idx); + pCol->dwFlags = 0; + if (m_list.GetCheckState(idx)) + pCol->bEnabled = pCol->bFilter = true; + pCol->setting_type = cmbVarType.GetItemData(cmbVarType.GetCurSel()); + replaceStrW(pCol->title, editTitle.GetText()); + + switch (pCol->setting_type) { + case QST_SETTING: + pCol->datatype = cmbDataType.GetItemData(cmbDataType.GetCurSel()); + pCol->module = mir_u2a(ptrW(editModule.GetText())); + pCol->setting = mir_u2a(ptrW(editSetting.GetText())); + break; + + case QST_CONTACTINFO: + pCol->cnftype = cmbCnfType.GetItemData(cmbCnfType.GetCurSel()); + break; + + case QST_OTHER: + pCol->other = cmbCnfType.GetItemData(cmbCnfType.GetCurSel()); + break; + } + + FillTableLine(idx, pCol); + NotifyChange(); + } + + void onClick_Resize(CCtrlButton *) + { + wchar_t *pcw; + int dx, rside; + + RECT rc, rc1; + GetClientRect(m_hwnd, &rc); + GetWindowRect(btnResize.GetHwnd(), &rc1); + + POINT pt = { rc1.left, 0 }; + ScreenToClient(m_hwnd, &pt); + if (pt.x < (rc.right - 50)) { + rside = SW_HIDE; + dx = rc.right - (rc1.right - rc1.left) - 4; + pcw = L"<"; + } + else { + rside = SW_SHOW; + + GetWindowRect(GetDlgItem(m_hwnd, IDC_S_COLSETTING), &rc); + pt.x = rc.left; + pt.y = 0; + ScreenToClient(m_hwnd, &pt); + dx = pt.x - (rc1.right - rc1.left) - 4; + pcw = L">"; + } + + btnResize.SetText(pcw); + + // move separator button + SetWindowPos(btnResize.GetHwnd(), 0, dx + 2, 2, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW); + + // resize left side controls + ResizeControl(IDC_LIST, dx); + ResizeControl(IDC_CH_GROUP, dx); + + ResizeControl(IDC_CH_USETOOLSTYLE, dx - 8); + ResizeControl(IDC_CH_DRAWGRID, dx - 8); + ResizeControl(IDC_CH_SAVEPATTERN, dx - 8); + ResizeControl(IDC_CH_AUTOCLOSE, dx - 8); + ResizeControl(IDC_CH_SORTSTATUS, dx - 8); + ResizeControl(IDC_CH_CLIENTICONS, dx - 8); + + // show/hide setting block (ugly, i know!) + ShowWindow(GetDlgItem(m_hwnd, IDC_S_COLSETTING), rside); + ShowWindow(GetDlgItem(m_hwnd, IDC_S_LINE), rside); + ShowWindow(GetDlgItem(m_hwnd, IDC_S_TITLE), rside); + ShowWindow(GetDlgItem(m_hwnd, IDC_E_TITLE), rside); + ShowWindow(GetDlgItem(m_hwnd, IDC_E_SCRIPT), rside); + ShowWindow(GetDlgItem(m_hwnd, IDC_E_MODULE), rside); + ShowWindow(GetDlgItem(m_hwnd, IDC_E_SETTING), rside); + ShowWindow(GetDlgItem(m_hwnd, IDC_S_VARTYPE), rside); + ShowWindow(GetDlgItem(m_hwnd, IDC_C_VARTYPE), rside); + ShowWindow(GetDlgItem(m_hwnd, IDC_C_OTHER), rside); + ShowWindow(GetDlgItem(m_hwnd, IDC_C_CNFTYPE), rside); + ShowWindow(GetDlgItem(m_hwnd, IDC_C_DATATYPE), rside); + ShowWindow(GetDlgItem(m_hwnd, IDC_SETITEM), rside); + + ClearScreen(); + if (rside == SW_SHOW) + SetupScreen(cmbVarType.GetItemData(cmbVarType.GetCurSel())); + } + + void onItemChanged_List(CCtrlListView::TEventInfo *ev) + { + auto *nmlv = ev->nmlv; + // we got new focus + if ((nmlv->uOldState & LVNI_FOCUSED) < (nmlv->uNewState & LVNI_FOCUSED)) { + CheckDirection(nmlv->iItem); + InitScreen(); + DisplayCurInfo((ColumnItem*)nmlv->lParam); + } + } + + void onSelChanged_Var(CCtrlCombo *pCombo) + { + SetupScreen(pCombo->GetItemData(pCombo->GetCurSel())); + } +}; + +int OnOptInit(WPARAM wParam, LPARAM) +{ + OPTIONSDIALOGPAGE odp = {}; + odp.flags = ODPF_BOLDGROUPS; + odp.szGroup.a = LPGEN("Contacts"); + odp.szTitle.a = LPGEN("Quick Search"); + odp.position = 900003000; + odp.pDialog = new COptionsDlg(); + g_plugin.addOptions(wParam, &odp); + return 0; +} diff --git a/plugins/QuickSearch/src/stdafx.cxx b/plugins/QuickSearch/src/stdafx.cxx index 1ab0efee94..ebbde0ade1 100644 --- a/plugins/QuickSearch/src/stdafx.cxx +++ b/plugins/QuickSearch/src/stdafx.cxx @@ -1,18 +1,18 @@ -/* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - +/* +Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + #include "stdafx.h" \ No newline at end of file diff --git a/plugins/QuickSearch/src/utils.cpp b/plugins/QuickSearch/src/utils.cpp index 9db7133c3b..2cf1cdbc9f 100644 --- a/plugins/QuickSearch/src/utils.cpp +++ b/plugins/QuickSearch/src/utils.cpp @@ -1,556 +1,556 @@ -/* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "stdafx.h" - -#define ACF_TYPE_NUMBER 0x00 // Parameter is number -#define ACF_TYPE_STRING 0x01 // Parameter is ANSI String -#define ACF_TYPE_UNICODE 0x02 // Parameter is Unicode string -#define ACF_TYPE_STRUCT 0x03 // Parameter is (result is in) structure -#define ACF_TYPE_PARAM 0x08 // Parameter is Call parameter -#define ACF_TYPE_CURRENT 0x09 // Parameter is ignored, used current user handle from current message window -#define ACF_TYPE_RESULT 0x0A // Parameter is previous action result -#define ACF_TYPE_MASK 0x0F // parameter/result type mask - -ColumnItem::ColumnItem(const wchar_t *pwszTitle, int _width, int _setting_type) : - title(mir_wstrdup(pwszTitle)), - width(_width), - setting_type(_setting_type) -{ - bEnabled = true; -} - -ColumnItem::ColumnItem(const ColumnItem &src) -{ - memcpy(this, &src, sizeof(ColumnItem)); - - title = mir_wstrdup(title); - - switch (setting_type) { - case QST_SETTING: - module = mir_strdup(module); - setting = mir_strdup(setting); - break; - - case QST_SCRIPT: - script = mir_wstrdup(script); - break; - - case QST_SERVICE: - svc.service = mir_strdup(svc.service); - switch (svc.wFlags) { - case ACF_TYPE_NUMBER: - case ACF_TYPE_STRING: - case ACF_TYPE_UNICODE: - svc.wParam = (WPARAM)mir_wstrdup((wchar_t *)svc.wParam); - break; - case ACF_TYPE_STRUCT: - svc.wParam = (WPARAM)mir_strdup((char *)svc.wParam); - break; - } - - switch (svc.lFlags) { - case ACF_TYPE_NUMBER: - case ACF_TYPE_STRING: - case ACF_TYPE_UNICODE: - svc.lParam = (WPARAM)mir_wstrdup((wchar_t *)svc.lParam); - break; - case ACF_TYPE_STRUCT: - svc.lParam = (WPARAM)mir_strdup((char *)svc.lParam); - break; - } - break; - } -} - -ColumnItem::~ColumnItem() -{ - mir_free(title); - - switch (setting_type) { - case QST_SETTING: - mir_free(module); - mir_free(setting); - break; - - case QST_SCRIPT: - mir_free(script); - break; - - case QST_SERVICE: - mir_free(svc.service); - switch (svc.wFlags) { - case ACF_TYPE_NUMBER: - case ACF_TYPE_STRING: - case ACF_TYPE_UNICODE: - mir_free((wchar_t *)svc.wParam); - break; - case ACF_TYPE_STRUCT: - mir_free((char *)svc.wParam); - break; - } - - switch (svc.lFlags) { - case ACF_TYPE_NUMBER: - case ACF_TYPE_STRING: - case ACF_TYPE_UNICODE: - mir_free((wchar_t *)svc.lParam); - break; - case ACF_TYPE_STRUCT: - mir_free((char *)svc.lParam); - break; - } - break; - } -} - -void ColumnItem::SetSpecialColumns() -{ - if (setting_type == QST_SETTING) { - if (datatype == QSTS_STRING && !mir_strcmp(module, "CList") && !mir_strcmp(setting, "Group")) - isGroup = true; - - else if (datatype == QSTS_STRING && !mir_strcmp(module, "Tab_SRMsg") && !mir_strcmp(setting, "containerW")) - isContainer = true; - - else if (datatype == QSTS_BYTE && !mir_strcmpi(setting, "XStatusId")) - isXstatus = true; - - else if (datatype == QSTS_STRING && !mir_strcmp(setting, "MirVer") && g_bFingerInstalled) - isClient = true; - } - else if (setting_type == QST_CONTACTINFO && cnftype == CNF_GENDER) - isGender = true; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// column functions - -int ListViewToColumn(int col) -{ - for (auto &it : g_plugin.m_columns) { - if (!it->bEnabled) - continue; - - if (col-- <= 0) - return g_plugin.m_columns.indexOf(&it); - } - return -1; -} - -int ColumnToListView(int col) -{ - int res = -1; - for (auto &it : g_plugin.m_columns) { - if (it->bEnabled) - res++; - - if (col-- <= 0) - break; - } - return res; -} - -void LoadDefaultColumns(OBJLIST &dst) -{ - dst.destroy(); - - auto *pNew = new ColumnItem(TranslateT("Account"), 82, QST_OTHER); - pNew->other = QSTO_ACCOUNT; - dst.insert(pNew); - - dst.insert(new ContactIntoColumn(TranslateT("Gender"), 20, CNF_GENDER)); - - pNew = new ContactIntoColumn(TranslateT("UserID"), 80, CNF_UNIQUEID); - pNew->bFilter = true; - dst.insert(pNew); - - pNew = new ContactIntoColumn(TranslateT("Nickname"), 76, QST_OTHER); - pNew->bFilter = true; - pNew->other = QSTO_DISPLAYNAME; - - pNew = new ContactIntoColumn(TranslateT("First name"), 68, CNF_FIRSTNAME); - pNew->bFilter = true; - dst.insert(pNew); - - pNew = new ContactIntoColumn(TranslateT("Last name"), 66, CNF_LASTNAME); - pNew->bFilter = true; - dst.insert(pNew); - - pNew = new ColumnItem(TranslateT("Group"), 80, QST_SETTING); - pNew->datatype = QSTS_STRING; - pNew->module = mir_strdup("CList"); - pNew->setting = mir_strdup("Group"); - pNew->bFilter = true; - dst.insert(pNew); - - pNew = new ColumnItem(TranslateT("Container"), 80, QST_SETTING); - pNew->datatype = QSTS_STRING; - pNew->module = mir_strdup("Tab_SRMsg"); - pNew->setting = mir_strdup("containerW"); - pNew->bFilter = true; - dst.insert(pNew); - - pNew = new ContactIntoColumn(TranslateT("Email"), 116, CNF_EMAIL); - pNew->bFilter = true; - dst.insert(pNew); - - pNew = new ColumnItem(TranslateT("Client ID"), 60, QST_SETTING); - pNew->datatype = QSTS_STRING; - pNew->setting = mir_strdup("MirVer"); - pNew->bFilter = true; - dst.insert(pNew); - - pNew = new ColumnItem(TranslateT("Last seen"), 116, QST_OTHER); - pNew->other = QSTO_LASTSEEN; - pNew->dwFlags = 0; - dst.insert(pNew); - - pNew = new ColumnItem(TranslateT("Last event"), 100, QST_OTHER); - pNew->other = QSTO_LASTEVENT; - pNew->dwFlags = 0; - dst.insert(pNew); - - pNew = new ColumnItem(TranslateT("Online since"), 100, QST_SETTING); - pNew->datatype = QSTS_TIMESTAMP; - pNew->setting = mir_strdup("LogonTS"); - pNew->bFilter = true; - dst.insert(pNew); - - pNew = new ColumnItem(TranslateT("Metacontact"), 50, QST_OTHER); - pNew->other = QSTO_METACONTACT; - pNew->dwFlags = 0; - dst.insert(pNew); - - pNew = new ColumnItem(TranslateT("Event count"), 50, QST_OTHER); - pNew->other = QSTO_EVENTCOUNT; - pNew->dwFlags = 0; - dst.insert(pNew); - - pNew = new ColumnItem(TranslateT("Contact add time"), 80, QST_SETTING); - pNew->datatype = QSTS_TIMESTAMP; - pNew->module = mir_strdup("UserInfo"); - pNew->setting = mir_strdup("ContactAddTime"); - dst.insert(pNew); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// window options - -void CMPlugin::LoadOptWnd() -{ - m_rect.bottom = getDword(so_mbottom); - m_rect.right = getDword(so_mright); - m_rect.left = getDword(so_mleft); - m_rect.top = getDword(so_mtop); - - m_flags = getDword(so_flags, QSO_SORTBYSTATUS + QSO_DRAWGRID + QSO_CLIENTICONS + QSO_COLORIZE + QSO_SORTASC); - m_sortOrder = getDword(so_columnsort); -} - -void CMPlugin::SaveOptWnd() -{ - setDword(so_mbottom, m_rect.bottom); - setDword(so_mright, m_rect.right); - setDword(so_mleft, m_rect.left); - setDword(so_mtop, m_rect.top); - - setDword(so_flags, m_flags); - setDword(so_columnsort, m_sortOrder); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// load options - -int CMPlugin::LoadColumns(OBJLIST &dst) -{ - m_flags = getDword(so_flags, QSO_SORTBYSTATUS + QSO_DRAWGRID + QSO_CLIENTICONS + QSO_COLORIZE + QSO_SORTASC); - int numCols = getWord(so_numcolumns); - - for (int i = 0; i < numCols; i++) { - auto *pNew = new ColumnItem(nullptr); - LoadColumn(i, *pNew); - dst.insert(pNew); - } - - return numCols; -} - -void CMPlugin::LoadColumn(int n, ColumnItem &col) -{ - char buf[127]; - int offset = mir_snprintf(buf, "%s%d_", so_item, n); - - strcpy(buf + offset, so_title); col.title = getWStringA(buf); - strcpy(buf + offset, so_setting_type); col.setting_type = getWord(buf); - strcpy(buf + offset, so_flags); col.dwFlags = getWord(buf); - strcpy(buf + offset, so_width); col.width = getWord(buf); - - switch (col.setting_type) { - case QST_SETTING: - strcpy(buf + offset, so_datatype); col.datatype = getWord(buf); - strcpy(buf + offset, so_module); col.module = getStringA(buf); - strcpy(buf + offset, so_setting); col.setting = getStringA(buf); - break; - - case QST_SCRIPT: - strcpy(buf + offset, so_script); col.script = getWStringA(buf); - break; - - case QST_CONTACTINFO: - strcpy(buf + offset, so_cnftype); col.cnftype = getWord(buf); - break; - - case QST_SERVICE: - offset = mir_snprintf(buf, "%s%d/service/", so_item, n); - strcpy(buf + offset, so_service); col.svc.service = getStringA(buf); - strcpy(buf + offset, so_restype); col.svc.flags = getDword(buf); - if (!mir_strcmp(col.svc.service, "Proto/GetContactBaseAccount")) { - col.setting_type = QST_OTHER; - col.other = QSTO_ACCOUNT; - break; - } - - strcpy(buf + offset, so_wparam); - LoadParamValue(buf, col.svc.wFlags, col.svc.wParam); - - strcpy(buf + offset, so_lparam); - LoadParamValue(buf, col.svc.lFlags, col.svc.lParam); - break; - - case QST_OTHER: - strcpy(buf + offset, so_other); col.other = getWord(buf); - break; - } -} - -void CMPlugin::LoadParamValue(char *buf, uint32_t &dwFlags, LPARAM &dwWalue) -{ - char *pEnd = buf + strlen(buf); - strcpy(pEnd, "flags"); dwFlags = getDword(buf); - - strcpy(pEnd, "value"); - switch (dwFlags) { - case ACF_TYPE_NUMBER: - case ACF_TYPE_STRING: - case ACF_TYPE_UNICODE: - dwWalue = LPARAM(getWStringA(buf)); - break; - - case ACF_TYPE_STRUCT: - dwWalue = LPARAM(getStringA(buf)); - break; - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// save options - -static int ListSettings(const char *szSetting, void *param) -{ - if (!memcmp(szSetting, so_item, 4)) { - auto *pList = (LIST*)param; - pList->insert(mir_strdup(szSetting)); - } - return 0; -} - -void CMPlugin::SaveOptions() -{ - // remove old settings - LIST settings(30); - db_enum_settings(0, ListSettings, MODULENAME, &settings); - - for (auto &it : settings) { - delSetting(it); - mir_free(it); - } - - // write new settings - setDword(so_flags, m_flags); - setWord(so_numcolumns, m_columns.getCount()); - - int i = 0; - for (auto &it : m_columns) - SaveColumn(i++, *it); -} - -void CMPlugin::SaveColumn(int n, const ColumnItem &col) -{ - char buf[127]; - int offset = mir_snprintf(buf, "%s%d_", so_item, n); - - strcpy(buf + offset, so_title); setWString(buf, col.title); - strcpy(buf + offset, so_setting_type); setWord(buf, col.setting_type); - strcpy(buf + offset, so_flags); setWord(buf, col.dwFlags); - strcpy(buf + offset, so_width); setWord(buf, col.width); - - switch (col.setting_type) { - case QST_SETTING: - strcpy(buf + offset, so_datatype); setWord(buf, col.datatype); - strcpy(buf + offset, so_module); setString(buf, col.module); - strcpy(buf + offset, so_setting); setString(buf, col.setting); - break; - - case QST_SCRIPT: - strcpy(buf + offset, so_script); setWString(buf, col.script); - break; - - case QST_CONTACTINFO: - strcpy(buf + offset, so_cnftype); setWord(buf, col.cnftype); - break; - - case QST_SERVICE: - offset = mir_snprintf(buf, "%s%d/service/", so_item, n); - strcpy(buf + offset, so_service); setString(buf, col.svc.service); - strcpy(buf + offset, so_restype); setDword(buf, col.svc.flags); - - strcpy(buf + offset, so_wparam); - SaveParamValue(buf, col.svc.wFlags, col.svc.wParam); - - strcpy(buf + offset, so_lparam); - SaveParamValue(buf, col.svc.lFlags, col.svc.lParam); - break; - - case QST_OTHER: - strcpy(buf + offset, so_other); setWord(buf, col.other); - break; - } -} - -void CMPlugin::SaveParamValue(char *buf, uint32_t flags, LPARAM value) -{ - char *pEnd = buf + strlen(buf); - strcpy(pEnd, "flags"); setDword(buf, flags); - - strcpy(pEnd, "value"); - switch (flags) { - case ACF_TYPE_NUMBER: - case ACF_TYPE_STRING: - case ACF_TYPE_UNICODE: - setWString(buf, (wchar_t *)value); - break; - - case ACF_TYPE_STRUCT: - setString(buf, (char *)value); - break; - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -const wchar_t* cnf2str(int cnf) -{ - switch (cnf) { - case CNF_FIRSTNAME: return TranslateT("First name"); - case CNF_LASTNAME: return TranslateT("Last name"); - case CNF_NICK: return TranslateT("Nick"); - case CNF_CUSTOMNICK: return TranslateT("Custom nick"); - case CNF_EMAIL: return TranslateT("Email"); - case CNF_CITY: return TranslateT("City"); - case CNF_STATE: return TranslateT("State"); - case CNF_COUNTRY: return TranslateT("Country"); - case CNF_PHONE: return TranslateT("Phone"); - case CNF_HOMEPAGE: return TranslateT("Homepage"); - case CNF_ABOUT: return TranslateT("About"); - case CNF_GENDER: return TranslateT("Gender"); - case CNF_AGE: return TranslateT("Age"); - case CNF_FIRSTLAST: return TranslateT("First name/Last name"); - case CNF_UNIQUEID: return TranslateT("Unique ID"); - case CNF_FAX: return TranslateT("Fax"); - case CNF_CELLULAR: return TranslateT("Cellular"); - case CNF_TIMEZONE: return TranslateT("Time zone"); - case CNF_MYNOTES: return TranslateT("My notes"); - case CNF_BIRTHDAY: return TranslateT("Birth day"); - case CNF_BIRTHMONTH: return TranslateT("Birth month"); - case CNF_BIRTHYEAR: return TranslateT("Birth year"); - case CNF_STREET: return TranslateT("Street"); - case CNF_ZIP: return TranslateT("ZIP code"); - case CNF_LANGUAGE1: return TranslateT("Language #1"); - case CNF_LANGUAGE2: return TranslateT("Language #2"); - case CNF_LANGUAGE3: return TranslateT("Language #3"); - case CNF_CONAME: return TranslateT("Company name"); - case CNF_CODEPT: return TranslateT("Company department"); - case CNF_COPOSITION: return TranslateT("Company position"); - case CNF_COSTREET: return TranslateT("Company street"); - case CNF_COCITY: return TranslateT("Company city"); - case CNF_COSTATE: return TranslateT("Company state"); - case CNF_COZIP: return TranslateT("Company ZIP"); - case CNF_COCOUNTRY: return TranslateT("Company country"); - case CNF_COHOMEPAGE: return TranslateT("Company homepage"); - case CNF_DISPLAYUID: return TranslateT("Display ID"); - } - return nullptr; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// formatters - -wchar_t* BuildLastSeenTime(uint32_t ts) -{ - int year = ts / (60 * 24 * 31 * 356); - if (year == 0) - return nullptr; - - year += 1980; ts = ts % (60 * 24 * 31 * 356); - - int month = ts / (60 * 24 * 31); ts = ts % (60 * 24 * 31); - int day = ts / (60 * 24); ts = ts % (60 * 24); - int hours = ts / 60; - int mins = ts % 60; - - return CMStringW(FORMAT, L"%02d.%02d.%04d - %02d:%02d", year, month, day, hours, mins).Detach(); -} - -uint32_t BuildLastSeenTimeInt(MCONTACT hContact, const char *szModule) -{ - int year = db_get_w(hContact, szModule, "Year"); - if (year == 0) - return 0; - - int day = db_get_w(hContact, szModule, "Day"); - int month = db_get_w(hContact, szModule, "Month"); - int hours = db_get_w(hContact, szModule, "Hours"); - int minutes = db_get_w(hContact, szModule, "Minutes"); - - return ((((year - 1980) * 356 + month) * 31 + day) * 24 + hours) * 60 + minutes; -} - -wchar_t* TimeToStrW(uint32_t timestamp) -{ - wchar_t buf[63]; - TimeZone_ToStringW(timestamp, L"d - t", buf, _countof(buf)); - return mir_wstrdup(buf); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void SnapToScreen(RECT &rc) -{ - int left = GetSystemMetrics(SM_XVIRTUALSCREEN); - int top = GetSystemMetrics(SM_YVIRTUALSCREEN); - int right = GetSystemMetrics(SM_CXVIRTUALSCREEN) + left; - int bottom = GetSystemMetrics(SM_CYVIRTUALSCREEN) + top; - if (rc.right > right) - rc.right = right; - if (rc.bottom > bottom) - rc.bottom = bottom; - if (rc.left < left) - rc.left = left; - if (rc.top < top) - rc.top = top; -} +/* +Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "stdafx.h" + +#define ACF_TYPE_NUMBER 0x00 // Parameter is number +#define ACF_TYPE_STRING 0x01 // Parameter is ANSI String +#define ACF_TYPE_UNICODE 0x02 // Parameter is Unicode string +#define ACF_TYPE_STRUCT 0x03 // Parameter is (result is in) structure +#define ACF_TYPE_PARAM 0x08 // Parameter is Call parameter +#define ACF_TYPE_CURRENT 0x09 // Parameter is ignored, used current user handle from current message window +#define ACF_TYPE_RESULT 0x0A // Parameter is previous action result +#define ACF_TYPE_MASK 0x0F // parameter/result type mask + +ColumnItem::ColumnItem(const wchar_t *pwszTitle, int _width, int _setting_type) : + title(mir_wstrdup(pwszTitle)), + width(_width), + setting_type(_setting_type) +{ + bEnabled = true; +} + +ColumnItem::ColumnItem(const ColumnItem &src) +{ + memcpy(this, &src, sizeof(ColumnItem)); + + title = mir_wstrdup(title); + + switch (setting_type) { + case QST_SETTING: + module = mir_strdup(module); + setting = mir_strdup(setting); + break; + + case QST_SCRIPT: + script = mir_wstrdup(script); + break; + + case QST_SERVICE: + svc.service = mir_strdup(svc.service); + switch (svc.wFlags) { + case ACF_TYPE_NUMBER: + case ACF_TYPE_STRING: + case ACF_TYPE_UNICODE: + svc.wParam = (WPARAM)mir_wstrdup((wchar_t *)svc.wParam); + break; + case ACF_TYPE_STRUCT: + svc.wParam = (WPARAM)mir_strdup((char *)svc.wParam); + break; + } + + switch (svc.lFlags) { + case ACF_TYPE_NUMBER: + case ACF_TYPE_STRING: + case ACF_TYPE_UNICODE: + svc.lParam = (WPARAM)mir_wstrdup((wchar_t *)svc.lParam); + break; + case ACF_TYPE_STRUCT: + svc.lParam = (WPARAM)mir_strdup((char *)svc.lParam); + break; + } + break; + } +} + +ColumnItem::~ColumnItem() +{ + mir_free(title); + + switch (setting_type) { + case QST_SETTING: + mir_free(module); + mir_free(setting); + break; + + case QST_SCRIPT: + mir_free(script); + break; + + case QST_SERVICE: + mir_free(svc.service); + switch (svc.wFlags) { + case ACF_TYPE_NUMBER: + case ACF_TYPE_STRING: + case ACF_TYPE_UNICODE: + mir_free((wchar_t *)svc.wParam); + break; + case ACF_TYPE_STRUCT: + mir_free((char *)svc.wParam); + break; + } + + switch (svc.lFlags) { + case ACF_TYPE_NUMBER: + case ACF_TYPE_STRING: + case ACF_TYPE_UNICODE: + mir_free((wchar_t *)svc.lParam); + break; + case ACF_TYPE_STRUCT: + mir_free((char *)svc.lParam); + break; + } + break; + } +} + +void ColumnItem::SetSpecialColumns() +{ + if (setting_type == QST_SETTING) { + if (datatype == QSTS_STRING && !mir_strcmp(module, "CList") && !mir_strcmp(setting, "Group")) + isGroup = true; + + else if (datatype == QSTS_STRING && !mir_strcmp(module, "Tab_SRMsg") && !mir_strcmp(setting, "containerW")) + isContainer = true; + + else if (datatype == QSTS_BYTE && !mir_strcmpi(setting, "XStatusId")) + isXstatus = true; + + else if (datatype == QSTS_STRING && !mir_strcmp(setting, "MirVer") && g_bFingerInstalled) + isClient = true; + } + else if (setting_type == QST_CONTACTINFO && cnftype == CNF_GENDER) + isGender = true; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// column functions + +int ListViewToColumn(int col) +{ + for (auto &it : g_plugin.m_columns) { + if (!it->bEnabled) + continue; + + if (col-- <= 0) + return g_plugin.m_columns.indexOf(&it); + } + return -1; +} + +int ColumnToListView(int col) +{ + int res = -1; + for (auto &it : g_plugin.m_columns) { + if (it->bEnabled) + res++; + + if (col-- <= 0) + break; + } + return res; +} + +void LoadDefaultColumns(OBJLIST &dst) +{ + dst.destroy(); + + auto *pNew = new ColumnItem(TranslateT("Account"), 82, QST_OTHER); + pNew->other = QSTO_ACCOUNT; + dst.insert(pNew); + + dst.insert(new ContactIntoColumn(TranslateT("Gender"), 20, CNF_GENDER)); + + pNew = new ContactIntoColumn(TranslateT("UserID"), 80, CNF_UNIQUEID); + pNew->bFilter = true; + dst.insert(pNew); + + pNew = new ContactIntoColumn(TranslateT("Nickname"), 76, QST_OTHER); + pNew->bFilter = true; + pNew->other = QSTO_DISPLAYNAME; + + pNew = new ContactIntoColumn(TranslateT("First name"), 68, CNF_FIRSTNAME); + pNew->bFilter = true; + dst.insert(pNew); + + pNew = new ContactIntoColumn(TranslateT("Last name"), 66, CNF_LASTNAME); + pNew->bFilter = true; + dst.insert(pNew); + + pNew = new ColumnItem(TranslateT("Group"), 80, QST_SETTING); + pNew->datatype = QSTS_STRING; + pNew->module = mir_strdup("CList"); + pNew->setting = mir_strdup("Group"); + pNew->bFilter = true; + dst.insert(pNew); + + pNew = new ColumnItem(TranslateT("Container"), 80, QST_SETTING); + pNew->datatype = QSTS_STRING; + pNew->module = mir_strdup("Tab_SRMsg"); + pNew->setting = mir_strdup("containerW"); + pNew->bFilter = true; + dst.insert(pNew); + + pNew = new ContactIntoColumn(TranslateT("Email"), 116, CNF_EMAIL); + pNew->bFilter = true; + dst.insert(pNew); + + pNew = new ColumnItem(TranslateT("Client ID"), 60, QST_SETTING); + pNew->datatype = QSTS_STRING; + pNew->setting = mir_strdup("MirVer"); + pNew->bFilter = true; + dst.insert(pNew); + + pNew = new ColumnItem(TranslateT("Last seen"), 116, QST_OTHER); + pNew->other = QSTO_LASTSEEN; + pNew->dwFlags = 0; + dst.insert(pNew); + + pNew = new ColumnItem(TranslateT("Last event"), 100, QST_OTHER); + pNew->other = QSTO_LASTEVENT; + pNew->dwFlags = 0; + dst.insert(pNew); + + pNew = new ColumnItem(TranslateT("Online since"), 100, QST_SETTING); + pNew->datatype = QSTS_TIMESTAMP; + pNew->setting = mir_strdup("LogonTS"); + pNew->bFilter = true; + dst.insert(pNew); + + pNew = new ColumnItem(TranslateT("Metacontact"), 50, QST_OTHER); + pNew->other = QSTO_METACONTACT; + pNew->dwFlags = 0; + dst.insert(pNew); + + pNew = new ColumnItem(TranslateT("Event count"), 50, QST_OTHER); + pNew->other = QSTO_EVENTCOUNT; + pNew->dwFlags = 0; + dst.insert(pNew); + + pNew = new ColumnItem(TranslateT("Contact add time"), 80, QST_SETTING); + pNew->datatype = QSTS_TIMESTAMP; + pNew->module = mir_strdup("UserInfo"); + pNew->setting = mir_strdup("ContactAddTime"); + dst.insert(pNew); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// window options + +void CMPlugin::LoadOptWnd() +{ + m_rect.bottom = getDword(so_mbottom); + m_rect.right = getDword(so_mright); + m_rect.left = getDword(so_mleft); + m_rect.top = getDword(so_mtop); + + m_flags = getDword(so_flags, QSO_SORTBYSTATUS + QSO_DRAWGRID + QSO_CLIENTICONS + QSO_COLORIZE + QSO_SORTASC); + m_sortOrder = getDword(so_columnsort); +} + +void CMPlugin::SaveOptWnd() +{ + setDword(so_mbottom, m_rect.bottom); + setDword(so_mright, m_rect.right); + setDword(so_mleft, m_rect.left); + setDword(so_mtop, m_rect.top); + + setDword(so_flags, m_flags); + setDword(so_columnsort, m_sortOrder); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// load options + +int CMPlugin::LoadColumns(OBJLIST &dst) +{ + m_flags = getDword(so_flags, QSO_SORTBYSTATUS + QSO_DRAWGRID + QSO_CLIENTICONS + QSO_COLORIZE + QSO_SORTASC); + int numCols = getWord(so_numcolumns); + + for (int i = 0; i < numCols; i++) { + auto *pNew = new ColumnItem(nullptr); + LoadColumn(i, *pNew); + dst.insert(pNew); + } + + return numCols; +} + +void CMPlugin::LoadColumn(int n, ColumnItem &col) +{ + char buf[127]; + int offset = mir_snprintf(buf, "%s%d_", so_item, n); + + strcpy(buf + offset, so_title); col.title = getWStringA(buf); + strcpy(buf + offset, so_setting_type); col.setting_type = getWord(buf); + strcpy(buf + offset, so_flags); col.dwFlags = getWord(buf); + strcpy(buf + offset, so_width); col.width = getWord(buf); + + switch (col.setting_type) { + case QST_SETTING: + strcpy(buf + offset, so_datatype); col.datatype = getWord(buf); + strcpy(buf + offset, so_module); col.module = getStringA(buf); + strcpy(buf + offset, so_setting); col.setting = getStringA(buf); + break; + + case QST_SCRIPT: + strcpy(buf + offset, so_script); col.script = getWStringA(buf); + break; + + case QST_CONTACTINFO: + strcpy(buf + offset, so_cnftype); col.cnftype = getWord(buf); + break; + + case QST_SERVICE: + offset = mir_snprintf(buf, "%s%d/service/", so_item, n); + strcpy(buf + offset, so_service); col.svc.service = getStringA(buf); + strcpy(buf + offset, so_restype); col.svc.flags = getDword(buf); + if (!mir_strcmp(col.svc.service, "Proto/GetContactBaseAccount")) { + col.setting_type = QST_OTHER; + col.other = QSTO_ACCOUNT; + break; + } + + strcpy(buf + offset, so_wparam); + LoadParamValue(buf, col.svc.wFlags, col.svc.wParam); + + strcpy(buf + offset, so_lparam); + LoadParamValue(buf, col.svc.lFlags, col.svc.lParam); + break; + + case QST_OTHER: + strcpy(buf + offset, so_other); col.other = getWord(buf); + break; + } +} + +void CMPlugin::LoadParamValue(char *buf, uint32_t &dwFlags, LPARAM &dwWalue) +{ + char *pEnd = buf + strlen(buf); + strcpy(pEnd, "flags"); dwFlags = getDword(buf); + + strcpy(pEnd, "value"); + switch (dwFlags) { + case ACF_TYPE_NUMBER: + case ACF_TYPE_STRING: + case ACF_TYPE_UNICODE: + dwWalue = LPARAM(getWStringA(buf)); + break; + + case ACF_TYPE_STRUCT: + dwWalue = LPARAM(getStringA(buf)); + break; + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// save options + +static int ListSettings(const char *szSetting, void *param) +{ + if (!memcmp(szSetting, so_item, 4)) { + auto *pList = (LIST*)param; + pList->insert(mir_strdup(szSetting)); + } + return 0; +} + +void CMPlugin::SaveOptions() +{ + // remove old settings + LIST settings(30); + db_enum_settings(0, ListSettings, MODULENAME, &settings); + + for (auto &it : settings) { + delSetting(it); + mir_free(it); + } + + // write new settings + setDword(so_flags, m_flags); + setWord(so_numcolumns, m_columns.getCount()); + + int i = 0; + for (auto &it : m_columns) + SaveColumn(i++, *it); +} + +void CMPlugin::SaveColumn(int n, const ColumnItem &col) +{ + char buf[127]; + int offset = mir_snprintf(buf, "%s%d_", so_item, n); + + strcpy(buf + offset, so_title); setWString(buf, col.title); + strcpy(buf + offset, so_setting_type); setWord(buf, col.setting_type); + strcpy(buf + offset, so_flags); setWord(buf, col.dwFlags); + strcpy(buf + offset, so_width); setWord(buf, col.width); + + switch (col.setting_type) { + case QST_SETTING: + strcpy(buf + offset, so_datatype); setWord(buf, col.datatype); + strcpy(buf + offset, so_module); setString(buf, col.module); + strcpy(buf + offset, so_setting); setString(buf, col.setting); + break; + + case QST_SCRIPT: + strcpy(buf + offset, so_script); setWString(buf, col.script); + break; + + case QST_CONTACTINFO: + strcpy(buf + offset, so_cnftype); setWord(buf, col.cnftype); + break; + + case QST_SERVICE: + offset = mir_snprintf(buf, "%s%d/service/", so_item, n); + strcpy(buf + offset, so_service); setString(buf, col.svc.service); + strcpy(buf + offset, so_restype); setDword(buf, col.svc.flags); + + strcpy(buf + offset, so_wparam); + SaveParamValue(buf, col.svc.wFlags, col.svc.wParam); + + strcpy(buf + offset, so_lparam); + SaveParamValue(buf, col.svc.lFlags, col.svc.lParam); + break; + + case QST_OTHER: + strcpy(buf + offset, so_other); setWord(buf, col.other); + break; + } +} + +void CMPlugin::SaveParamValue(char *buf, uint32_t flags, LPARAM value) +{ + char *pEnd = buf + strlen(buf); + strcpy(pEnd, "flags"); setDword(buf, flags); + + strcpy(pEnd, "value"); + switch (flags) { + case ACF_TYPE_NUMBER: + case ACF_TYPE_STRING: + case ACF_TYPE_UNICODE: + setWString(buf, (wchar_t *)value); + break; + + case ACF_TYPE_STRUCT: + setString(buf, (char *)value); + break; + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +const wchar_t* cnf2str(int cnf) +{ + switch (cnf) { + case CNF_FIRSTNAME: return TranslateT("First name"); + case CNF_LASTNAME: return TranslateT("Last name"); + case CNF_NICK: return TranslateT("Nick"); + case CNF_CUSTOMNICK: return TranslateT("Custom nick"); + case CNF_EMAIL: return TranslateT("Email"); + case CNF_CITY: return TranslateT("City"); + case CNF_STATE: return TranslateT("State"); + case CNF_COUNTRY: return TranslateT("Country"); + case CNF_PHONE: return TranslateT("Phone"); + case CNF_HOMEPAGE: return TranslateT("Homepage"); + case CNF_ABOUT: return TranslateT("About"); + case CNF_GENDER: return TranslateT("Gender"); + case CNF_AGE: return TranslateT("Age"); + case CNF_FIRSTLAST: return TranslateT("First name/Last name"); + case CNF_UNIQUEID: return TranslateT("Unique ID"); + case CNF_FAX: return TranslateT("Fax"); + case CNF_CELLULAR: return TranslateT("Cellular"); + case CNF_TIMEZONE: return TranslateT("Time zone"); + case CNF_MYNOTES: return TranslateT("My notes"); + case CNF_BIRTHDAY: return TranslateT("Birth day"); + case CNF_BIRTHMONTH: return TranslateT("Birth month"); + case CNF_BIRTHYEAR: return TranslateT("Birth year"); + case CNF_STREET: return TranslateT("Street"); + case CNF_ZIP: return TranslateT("ZIP code"); + case CNF_LANGUAGE1: return TranslateT("Language #1"); + case CNF_LANGUAGE2: return TranslateT("Language #2"); + case CNF_LANGUAGE3: return TranslateT("Language #3"); + case CNF_CONAME: return TranslateT("Company name"); + case CNF_CODEPT: return TranslateT("Company department"); + case CNF_COPOSITION: return TranslateT("Company position"); + case CNF_COSTREET: return TranslateT("Company street"); + case CNF_COCITY: return TranslateT("Company city"); + case CNF_COSTATE: return TranslateT("Company state"); + case CNF_COZIP: return TranslateT("Company ZIP"); + case CNF_COCOUNTRY: return TranslateT("Company country"); + case CNF_COHOMEPAGE: return TranslateT("Company homepage"); + case CNF_DISPLAYUID: return TranslateT("Display ID"); + } + return nullptr; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// formatters + +wchar_t* BuildLastSeenTime(uint32_t ts) +{ + int year = ts / (60 * 24 * 31 * 356); + if (year == 0) + return nullptr; + + year += 1980; ts = ts % (60 * 24 * 31 * 356); + + int month = ts / (60 * 24 * 31); ts = ts % (60 * 24 * 31); + int day = ts / (60 * 24); ts = ts % (60 * 24); + int hours = ts / 60; + int mins = ts % 60; + + return CMStringW(FORMAT, L"%02d.%02d.%04d - %02d:%02d", year, month, day, hours, mins).Detach(); +} + +uint32_t BuildLastSeenTimeInt(MCONTACT hContact, const char *szModule) +{ + int year = db_get_w(hContact, szModule, "Year"); + if (year == 0) + return 0; + + int day = db_get_w(hContact, szModule, "Day"); + int month = db_get_w(hContact, szModule, "Month"); + int hours = db_get_w(hContact, szModule, "Hours"); + int minutes = db_get_w(hContact, szModule, "Minutes"); + + return ((((year - 1980) * 356 + month) * 31 + day) * 24 + hours) * 60 + minutes; +} + +wchar_t* TimeToStrW(uint32_t timestamp) +{ + wchar_t buf[63]; + TimeZone_ToStringW(timestamp, L"d - t", buf, _countof(buf)); + return mir_wstrdup(buf); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void SnapToScreen(RECT &rc) +{ + int left = GetSystemMetrics(SM_XVIRTUALSCREEN); + int top = GetSystemMetrics(SM_YVIRTUALSCREEN); + int right = GetSystemMetrics(SM_CXVIRTUALSCREEN) + left; + int bottom = GetSystemMetrics(SM_CYVIRTUALSCREEN) + top; + if (rc.right > right) + rc.right = right; + if (rc.bottom > bottom) + rc.bottom = bottom; + if (rc.left < left) + rc.left = left; + if (rc.top < top) + rc.top = top; +} diff --git a/plugins/QuickSearch/src/version.h b/plugins/QuickSearch/src/version.h index c054045e77..d1f948c4c1 100644 --- a/plugins/QuickSearch/src/version.h +++ b/plugins/QuickSearch/src/version.h @@ -10,4 +10,4 @@ #define __DESCRIPTION "This plugin allows you to quick search for nickname, firstname, lastname, email, uin in your contact list." #define __AUTHOR "Bethoven, Awkward" #define __AUTHORWEB "https://miranda-ng.org/p/QuickSearch" -#define __COPYRIGHT "© 2004-05 Bethoven; 2006-13 Awkward; 2014-22 Miranda NG team" +#define __COPYRIGHT "© 2004-05 Bethoven; 2006-13 Awkward; 2014-23 Miranda NG team" diff --git a/plugins/QuickSearch/src/window.cpp b/plugins/QuickSearch/src/window.cpp index 891d39aa92..8624be7d98 100644 --- a/plugins/QuickSearch/src/window.cpp +++ b/plugins/QuickSearch/src/window.cpp @@ -1,876 +1,876 @@ -/* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org) - -This program is free software; you can redistribute it &/| -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY | FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "stdafx.h" - -#define IDM_STAYONTOP (WM_USER+1) - -static QSMainDlg *g_pDlg = 0; - -///////////////////////////////////////////////////////////////////////////////////////// -// edit control window procedure - -static LRESULT CALLBACK sttNewEditProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - auto *pDlg = (QSMainDlg *)GetWindowLongPtrW(hwnd, GWLP_USERDATA); - if (pDlg) - if (INT_PTR res = pDlg->NewEditProc(msg, wParam, lParam)) - return res; - - return mir_callNextSubclass(hwnd, sttNewEditProc, msg, wParam, lParam); -} - -INT_PTR QSMainDlg::NewEditProc(UINT msg, WPARAM wParam, LPARAM) -{ - switch (msg) { - case WM_CHAR: - if (wParam == 27) // Escape - Close(); - break; - - case WM_KEYUP: - if (wParam == VK_RETURN) { - if (m_grid.GetSelectedCount() == 1) - ShowContactMsgDlg(GetFocusedContact()); - return 0; - } - break; - - case WM_KEYDOWN: - int count = m_grid.GetItemCount(); - int current = m_grid.GetNextItem(-1, LVNI_FOCUSED); - int next = -1; - if (count > 0) { - switch (wParam) { - case VK_UP: - if (current > 0) - next = current - 1; - break; - - case VK_DOWN: - if (current < count - 1) - next = current + 1; - break; - - case VK_F5: - onClick_Refresh(0); - return 0; - - case VK_NEXT: - case VK_PRIOR: - int perpage = m_grid.GetCountPerPage(); - if (wParam == VK_NEXT) - next = min(current + perpage, count); - else - next = max(current - perpage, 0); - break; - } - } - - if (next >= 0) { - m_grid.SetItemState(-1, 0, LVIS_SELECTED); - m_grid.SetCurSel(next); - m_grid.EnsureVisible(next, FALSE); - } - } - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// list header window procedure - -static void MakeColumnMenu() -{ - HMENU hMenu = CreatePopupMenu(); - - for (auto &it : g_plugin.m_columns) { - int flag = MF_STRING + (it->bEnabled) ? MF_CHECKED : MF_UNCHECKED; - AppendMenuW(hMenu, flag, 100 + g_plugin.m_columns.indexOf(&it), TranslateW(it->title)); - } - - POINT pt; - GetCursorPos(&pt); - - int id = TrackPopupMenu(hMenu, TPM_RETURNCMD + TPM_NONOTIFY, pt.x, pt.y, 0, g_pDlg->GetHwnd(), 0); - if (id >= 100) - g_pDlg->ToggleColumn(id - 100); - - DestroyMenu(hMenu); -} - -void QSMainDlg::ToggleColumn(int col) -{ - auto &pCol = g_plugin.m_columns[col]; - - if (!pCol.bEnabled) { // show column - pCol.bEnabled = true; - - if (!pCol.bInit) { - for (auto &it : m_rows) - it->pValues[col].LoadOneItem(it->hContact, pCol, this); - pCol.bInit = true; - } - - // screen - int lvcol = ColumnToListView(col); - AddColumn(lvcol, &pCol); - - int nCount = m_grid.GetItemCount(); - for (int i = 0; i < nCount; i++) { - auto *pRow = GetRow(i); - - LV_ITEMW li; - li.iItem = i; - li.iSubItem = lvcol; - li.mask = LVIF_TEXT; - li.pszText = pRow->pValues[col].text; - if ((pCol.isClient && (g_plugin.m_flags & QSO_CLIENTICONS) && li.pszText) || pCol.isGender || pCol.isXstatus) - li.mask |= LVIF_IMAGE; - m_grid.SetItem(&li); - } - } - else { // hide column - int cnt = 0; - for (auto &it : g_plugin.m_columns) - if (it->bEnabled) - cnt++; - - // keep at least one visible column (1 + this) - if (cnt > 2) { - m_grid.DeleteColumn(col); - pCol.bEnabled = false; - } - } -} - -static LRESULT CALLBACK sttNewLVHProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_RBUTTONUP: - return 0; - - case WM_RBUTTONDOWN: - MakeColumnMenu(); - break; - } - - return mir_callNextSubclass(hwnd, sttNewLVHProc, msg, wParam, lParam); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// grid list window procedure - -static int OldHSubItem = 0, OldHItem = 0; - -static LRESULT CALLBACK sttNewLVProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - auto *pDlg = (QSMainDlg *)GetWindowLongPtrW(hwnd, GWLP_USERDATA); - if (pDlg) - if (INT_PTR res = pDlg->NewLVProc(msg, wParam, lParam)) - return res; - - return mir_callNextSubclass(hwnd, sttNewLVProc, msg, wParam, lParam); -} - -INT_PTR QSMainDlg::NewLVProc(UINT msg, WPARAM wParam, LPARAM lParam) -{ - LV_HITTESTINFO pinfo; - - switch (msg) { - case WM_CHAR: - switch (wParam) { // ESC - case 27: - Close(); - break; - - case 1: // Cltr+A - m_grid.SetItemState(-1, LVIS_SELECTED, LVIS_SELECTED); - break; - - case 3: // Ctrl-C - CopyMultiLines(); - break; - - case 8: // backspace - edtFilter.SendMsg(msg, wParam, lParam); - break; - } - - if (wParam >= 32 && wParam <= 127) // letters - edtFilter.SendMsg(msg, wParam, lParam); - break; - - case WM_MOUSEMOVE: - pinfo.pt.x = LOWORD(lParam); - pinfo.pt.y = HIWORD(lParam); - pinfo.flags = 0; - if (m_grid.SubItemHitTest(&pinfo) == -1) - break; - - if ((pinfo.flags & LVHT_ONITEM) && (pinfo.iItem != OldHItem || pinfo.iSubItem != OldHSubItem)) { - OldHSubItem = pinfo.iSubItem; - OldHItem = pinfo.iItem; - - if (g_bTipperInstalled) { - if (TTShowed) { - TTShowed = false; - Tipper_Hide(); - } - m_hover.Stop(); - - if (OldHSubItem == 0) - m_hover.Start(450); - } - - TOOLINFOW ti = {}; - ti.cbSize = sizeof(ti); - ti.uFlags = TTF_SUBCLASS + TTF_IDISHWND; - ti.hwnd = m_hwnd; - ti.uId = LPARAM(m_hwnd); - - int num = ListViewToColumn(OldHSubItem); - auto &pCol = g_plugin.m_columns[num]; - if (pCol.isXstatus || pCol.isGender) { - auto *pRow = GetRow(OldHItem); - if (pCol.isGender) { - switch (pRow->pValues[num].data) { - case 'M': ti.lpszText = TranslateT("Male"); break; - case 'F': ti.lpszText = TranslateT("Female"); break; - default: ti.lpszText = TranslateT("Unknown"); break; - } - } - else { - wchar_t buf[256]; - mir_wstrncpy(buf, pRow->pValues[num].text, _countof(buf)); - int iStatus = _wtoi(buf); - - CUSTOM_STATUS ics = {}; - ics.cbSize = sizeof(ics); - ics.status = &iStatus; - ics.flags = CSSF_DEFAULT_NAME | CSSF_MASK_NAME | CSSF_UNICODE; - ics.pwszName = buf; - CallProtoService(pRow->szProto, PS_GETCUSTOMSTATUSEX, 0, (LPARAM)&ics); - ti.lpszText = TranslateW(buf); - } - } - - SendMessageW(HintWnd, TTM_SETTOOLINFOW, 0, LPARAM(&ti)); - } - break; - - case WM_KEYUP: - switch (wParam) { - case VK_RETURN: - if (m_grid.GetSelectedCount() == 1) - ShowContactMsgDlg(GetFocusedContact()); - break; - - case VK_INSERT: - CallService(MS_FINDADD_FINDADD, 0, 0); - break; - - case VK_DELETE: - lParam = m_grid.GetSelectedCount(); - if (lParam > 1) - DeleteByList(); - else if (lParam == 1) - DeleteOneContact(GetFocusedContact()); - break; - - case VK_F5: - onClick_Refresh(0); - break; - } - break; - - case WM_NOTIFY: - if (((LPNMHDR)lParam)->code == HDN_ITEMSTATEICONCLICK) { - NMHEADER *pdhr = (NMHEADER *)lParam; - if ((pdhr->pitem->mask & HDI_FORMAT) && (pdhr->pitem->fmt & HDF_CHECKBOX)) { - int i = ListViewToColumn(pdhr->iItem); - auto &pCol = g_plugin.m_columns[i]; - - if (pdhr->pitem->fmt & HDF_CHECKED) { - pCol.bFilter = false; - pdhr->pitem->fmt &= ~HDF_CHECKED; - } - else { - pCol.bFilter = true; - pdhr->pitem->fmt |= HDF_CHECKED; - } - - SendMessage(pdhr->hdr.hwndFrom, HDM_SETITEM, pdhr->iItem, LPARAM(pdhr->pitem)); - FillGrid(); - return TRUE; - } - } - } - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// QSMainDlg class implementation - -static int CompareSb(const CStatusBarItem *p1, const CStatusBarItem *p2) -{ - if (p1->bAccDel != p2->bAccDel) - return (p1->bAccDel) ? 1 : -1; - - if (p1->bAccOff != p2->bAccOff) - return (p1->bAccOff) ? 1 : -1; - - return mir_strcmp(p1->szProto, p2->szProto); -} - -QSMainDlg::QSMainDlg(const wchar_t *pwszPattern) : - CDlgBase(g_plugin, IDD_MAIN), - m_rows(50), - m_patterns(1), - m_sbdata(10, CompareSb), - m_grid(this, IDC_LIST), - m_hover(this, 10), - cmbProto(this, IDC_CB_PROTOCOLS), - edtFilter(this, IDC_E_SEARCHTEXT), - btnRefresh(this, IDC_REFRESH), - chkColorize(this, IDC_CH_COLORIZE), - chkShowOffline(this, IDC_CH_SHOWOFFLINE) -{ - SetMinSize(300, 160); - - if (pwszPattern) - m_wszPatternBuf = mir_wstrdup(pwszPattern); - else if (g_plugin.m_flags & QSO_SAVEPATTERN) - m_wszPatternBuf = g_plugin.getWStringA("pattern"); - - m_hover.OnEvent = Callback(this, &QSMainDlg::onTimer_Hover); - - m_grid.OnBuildMenu = Callback(this, &QSMainDlg::onBuildMenu_Grid); - m_grid.OnColumnClick = Callback(this, &QSMainDlg::onColumnClick_Grid); - m_grid.OnCustomDraw = Callback(this, &QSMainDlg::onCustomDraw_Grid); - m_grid.OnDoubleClick = Callback(this, &QSMainDlg::onDblClick_Grid); - - btnRefresh.OnClick = Callback(this, &QSMainDlg::onClick_Refresh); - - cmbProto.OnSelChanged = Callback(this, &QSMainDlg::onSelChange_Proto); - - edtFilter.OnChange = Callback(this, &QSMainDlg::onChange_Filter); - chkColorize.OnChange = Callback(this, &QSMainDlg::onChange_Colorize); - chkShowOffline.OnChange = Callback(this, &QSMainDlg::onChange_ShowOffline); -} - -bool QSMainDlg::OnInitDialog() -{ - g_pDlg = this; - mnuhandle = 0; - - SetCaption(TranslateT("Quick Search")); - - hwndStatusBar = GetDlgItem(m_hwnd, IDC_STATUSBAR); - - HMENU smenu = GetSystemMenu(m_hwnd, false); - InsertMenu(smenu, 5, MF_BYPOSITION | MF_SEPARATOR, 0, nullptr); - InsertMenuW(smenu, 6, MF_BYPOSITION | MF_STRING, IDM_STAYONTOP, TranslateT("Stay on Top")); - - if (g_plugin.m_flags & QSO_STAYONTOP) { - CheckMenuItem(smenu, IDM_STAYONTOP, MF_BYCOMMAND | MF_CHECKED); - SetWindowPos(m_hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); - } - - chkShowOffline.SetState((g_plugin.m_flags & QSO_SHOWOFFLINE) != 0); - - szFilterProto = nullptr; // display all protocols - if (g_plugin.m_flags & QSO_SHOWOFFLINE) - bShowOffline = true; - - chkColorize.SetState((g_plugin.m_flags & QSO_COLORIZE) != 0); - - // Window - INT_PTR tmp = GetWindowLongPtrW(m_hwnd, GWL_EXSTYLE); - if (g_plugin.m_flags & QSO_TOOLSTYLE) - tmp |= WS_EX_TOOLWINDOW; - else - tmp &= ~WS_EX_TOOLWINDOW; - SetWindowLongPtrW(m_hwnd, GWL_EXSTYLE, tmp); - - SendMessage(m_hwnd, WM_SETICON, ICON_SMALL, (LPARAM)g_plugin.getIcon(IDI_QS)); - - // ListView - m_grid.SetImageList(Clist_GetImageList(), LVSIL_SMALL); - - tmp = LVS_EX_FULLROWSELECT | LVS_EX_SUBITEMIMAGES | LVS_EX_HEADERDRAGDROP | - LVS_EX_LABELTIP | LVS_EX_DOUBLEBUFFER; - if (g_plugin.m_flags & QSO_DRAWGRID) - tmp |= LVS_EX_GRIDLINES; - m_grid.SetExtendedListViewStyle(tmp); - - // ListView header - HWND header = m_grid.GetHeader(); - SetWindowLongPtrW(header, GWL_STYLE, GetWindowLongPtrW(header, GWL_STYLE) | HDS_CHECKBOXES); - - mir_subclassWindow(edtFilter.GetHwnd(), &sttNewEditProc); - - SetWindowLongPtrW(m_grid.GetHeader(), GWLP_USERDATA, LPARAM(this)); - mir_subclassWindow(m_grid.GetHeader(), &sttNewLVHProc); - - SetWindowLongPtrW(m_grid.GetHwnd(), GWLP_USERDATA, LPARAM(this)); - mir_subclassWindow(m_grid.GetHwnd(), &sttNewLVProc); - - FillProtoCombo(); - - PrepareTable(); - - if (m_wszPatternBuf) { - edtFilter.SetText(m_wszPatternBuf); - MakePattern(m_wszPatternBuf); - } - FillGrid(); - - // Show sorting column - HDITEM hdi = {}; - hdi.mask = HDI_FORMAT; - SendMessageW(header, HDM_GETITEM, g_plugin.m_sortOrder, LPARAM(&hdi)); - if (g_plugin.m_flags & QSO_SORTASC) - hdi.fmt |= HDF_SORTUP; - else - hdi.fmt |= HDF_SORTDOWN; - SendMessageW(header, HDM_SETITEM, g_plugin.m_sortOrder, LPARAM(&hdi)); - - RECT rc = g_plugin.m_rect; - ::SnapToScreen(rc); - ::MoveWindow(m_hwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, false); - - HintWnd = CreateWindowExW(0, TOOLTIPS_CLASS, nullptr, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, m_hwnd, 0, g_plugin.getInst(), 0); - - TOOLINFOW ti; - ti.cbSize = sizeof(ti); - ti.uFlags = TTF_SUBCLASS + TTF_IDISHWND; - ti.hwnd = m_hwnd; - ti.uId = UINT_PTR(m_grid.GetHwnd()); - SendMessageW(HintWnd, TTM_ADDTOOLW, 0, LPARAM(&ti)); - - hAdd = HookEventMessage(ME_DB_CONTACT_ADDED, m_hwnd, WM_CONTACT_ADDED); - hDelete = HookEventMessage(ME_DB_CONTACT_DELETED, m_hwnd, WM_CONTACT_DELETED); - hChange = HookEventMessage(ME_CLIST_CONTACTICONCHANGED, m_hwnd, WM_STATUS_CHANGED); - return true; -} - -void QSMainDlg::OnDestroy() -{ - if (mnuhandle) - Menu_RemoveItem(mnuhandle); - - UnhookEvent(hAdd); - UnhookEvent(hDelete); - UnhookEvent(hChange); - - g_pDlg = nullptr; - - RECT rc; - GetWindowRect(m_hwnd, &rc); - CopyRect(&g_plugin.m_rect, &rc); - - // save column width/order - SaveColumnOrder(); - - g_plugin.SaveOptWnd(); - - m_grid.SetImageList(0, LVSIL_SMALL); - - if (g_plugin.m_flags & QSO_SAVEPATTERN) - g_plugin.setWString("pattern", ptrW(edtFilter.GetText())); - - m_rows.destroy(); - m_patterns.destroy(); -} - -int QSMainDlg::Resizer(UTILRESIZECONTROL *urc) -{ - switch (urc->wId) { - case IDC_REFRESH: - return RD_ANCHORX_RIGHT | RD_ANCHORY_TOP; - - case IDC_E_SEARCHTEXT: - return RD_ANCHORX_WIDTH | RD_ANCHORY_TOP; - - case IDC_LIST: - return RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT; - - case IDC_STATUSBAR: - return RD_ANCHORX_WIDTH | RD_ANCHORY_BOTTOM; - } - return RD_ANCHORX_LEFT | RD_ANCHORY_TOP; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// event handlers - -INT_PTR QSMainDlg::OnContactAdded(UINT, WPARAM hContact, LPARAM) -{ - auto *pRow = new CRowItem(hContact, this); - m_rows.insert(pRow); - AddContactToList(hContact, pRow); - ProcessLine(pRow); - Sort(); - UpdateSB(); - return 0; -} - -INT_PTR QSMainDlg::OnContactDeleted(UINT, WPARAM hContact, LPARAM) -{ - int idx = -1; - CRowItem *pRow = 0; - - for (auto &it : m_rows) - if (it->hContact == hContact) { - pRow = it; - idx = m_rows.indexOf(&it); - break; - } - - if (idx == -1) - return 0; - - int iItem = FindItem(pRow); - if (iItem != -1) - m_grid.DeleteItem(iItem); - - m_rows.remove(idx); - UpdateSB(); - return 0; -} - -INT_PTR QSMainDlg::OnStatusChanged(UINT, WPARAM hContact, LPARAM lParam) -{ - auto *pRow = FindRow(hContact); - if (pRow == nullptr) - return 0; - - int oldStatus = pRow->status; - int newStatus = Contact::GetStatus(hContact); - pRow->status = newStatus; - - if (oldStatus != ID_STATUS_OFFLINE && newStatus != ID_STATUS_OFFLINE) - ChangeStatusPicture(pRow, hContact, lParam); - else if (oldStatus != ID_STATUS_OFFLINE) { - if (g_plugin.m_flags & QSO_SHOWOFFLINE) - ChangeStatusPicture(pRow, hContact, lParam); - else - ProcessLine(pRow, true); - } - else if (newStatus != ID_STATUS_OFFLINE) { - if (g_plugin.m_flags & QSO_SHOWOFFLINE) - ChangeStatusPicture(pRow, hContact, lParam); - else { - pRow->bActive = false; - m_grid.DeleteItem(FindItem(pRow)); - } - } - - if (g_plugin.m_flags & QSO_SORTBYSTATUS) - Sort(); - - UpdateSB(); - return 0; -} - -INT_PTR QSMainDlg::OnSysCommand(UINT, WPARAM wParam, LPARAM) -{ - if (wParam == IDM_STAYONTOP) { - int h; HWND w; - if (g_plugin.m_flags & QSO_STAYONTOP) { - h = MF_BYCOMMAND | MF_UNCHECKED; - w = HWND_NOTOPMOST; - } - else { - h = MF_BYCOMMAND | MF_CHECKED; - w = HWND_TOPMOST; - } - CheckMenuItem(GetSystemMenu(m_hwnd, false), IDM_STAYONTOP, h); - SetWindowPos(m_hwnd, w, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); - g_plugin.m_flags ^= QSO_STAYONTOP; - } - return 0; -} - -INT_PTR QSMainDlg::OnMouseMove(UINT, WPARAM, LPARAM lParam) -{ - if (g_bTipperInstalled) { - RECT rc; - GetWindowRect(m_grid.GetHwnd(), &rc); - - POINT pt = { LOWORD(lParam), HIWORD(lParam) }; - ClientToScreen(m_hwnd, &pt); - if (!PtInRect(&rc, pt)) { - if (TTShowed) { - TTShowed = false; - CallService(MS_TIPPER_HIDETIP, 0, 0); - } - } - - m_hover.Stop(); - } - return 0; -} - -INT_PTR QSMainDlg::OnKeydown(UINT, WPARAM wParam, LPARAM) -{ - if (wParam == VK_F5) - PostMessage(m_hwnd, WM_COMMAND, IDC_REFRESH, 0); - return 0; -} - -void QSMainDlg::onBuildMenu_Grid(CContextMenuPos *pos) -{ - int w = m_grid.GetSelectedCount(); - if (w > 1) - ShowMultiPopup(w); - else - ShowContactMenu(GetFocusedContact(), GetLVSubItem(pos->pt.x, pos->pt.y)); -} - -void QSMainDlg::onSelChange_Proto(CCtrlCombo *) -{ - LPARAM lParam = cmbProto.GetItemData(cmbProto.GetCurSel()); - if (lParam == -1 || lParam == 0) - szFilterProto = nullptr; - else - szFilterProto = ((PROTOACCOUNT *)lParam)->szModuleName; - - AdvancedFilter(); -} - -void QSMainDlg::onChange_Filter(CCtrlEdit *) -{ - if (!m_bInitialized) - return; - - MakePattern(ptrW(edtFilter.GetText())); - FillGrid(); -} - -void QSMainDlg::onChange_ShowOffline(CCtrlCheck *) -{ - if (chkShowOffline.IsChecked()) { - g_plugin.m_flags |= QSO_SHOWOFFLINE; - bShowOffline = true; - } - else { - g_plugin.m_flags &= ~QSO_SHOWOFFLINE; - bShowOffline = false; - } - - AdvancedFilter(); -} - -void QSMainDlg::onChange_Colorize(CCtrlCheck *) -{ - if (chkColorize.IsChecked()) - g_plugin.m_flags |= QSO_COLORIZE; - else - g_plugin.m_flags &= ~QSO_COLORIZE; - RedrawWindow(m_grid.GetHwnd(), nullptr, 0, RDW_INVALIDATE); -} - -void QSMainDlg::onClick_Refresh(CCtrlButton *) -{ - m_rows.destroy(); - PrepareToFill(); - PrepareTable(true); - FillGrid(); -} - -void QSMainDlg::onColumnClick_Grid(CCtrlListView::TEventInfo *ev) -{ - HWND header = m_grid.GetHeader(); - - // clear sort mark - HDITEM hdi = {}; - hdi.mask = HDI_FORMAT; - SendMessage(header, HDM_GETITEM, g_plugin.m_sortOrder, LPARAM(&hdi)); - hdi.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP); - SendMessage(header, HDM_SETITEM, g_plugin.m_sortOrder, LPARAM(&hdi)); - - if (g_plugin.m_sortOrder != ev->nmlv->iSubItem) { - g_plugin.m_flags |= QSO_SORTASC; - g_plugin.m_sortOrder = ev->nmlv->iSubItem; - } - else g_plugin.m_flags ^= QSO_SORTASC;; - - // set new sort mark - SendMessage(header, HDM_GETITEM, g_plugin.m_sortOrder, LPARAM(&hdi)); - if ((g_plugin.m_flags & QSO_SORTASC) == 0) - hdi.fmt |= HDF_SORTDOWN; - else - hdi.fmt &= ~HDF_SORTUP; - SendMessage(header, HDM_SETITEM, g_plugin.m_sortOrder, LPARAM(&hdi)); - - Sort(); -} - -void QSMainDlg::onDblClick_Grid(CCtrlListView::TEventInfo*) -{ - ShowContactMsgDlg(GetFocusedContact()); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void QSMainDlg::onCustomDraw_Grid(CCtrlListView::TEventInfo *ev) -{ - LPNMLVCUSTOMDRAW lplvcd = ev->nmcd; - HICON h; - RECT rc; - auto *pRow = (CRowItem *)lplvcd->nmcd.lItemlParam; - - int result = CDRF_DODEFAULT; - switch (lplvcd->nmcd.dwDrawStage) { - case CDDS_PREPAINT: - result = CDRF_NOTIFYITEMDRAW; - break; - - case CDDS_ITEMPREPAINT: - pRow->GetCellColor(lplvcd->nmcd.dwItemSpec, lplvcd->clrTextBk, lplvcd->clrText); - result = CDRF_NOTIFYSUBITEMDRAW; - break; - - case CDDS_SUBITEM + CDDS_ITEMPREPAINT: - pRow->GetCellColor(lplvcd->nmcd.dwItemSpec, lplvcd->clrTextBk, lplvcd->clrText); - { - int sub = ListViewToColumn(lplvcd->iSubItem); - auto *pCol = &g_plugin.m_columns[sub]; - if (pCol == nullptr) - break; - - if (pCol->isGender) { - m_grid.GetSubItemRect(lplvcd->nmcd.dwItemSpec, lplvcd->iSubItem, LVIR_ICON, &rc); - - switch (pRow->pValues[sub].data) { - case 'F': h = g_plugin.getIcon(IDI_FEMALE); break; - case 'M': h = g_plugin.getIcon(IDI_MALE); break; - default: h = 0; - } - - if (h) - DrawIconEx(lplvcd->nmcd.hdc, rc.left + 1, rc.top, h, 16, 16, 0, 0, DI_NORMAL); - result = CDRF_SKIPDEFAULT; - } - else if (pCol->isXstatus) { - int j = _wtoi(pRow->pValues[sub].text); - if (j > 0 && ProtoServiceExists(pRow->szProto, PS_GETCUSTOMSTATUSICON)) { - h = (HICON)CallProtoService(pRow->szProto, PS_GETCUSTOMSTATUSICON, j, LR_SHARED); - m_grid.GetSubItemRect(lplvcd->nmcd.dwItemSpec, lplvcd->iSubItem, LVIR_ICON, &rc); - DrawIconEx(lplvcd->nmcd.hdc, rc.left + 1, rc.top, h, 16, 16, 0, 0, DI_NORMAL); - } - result = CDRF_SKIPDEFAULT; - } - else if ((g_plugin.m_flags & QSO_CLIENTICONS) && pCol->isClient) - result = CDRF_NOTIFYPOSTPAINT; - } - break; - - case CDDS_SUBITEM + CDDS_ITEMPOSTPAINT: - { - int sub = ListViewToColumn(lplvcd->iSubItem); - auto *pCol = &g_plugin.m_columns[sub]; - if (pCol == nullptr) - break; - - if (pCol->isClient) { - auto *MirVerW = pRow->pValues[sub].text; - if (MirVerW && *MirVerW && g_bFingerInstalled) { - h = Finger_GetClientIcon(MirVerW, FALSE); - m_grid.GetSubItemRect(lplvcd->nmcd.dwItemSpec, lplvcd->iSubItem, LVIR_ICON, &rc); - DrawIconEx(lplvcd->nmcd.hdc, rc.left + 1, rc.top, h, 16, 16, 0, 0, DI_NORMAL); - DestroyIcon(h); - } - } - result = CDRF_SKIPDEFAULT; - } - break; - } - - SetWindowLongPtrW(m_hwnd, DWLP_MSGRESULT, result); -} - -void QSMainDlg::onTimer_Hover(CTimer *pTimer) -{ - pTimer->Stop(); - - if (GetForegroundWindow() != m_hwnd) - return; - - auto *pRow = GetRow(OldHItem); - if (pRow == 0) - return; - - POINT pt; - GetCursorPos(&pt); - - RECT rcItem; - m_grid.GetItemRect(OldHItem, &rcItem, 0); - ScreenToClient(m_grid.GetHwnd(), &pt); - if (!PtInRect(&rcItem, pt)) - return; - - CLCINFOTIP info = {}; - info.cbSize = sizeof(info); - info.hItem = HANDLE(pRow->hContact); - Tipper_ShowTip(0, &info); - TTShowed = true; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -int CloseSrWindow(bool) -{ - if (!g_pDlg) - return false; - - g_pDlg->Close(); - return true; -} - -int OpenSrWindow(const wchar_t *pwszPattern) -{ - if (g_pDlg) { - WINDOWPLACEMENT wp; - wp.length = sizeof(wp); - GetWindowPlacement(g_pDlg->GetHwnd(), &wp); - if (wp.showCmd == SW_SHOWMINIMIZED) - g_pDlg->Show(SW_RESTORE); - SetForegroundWindow(g_pDlg->GetHwnd()); - return true; - } - - int count = 0; - for (auto &it : g_plugin.m_columns) - if (it->bEnabled) - count++; - - // no even one visible column - if (count == 0) - return true; - - g_plugin.LoadOptWnd(); - - auto *pDlg = new QSMainDlg(pwszPattern); - if (pDlg->PrepareToFill()) - pDlg->Create(); - else - delete pDlg; - - return true; -} +/* +Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org) + +This program is free software; you can redistribute it &/| +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY | FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "stdafx.h" + +#define IDM_STAYONTOP (WM_USER+1) + +static QSMainDlg *g_pDlg = 0; + +///////////////////////////////////////////////////////////////////////////////////////// +// edit control window procedure + +static LRESULT CALLBACK sttNewEditProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + auto *pDlg = (QSMainDlg *)GetWindowLongPtrW(hwnd, GWLP_USERDATA); + if (pDlg) + if (INT_PTR res = pDlg->NewEditProc(msg, wParam, lParam)) + return res; + + return mir_callNextSubclass(hwnd, sttNewEditProc, msg, wParam, lParam); +} + +INT_PTR QSMainDlg::NewEditProc(UINT msg, WPARAM wParam, LPARAM) +{ + switch (msg) { + case WM_CHAR: + if (wParam == 27) // Escape + Close(); + break; + + case WM_KEYUP: + if (wParam == VK_RETURN) { + if (m_grid.GetSelectedCount() == 1) + ShowContactMsgDlg(GetFocusedContact()); + return 0; + } + break; + + case WM_KEYDOWN: + int count = m_grid.GetItemCount(); + int current = m_grid.GetNextItem(-1, LVNI_FOCUSED); + int next = -1; + if (count > 0) { + switch (wParam) { + case VK_UP: + if (current > 0) + next = current - 1; + break; + + case VK_DOWN: + if (current < count - 1) + next = current + 1; + break; + + case VK_F5: + onClick_Refresh(0); + return 0; + + case VK_NEXT: + case VK_PRIOR: + int perpage = m_grid.GetCountPerPage(); + if (wParam == VK_NEXT) + next = min(current + perpage, count); + else + next = max(current - perpage, 0); + break; + } + } + + if (next >= 0) { + m_grid.SetItemState(-1, 0, LVIS_SELECTED); + m_grid.SetCurSel(next); + m_grid.EnsureVisible(next, FALSE); + } + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// list header window procedure + +static void MakeColumnMenu() +{ + HMENU hMenu = CreatePopupMenu(); + + for (auto &it : g_plugin.m_columns) { + int flag = MF_STRING + (it->bEnabled) ? MF_CHECKED : MF_UNCHECKED; + AppendMenuW(hMenu, flag, 100 + g_plugin.m_columns.indexOf(&it), TranslateW(it->title)); + } + + POINT pt; + GetCursorPos(&pt); + + int id = TrackPopupMenu(hMenu, TPM_RETURNCMD + TPM_NONOTIFY, pt.x, pt.y, 0, g_pDlg->GetHwnd(), 0); + if (id >= 100) + g_pDlg->ToggleColumn(id - 100); + + DestroyMenu(hMenu); +} + +void QSMainDlg::ToggleColumn(int col) +{ + auto &pCol = g_plugin.m_columns[col]; + + if (!pCol.bEnabled) { // show column + pCol.bEnabled = true; + + if (!pCol.bInit) { + for (auto &it : m_rows) + it->pValues[col].LoadOneItem(it->hContact, pCol, this); + pCol.bInit = true; + } + + // screen + int lvcol = ColumnToListView(col); + AddColumn(lvcol, &pCol); + + int nCount = m_grid.GetItemCount(); + for (int i = 0; i < nCount; i++) { + auto *pRow = GetRow(i); + + LV_ITEMW li; + li.iItem = i; + li.iSubItem = lvcol; + li.mask = LVIF_TEXT; + li.pszText = pRow->pValues[col].text; + if ((pCol.isClient && (g_plugin.m_flags & QSO_CLIENTICONS) && li.pszText) || pCol.isGender || pCol.isXstatus) + li.mask |= LVIF_IMAGE; + m_grid.SetItem(&li); + } + } + else { // hide column + int cnt = 0; + for (auto &it : g_plugin.m_columns) + if (it->bEnabled) + cnt++; + + // keep at least one visible column (1 + this) + if (cnt > 2) { + m_grid.DeleteColumn(col); + pCol.bEnabled = false; + } + } +} + +static LRESULT CALLBACK sttNewLVHProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_RBUTTONUP: + return 0; + + case WM_RBUTTONDOWN: + MakeColumnMenu(); + break; + } + + return mir_callNextSubclass(hwnd, sttNewLVHProc, msg, wParam, lParam); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// grid list window procedure + +static int OldHSubItem = 0, OldHItem = 0; + +static LRESULT CALLBACK sttNewLVProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + auto *pDlg = (QSMainDlg *)GetWindowLongPtrW(hwnd, GWLP_USERDATA); + if (pDlg) + if (INT_PTR res = pDlg->NewLVProc(msg, wParam, lParam)) + return res; + + return mir_callNextSubclass(hwnd, sttNewLVProc, msg, wParam, lParam); +} + +INT_PTR QSMainDlg::NewLVProc(UINT msg, WPARAM wParam, LPARAM lParam) +{ + LV_HITTESTINFO pinfo; + + switch (msg) { + case WM_CHAR: + switch (wParam) { // ESC + case 27: + Close(); + break; + + case 1: // Cltr+A + m_grid.SetItemState(-1, LVIS_SELECTED, LVIS_SELECTED); + break; + + case 3: // Ctrl-C + CopyMultiLines(); + break; + + case 8: // backspace + edtFilter.SendMsg(msg, wParam, lParam); + break; + } + + if (wParam >= 32 && wParam <= 127) // letters + edtFilter.SendMsg(msg, wParam, lParam); + break; + + case WM_MOUSEMOVE: + pinfo.pt.x = LOWORD(lParam); + pinfo.pt.y = HIWORD(lParam); + pinfo.flags = 0; + if (m_grid.SubItemHitTest(&pinfo) == -1) + break; + + if ((pinfo.flags & LVHT_ONITEM) && (pinfo.iItem != OldHItem || pinfo.iSubItem != OldHSubItem)) { + OldHSubItem = pinfo.iSubItem; + OldHItem = pinfo.iItem; + + if (g_bTipperInstalled) { + if (TTShowed) { + TTShowed = false; + Tipper_Hide(); + } + m_hover.Stop(); + + if (OldHSubItem == 0) + m_hover.Start(450); + } + + TOOLINFOW ti = {}; + ti.cbSize = sizeof(ti); + ti.uFlags = TTF_SUBCLASS + TTF_IDISHWND; + ti.hwnd = m_hwnd; + ti.uId = LPARAM(m_hwnd); + + int num = ListViewToColumn(OldHSubItem); + auto &pCol = g_plugin.m_columns[num]; + if (pCol.isXstatus || pCol.isGender) { + auto *pRow = GetRow(OldHItem); + if (pCol.isGender) { + switch (pRow->pValues[num].data) { + case 'M': ti.lpszText = TranslateT("Male"); break; + case 'F': ti.lpszText = TranslateT("Female"); break; + default: ti.lpszText = TranslateT("Unknown"); break; + } + } + else { + wchar_t buf[256]; + mir_wstrncpy(buf, pRow->pValues[num].text, _countof(buf)); + int iStatus = _wtoi(buf); + + CUSTOM_STATUS ics = {}; + ics.cbSize = sizeof(ics); + ics.status = &iStatus; + ics.flags = CSSF_DEFAULT_NAME | CSSF_MASK_NAME | CSSF_UNICODE; + ics.pwszName = buf; + CallProtoService(pRow->szProto, PS_GETCUSTOMSTATUSEX, 0, (LPARAM)&ics); + ti.lpszText = TranslateW(buf); + } + } + + SendMessageW(HintWnd, TTM_SETTOOLINFOW, 0, LPARAM(&ti)); + } + break; + + case WM_KEYUP: + switch (wParam) { + case VK_RETURN: + if (m_grid.GetSelectedCount() == 1) + ShowContactMsgDlg(GetFocusedContact()); + break; + + case VK_INSERT: + CallService(MS_FINDADD_FINDADD, 0, 0); + break; + + case VK_DELETE: + lParam = m_grid.GetSelectedCount(); + if (lParam > 1) + DeleteByList(); + else if (lParam == 1) + DeleteOneContact(GetFocusedContact()); + break; + + case VK_F5: + onClick_Refresh(0); + break; + } + break; + + case WM_NOTIFY: + if (((LPNMHDR)lParam)->code == HDN_ITEMSTATEICONCLICK) { + NMHEADER *pdhr = (NMHEADER *)lParam; + if ((pdhr->pitem->mask & HDI_FORMAT) && (pdhr->pitem->fmt & HDF_CHECKBOX)) { + int i = ListViewToColumn(pdhr->iItem); + auto &pCol = g_plugin.m_columns[i]; + + if (pdhr->pitem->fmt & HDF_CHECKED) { + pCol.bFilter = false; + pdhr->pitem->fmt &= ~HDF_CHECKED; + } + else { + pCol.bFilter = true; + pdhr->pitem->fmt |= HDF_CHECKED; + } + + SendMessage(pdhr->hdr.hwndFrom, HDM_SETITEM, pdhr->iItem, LPARAM(pdhr->pitem)); + FillGrid(); + return TRUE; + } + } + } + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// QSMainDlg class implementation + +static int CompareSb(const CStatusBarItem *p1, const CStatusBarItem *p2) +{ + if (p1->bAccDel != p2->bAccDel) + return (p1->bAccDel) ? 1 : -1; + + if (p1->bAccOff != p2->bAccOff) + return (p1->bAccOff) ? 1 : -1; + + return mir_strcmp(p1->szProto, p2->szProto); +} + +QSMainDlg::QSMainDlg(const wchar_t *pwszPattern) : + CDlgBase(g_plugin, IDD_MAIN), + m_rows(50), + m_patterns(1), + m_sbdata(10, CompareSb), + m_grid(this, IDC_LIST), + m_hover(this, 10), + cmbProto(this, IDC_CB_PROTOCOLS), + edtFilter(this, IDC_E_SEARCHTEXT), + btnRefresh(this, IDC_REFRESH), + chkColorize(this, IDC_CH_COLORIZE), + chkShowOffline(this, IDC_CH_SHOWOFFLINE) +{ + SetMinSize(300, 160); + + if (pwszPattern) + m_wszPatternBuf = mir_wstrdup(pwszPattern); + else if (g_plugin.m_flags & QSO_SAVEPATTERN) + m_wszPatternBuf = g_plugin.getWStringA("pattern"); + + m_hover.OnEvent = Callback(this, &QSMainDlg::onTimer_Hover); + + m_grid.OnBuildMenu = Callback(this, &QSMainDlg::onBuildMenu_Grid); + m_grid.OnColumnClick = Callback(this, &QSMainDlg::onColumnClick_Grid); + m_grid.OnCustomDraw = Callback(this, &QSMainDlg::onCustomDraw_Grid); + m_grid.OnDoubleClick = Callback(this, &QSMainDlg::onDblClick_Grid); + + btnRefresh.OnClick = Callback(this, &QSMainDlg::onClick_Refresh); + + cmbProto.OnSelChanged = Callback(this, &QSMainDlg::onSelChange_Proto); + + edtFilter.OnChange = Callback(this, &QSMainDlg::onChange_Filter); + chkColorize.OnChange = Callback(this, &QSMainDlg::onChange_Colorize); + chkShowOffline.OnChange = Callback(this, &QSMainDlg::onChange_ShowOffline); +} + +bool QSMainDlg::OnInitDialog() +{ + g_pDlg = this; + mnuhandle = 0; + + SetCaption(TranslateT("Quick Search")); + + hwndStatusBar = GetDlgItem(m_hwnd, IDC_STATUSBAR); + + HMENU smenu = GetSystemMenu(m_hwnd, false); + InsertMenu(smenu, 5, MF_BYPOSITION | MF_SEPARATOR, 0, nullptr); + InsertMenuW(smenu, 6, MF_BYPOSITION | MF_STRING, IDM_STAYONTOP, TranslateT("Stay on Top")); + + if (g_plugin.m_flags & QSO_STAYONTOP) { + CheckMenuItem(smenu, IDM_STAYONTOP, MF_BYCOMMAND | MF_CHECKED); + SetWindowPos(m_hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + } + + chkShowOffline.SetState((g_plugin.m_flags & QSO_SHOWOFFLINE) != 0); + + szFilterProto = nullptr; // display all protocols + if (g_plugin.m_flags & QSO_SHOWOFFLINE) + bShowOffline = true; + + chkColorize.SetState((g_plugin.m_flags & QSO_COLORIZE) != 0); + + // Window + INT_PTR tmp = GetWindowLongPtrW(m_hwnd, GWL_EXSTYLE); + if (g_plugin.m_flags & QSO_TOOLSTYLE) + tmp |= WS_EX_TOOLWINDOW; + else + tmp &= ~WS_EX_TOOLWINDOW; + SetWindowLongPtrW(m_hwnd, GWL_EXSTYLE, tmp); + + SendMessage(m_hwnd, WM_SETICON, ICON_SMALL, (LPARAM)g_plugin.getIcon(IDI_QS)); + + // ListView + m_grid.SetImageList(Clist_GetImageList(), LVSIL_SMALL); + + tmp = LVS_EX_FULLROWSELECT | LVS_EX_SUBITEMIMAGES | LVS_EX_HEADERDRAGDROP | + LVS_EX_LABELTIP | LVS_EX_DOUBLEBUFFER; + if (g_plugin.m_flags & QSO_DRAWGRID) + tmp |= LVS_EX_GRIDLINES; + m_grid.SetExtendedListViewStyle(tmp); + + // ListView header + HWND header = m_grid.GetHeader(); + SetWindowLongPtrW(header, GWL_STYLE, GetWindowLongPtrW(header, GWL_STYLE) | HDS_CHECKBOXES); + + mir_subclassWindow(edtFilter.GetHwnd(), &sttNewEditProc); + + SetWindowLongPtrW(m_grid.GetHeader(), GWLP_USERDATA, LPARAM(this)); + mir_subclassWindow(m_grid.GetHeader(), &sttNewLVHProc); + + SetWindowLongPtrW(m_grid.GetHwnd(), GWLP_USERDATA, LPARAM(this)); + mir_subclassWindow(m_grid.GetHwnd(), &sttNewLVProc); + + FillProtoCombo(); + + PrepareTable(); + + if (m_wszPatternBuf) { + edtFilter.SetText(m_wszPatternBuf); + MakePattern(m_wszPatternBuf); + } + FillGrid(); + + // Show sorting column + HDITEM hdi = {}; + hdi.mask = HDI_FORMAT; + SendMessageW(header, HDM_GETITEM, g_plugin.m_sortOrder, LPARAM(&hdi)); + if (g_plugin.m_flags & QSO_SORTASC) + hdi.fmt |= HDF_SORTUP; + else + hdi.fmt |= HDF_SORTDOWN; + SendMessageW(header, HDM_SETITEM, g_plugin.m_sortOrder, LPARAM(&hdi)); + + RECT rc = g_plugin.m_rect; + ::SnapToScreen(rc); + ::MoveWindow(m_hwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, false); + + HintWnd = CreateWindowExW(0, TOOLTIPS_CLASS, nullptr, 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, m_hwnd, 0, g_plugin.getInst(), 0); + + TOOLINFOW ti; + ti.cbSize = sizeof(ti); + ti.uFlags = TTF_SUBCLASS + TTF_IDISHWND; + ti.hwnd = m_hwnd; + ti.uId = UINT_PTR(m_grid.GetHwnd()); + SendMessageW(HintWnd, TTM_ADDTOOLW, 0, LPARAM(&ti)); + + hAdd = HookEventMessage(ME_DB_CONTACT_ADDED, m_hwnd, WM_CONTACT_ADDED); + hDelete = HookEventMessage(ME_DB_CONTACT_DELETED, m_hwnd, WM_CONTACT_DELETED); + hChange = HookEventMessage(ME_CLIST_CONTACTICONCHANGED, m_hwnd, WM_STATUS_CHANGED); + return true; +} + +void QSMainDlg::OnDestroy() +{ + if (mnuhandle) + Menu_RemoveItem(mnuhandle); + + UnhookEvent(hAdd); + UnhookEvent(hDelete); + UnhookEvent(hChange); + + g_pDlg = nullptr; + + RECT rc; + GetWindowRect(m_hwnd, &rc); + CopyRect(&g_plugin.m_rect, &rc); + + // save column width/order + SaveColumnOrder(); + + g_plugin.SaveOptWnd(); + + m_grid.SetImageList(0, LVSIL_SMALL); + + if (g_plugin.m_flags & QSO_SAVEPATTERN) + g_plugin.setWString("pattern", ptrW(edtFilter.GetText())); + + m_rows.destroy(); + m_patterns.destroy(); +} + +int QSMainDlg::Resizer(UTILRESIZECONTROL *urc) +{ + switch (urc->wId) { + case IDC_REFRESH: + return RD_ANCHORX_RIGHT | RD_ANCHORY_TOP; + + case IDC_E_SEARCHTEXT: + return RD_ANCHORX_WIDTH | RD_ANCHORY_TOP; + + case IDC_LIST: + return RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT; + + case IDC_STATUSBAR: + return RD_ANCHORX_WIDTH | RD_ANCHORY_BOTTOM; + } + return RD_ANCHORX_LEFT | RD_ANCHORY_TOP; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// event handlers + +INT_PTR QSMainDlg::OnContactAdded(UINT, WPARAM hContact, LPARAM) +{ + auto *pRow = new CRowItem(hContact, this); + m_rows.insert(pRow); + AddContactToList(hContact, pRow); + ProcessLine(pRow); + Sort(); + UpdateSB(); + return 0; +} + +INT_PTR QSMainDlg::OnContactDeleted(UINT, WPARAM hContact, LPARAM) +{ + int idx = -1; + CRowItem *pRow = 0; + + for (auto &it : m_rows) + if (it->hContact == hContact) { + pRow = it; + idx = m_rows.indexOf(&it); + break; + } + + if (idx == -1) + return 0; + + int iItem = FindItem(pRow); + if (iItem != -1) + m_grid.DeleteItem(iItem); + + m_rows.remove(idx); + UpdateSB(); + return 0; +} + +INT_PTR QSMainDlg::OnStatusChanged(UINT, WPARAM hContact, LPARAM lParam) +{ + auto *pRow = FindRow(hContact); + if (pRow == nullptr) + return 0; + + int oldStatus = pRow->status; + int newStatus = Contact::GetStatus(hContact); + pRow->status = newStatus; + + if (oldStatus != ID_STATUS_OFFLINE && newStatus != ID_STATUS_OFFLINE) + ChangeStatusPicture(pRow, hContact, lParam); + else if (oldStatus != ID_STATUS_OFFLINE) { + if (g_plugin.m_flags & QSO_SHOWOFFLINE) + ChangeStatusPicture(pRow, hContact, lParam); + else + ProcessLine(pRow, true); + } + else if (newStatus != ID_STATUS_OFFLINE) { + if (g_plugin.m_flags & QSO_SHOWOFFLINE) + ChangeStatusPicture(pRow, hContact, lParam); + else { + pRow->bActive = false; + m_grid.DeleteItem(FindItem(pRow)); + } + } + + if (g_plugin.m_flags & QSO_SORTBYSTATUS) + Sort(); + + UpdateSB(); + return 0; +} + +INT_PTR QSMainDlg::OnSysCommand(UINT, WPARAM wParam, LPARAM) +{ + if (wParam == IDM_STAYONTOP) { + int h; HWND w; + if (g_plugin.m_flags & QSO_STAYONTOP) { + h = MF_BYCOMMAND | MF_UNCHECKED; + w = HWND_NOTOPMOST; + } + else { + h = MF_BYCOMMAND | MF_CHECKED; + w = HWND_TOPMOST; + } + CheckMenuItem(GetSystemMenu(m_hwnd, false), IDM_STAYONTOP, h); + SetWindowPos(m_hwnd, w, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + g_plugin.m_flags ^= QSO_STAYONTOP; + } + return 0; +} + +INT_PTR QSMainDlg::OnMouseMove(UINT, WPARAM, LPARAM lParam) +{ + if (g_bTipperInstalled) { + RECT rc; + GetWindowRect(m_grid.GetHwnd(), &rc); + + POINT pt = { LOWORD(lParam), HIWORD(lParam) }; + ClientToScreen(m_hwnd, &pt); + if (!PtInRect(&rc, pt)) { + if (TTShowed) { + TTShowed = false; + CallService(MS_TIPPER_HIDETIP, 0, 0); + } + } + + m_hover.Stop(); + } + return 0; +} + +INT_PTR QSMainDlg::OnKeydown(UINT, WPARAM wParam, LPARAM) +{ + if (wParam == VK_F5) + PostMessage(m_hwnd, WM_COMMAND, IDC_REFRESH, 0); + return 0; +} + +void QSMainDlg::onBuildMenu_Grid(CContextMenuPos *pos) +{ + int w = m_grid.GetSelectedCount(); + if (w > 1) + ShowMultiPopup(w); + else + ShowContactMenu(GetFocusedContact(), GetLVSubItem(pos->pt.x, pos->pt.y)); +} + +void QSMainDlg::onSelChange_Proto(CCtrlCombo *) +{ + LPARAM lParam = cmbProto.GetItemData(cmbProto.GetCurSel()); + if (lParam == -1 || lParam == 0) + szFilterProto = nullptr; + else + szFilterProto = ((PROTOACCOUNT *)lParam)->szModuleName; + + AdvancedFilter(); +} + +void QSMainDlg::onChange_Filter(CCtrlEdit *) +{ + if (!m_bInitialized) + return; + + MakePattern(ptrW(edtFilter.GetText())); + FillGrid(); +} + +void QSMainDlg::onChange_ShowOffline(CCtrlCheck *) +{ + if (chkShowOffline.IsChecked()) { + g_plugin.m_flags |= QSO_SHOWOFFLINE; + bShowOffline = true; + } + else { + g_plugin.m_flags &= ~QSO_SHOWOFFLINE; + bShowOffline = false; + } + + AdvancedFilter(); +} + +void QSMainDlg::onChange_Colorize(CCtrlCheck *) +{ + if (chkColorize.IsChecked()) + g_plugin.m_flags |= QSO_COLORIZE; + else + g_plugin.m_flags &= ~QSO_COLORIZE; + RedrawWindow(m_grid.GetHwnd(), nullptr, 0, RDW_INVALIDATE); +} + +void QSMainDlg::onClick_Refresh(CCtrlButton *) +{ + m_rows.destroy(); + PrepareToFill(); + PrepareTable(true); + FillGrid(); +} + +void QSMainDlg::onColumnClick_Grid(CCtrlListView::TEventInfo *ev) +{ + HWND header = m_grid.GetHeader(); + + // clear sort mark + HDITEM hdi = {}; + hdi.mask = HDI_FORMAT; + SendMessage(header, HDM_GETITEM, g_plugin.m_sortOrder, LPARAM(&hdi)); + hdi.fmt &= ~(HDF_SORTDOWN | HDF_SORTUP); + SendMessage(header, HDM_SETITEM, g_plugin.m_sortOrder, LPARAM(&hdi)); + + if (g_plugin.m_sortOrder != ev->nmlv->iSubItem) { + g_plugin.m_flags |= QSO_SORTASC; + g_plugin.m_sortOrder = ev->nmlv->iSubItem; + } + else g_plugin.m_flags ^= QSO_SORTASC;; + + // set new sort mark + SendMessage(header, HDM_GETITEM, g_plugin.m_sortOrder, LPARAM(&hdi)); + if ((g_plugin.m_flags & QSO_SORTASC) == 0) + hdi.fmt |= HDF_SORTDOWN; + else + hdi.fmt &= ~HDF_SORTUP; + SendMessage(header, HDM_SETITEM, g_plugin.m_sortOrder, LPARAM(&hdi)); + + Sort(); +} + +void QSMainDlg::onDblClick_Grid(CCtrlListView::TEventInfo*) +{ + ShowContactMsgDlg(GetFocusedContact()); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void QSMainDlg::onCustomDraw_Grid(CCtrlListView::TEventInfo *ev) +{ + LPNMLVCUSTOMDRAW lplvcd = ev->nmcd; + HICON h; + RECT rc; + auto *pRow = (CRowItem *)lplvcd->nmcd.lItemlParam; + + int result = CDRF_DODEFAULT; + switch (lplvcd->nmcd.dwDrawStage) { + case CDDS_PREPAINT: + result = CDRF_NOTIFYITEMDRAW; + break; + + case CDDS_ITEMPREPAINT: + pRow->GetCellColor(lplvcd->nmcd.dwItemSpec, lplvcd->clrTextBk, lplvcd->clrText); + result = CDRF_NOTIFYSUBITEMDRAW; + break; + + case CDDS_SUBITEM + CDDS_ITEMPREPAINT: + pRow->GetCellColor(lplvcd->nmcd.dwItemSpec, lplvcd->clrTextBk, lplvcd->clrText); + { + int sub = ListViewToColumn(lplvcd->iSubItem); + auto *pCol = &g_plugin.m_columns[sub]; + if (pCol == nullptr) + break; + + if (pCol->isGender) { + m_grid.GetSubItemRect(lplvcd->nmcd.dwItemSpec, lplvcd->iSubItem, LVIR_ICON, &rc); + + switch (pRow->pValues[sub].data) { + case 'F': h = g_plugin.getIcon(IDI_FEMALE); break; + case 'M': h = g_plugin.getIcon(IDI_MALE); break; + default: h = 0; + } + + if (h) + DrawIconEx(lplvcd->nmcd.hdc, rc.left + 1, rc.top, h, 16, 16, 0, 0, DI_NORMAL); + result = CDRF_SKIPDEFAULT; + } + else if (pCol->isXstatus) { + int j = _wtoi(pRow->pValues[sub].text); + if (j > 0 && ProtoServiceExists(pRow->szProto, PS_GETCUSTOMSTATUSICON)) { + h = (HICON)CallProtoService(pRow->szProto, PS_GETCUSTOMSTATUSICON, j, LR_SHARED); + m_grid.GetSubItemRect(lplvcd->nmcd.dwItemSpec, lplvcd->iSubItem, LVIR_ICON, &rc); + DrawIconEx(lplvcd->nmcd.hdc, rc.left + 1, rc.top, h, 16, 16, 0, 0, DI_NORMAL); + } + result = CDRF_SKIPDEFAULT; + } + else if ((g_plugin.m_flags & QSO_CLIENTICONS) && pCol->isClient) + result = CDRF_NOTIFYPOSTPAINT; + } + break; + + case CDDS_SUBITEM + CDDS_ITEMPOSTPAINT: + { + int sub = ListViewToColumn(lplvcd->iSubItem); + auto *pCol = &g_plugin.m_columns[sub]; + if (pCol == nullptr) + break; + + if (pCol->isClient) { + auto *MirVerW = pRow->pValues[sub].text; + if (MirVerW && *MirVerW && g_bFingerInstalled) { + h = Finger_GetClientIcon(MirVerW, FALSE); + m_grid.GetSubItemRect(lplvcd->nmcd.dwItemSpec, lplvcd->iSubItem, LVIR_ICON, &rc); + DrawIconEx(lplvcd->nmcd.hdc, rc.left + 1, rc.top, h, 16, 16, 0, 0, DI_NORMAL); + DestroyIcon(h); + } + } + result = CDRF_SKIPDEFAULT; + } + break; + } + + SetWindowLongPtrW(m_hwnd, DWLP_MSGRESULT, result); +} + +void QSMainDlg::onTimer_Hover(CTimer *pTimer) +{ + pTimer->Stop(); + + if (GetForegroundWindow() != m_hwnd) + return; + + auto *pRow = GetRow(OldHItem); + if (pRow == 0) + return; + + POINT pt; + GetCursorPos(&pt); + + RECT rcItem; + m_grid.GetItemRect(OldHItem, &rcItem, 0); + ScreenToClient(m_grid.GetHwnd(), &pt); + if (!PtInRect(&rcItem, pt)) + return; + + CLCINFOTIP info = {}; + info.cbSize = sizeof(info); + info.hItem = HANDLE(pRow->hContact); + Tipper_ShowTip(0, &info); + TTShowed = true; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +int CloseSrWindow(bool) +{ + if (!g_pDlg) + return false; + + g_pDlg->Close(); + return true; +} + +int OpenSrWindow(const wchar_t *pwszPattern) +{ + if (g_pDlg) { + WINDOWPLACEMENT wp; + wp.length = sizeof(wp); + GetWindowPlacement(g_pDlg->GetHwnd(), &wp); + if (wp.showCmd == SW_SHOWMINIMIZED) + g_pDlg->Show(SW_RESTORE); + SetForegroundWindow(g_pDlg->GetHwnd()); + return true; + } + + int count = 0; + for (auto &it : g_plugin.m_columns) + if (it->bEnabled) + count++; + + // no even one visible column + if (count == 0) + return true; + + g_plugin.LoadOptWnd(); + + auto *pDlg = new QSMainDlg(pwszPattern); + if (pDlg->PrepareToFill()) + pDlg->Create(); + else + delete pDlg; + + return true; +} diff --git a/plugins/QuickSearch/src/window_misc.cpp b/plugins/QuickSearch/src/window_misc.cpp index e6b5e23341..58d96561fc 100644 --- a/plugins/QuickSearch/src/window_misc.cpp +++ b/plugins/QuickSearch/src/window_misc.cpp @@ -1,875 +1,875 @@ -/* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org) - -This program is free software; you can redistribute it &/| -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY | FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "stdafx.h" - -///////////////////////////////////////////////////////////////////////////////////////// -// patterns - -bool QSMainDlg::CheckPattern(CRowItem *pRow) -{ - if (m_patterns.getCount() == 0) - return true; - - for (auto &p : m_patterns) - p->res = 0; - - int i = 0; - for (auto &it : g_plugin.m_columns) { - if (it->bEnabled && it->bFilter && pRow->pValues[i].text != nullptr) { - CMStringW buf(pRow->pValues[i].text); - buf.MakeLower(); - - for (auto &p : m_patterns) - if (!p->res && buf.Find(p->str) != -1) - p->res = true; - } - i++; - } - - bool result = true; - for (auto &p : m_patterns) - result = result && p->res; - return result; -} - -void QSMainDlg::MakePattern(const wchar_t *pwszPattern) -{ - m_patterns.destroy(); - if (mir_wstrlen(pwszPattern) == 0) - return; - - // m_wszPatternBuf works as a storage for patterns, we store pointers to it in m_patterns - m_wszPatternBuf = mir_wstrdup(pwszPattern); - CharLowerW(m_wszPatternBuf); - - for (wchar_t *p = m_wszPatternBuf; *p; ) { - auto *pWord = wcspbrk(p, L" \""); - if (pWord == nullptr) { - m_patterns.insert(new Pattern(p)); - return; - } - - bool isSpace = pWord[0] == ' '; - - // there's some valuable info between p and pWord - if (pWord != p) { - *pWord = 0; - m_patterns.insert(new Pattern(p)); - } - - if (isSpace) { - p = ltrimpw(pWord + 1); // skip all spaces - } - else { - auto *pEnd = wcschr(++pWord, '\"'); - - // treat the rest of line as one pattern - if (pEnd == nullptr) { - m_patterns.insert(new Pattern(pWord)); - return; - } - - *pEnd = 0; - m_patterns.insert(new Pattern(pWord)); - p = ltrimpw(pEnd + 1); - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void QSMainDlg::AddColumn(int idx, ColumnItem *pCol) -{ - LV_COLUMN lvcol = {}; - lvcol.mask = LVCF_TEXT | LVCF_WIDTH; - lvcol.pszText = TranslateW(pCol->title); - lvcol.cx = pCol->width; - m_grid.InsertColumn(idx, &lvcol); - - HDITEM hdi; - hdi.mask = HDI_FORMAT; - if (pCol->bFilter) - hdi.fmt = HDF_LEFT | HDF_STRING | HDF_CHECKBOX | HDF_CHECKED; - else - hdi.fmt = HDF_LEFT | HDF_STRING | HDF_CHECKBOX; - SendMessage(m_grid.GetHeader(), HDM_SETITEM, idx, LPARAM(&hdi)); -} - -void QSMainDlg::AddContactToList(MCONTACT hContact, CRowItem *pRow) -{ - LV_ITEMW li = {}; - li.mask = LVIF_IMAGE | LVIF_PARAM; - li.iItem = 100000; - li.iImage = Clist_GetContactIcon(hContact); - li.lParam = LPARAM(pRow); - - li.iItem = m_grid.InsertItem(&li); - li.iImage = 0; - li.iSubItem = 0; - - for (int i = 0; i < g_plugin.m_columns.getCount(); i++) { - auto &col = g_plugin.m_columns[i]; - if (!col.bEnabled) - continue; - - // Client icons preprocess - li.pszText = pRow->pValues[i].text; - li.mask = LVIF_TEXT; - if ((col.isClient && (g_plugin.m_flags & QSO_CLIENTICONS) && li.pszText != 0) || col.isXstatus || col.isGender) - li.mask |= LVIF_IMAGE; - m_grid.SetItem(&li); - li.iSubItem++; - } -} - -void QSMainDlg::AdvancedFilter() -{ - m_grid.SetDraw(false); - - for (auto &it : m_rows) { - bool bShow = (szFilterProto == nullptr) || !mir_strcmp(szFilterProto, it->szProto); - if (bShow && !bShowOffline && it->status == ID_STATUS_OFFLINE) - bShow = false; - - if (it->bPattern) { - if (bShow) { - if (!it->bActive) - ProcessLine(it, false); - } - else { - it->bActive = false; - m_grid.DeleteItem(FindItem(it)); - } - } - } - - m_grid.SetDraw(true); - InvalidateRect(m_grid.GetHwnd(), 0, false); - - Sort(); - UpdateSB(); -} - -void QSMainDlg::ChangeStatusPicture(CRowItem *pRow, MCONTACT, LPARAM lParam) -{ - int idx = FindItem(pRow); - if (idx == -1) - return; - - LV_ITEMW li = {}; - li.iItem = idx; - li.mask = LVIF_IMAGE; - li.iImage = lParam; //CallService(MS_CLIST_GETCONTACTICON,hContact,0); - m_grid.SetItem(&li); -} - -void QSMainDlg::CopyMultiLines() -{ - CMStringW buf; - - int i = 0; - for (auto &it : g_plugin.m_columns) { - if (it->bEnabled) { - it->width = m_grid.GetColumnWidth(i); - if (it->width >= 10) - buf.AppendFormat(L"%s\t", it->title); - } - i++; - } - buf.Append(L"\r\n"); - - int nRows = m_grid.GetItemCount(); - int nSelected = m_grid.GetSelectedCount(); - - for (int j = 0; j < nRows; j++) { - if (nSelected > 1 && !m_grid.GetItemState(j, LVIS_SELECTED)) - continue; - - auto *pRow = GetRow(j); - - i = 0; - for (auto &it : g_plugin.m_columns) { - if (it->bEnabled && it->width >= 10) - buf.AppendFormat(L"%s\t", pRow->pValues[i].getText()); - i++; - } - buf.Append(L"\r\n"); - } - - Utils_ClipboardCopy(buf); -} - -void QSMainDlg::DeleteByList() -{ - if (IDOK != MessageBoxW(0, TranslateT("Do you really want to delete selected contacts?"), TranslateT("Warning"), MB_OKCANCEL + MB_ICONWARNING)) - return; - - m_grid.SetDraw(false); - - for (int i = m_grid.GetItemCount() - 1; i >= 0; i--) - if (m_grid.GetItemState(i, LVIS_SELECTED)) - db_delete_contact(GetRow(i)->hContact); - - m_grid.SetDraw(true); -} - -void QSMainDlg::DeleteOneContact(MCONTACT hContact) -{ - if (ServiceExists(MS_CLIST_DELETECONTACT)) - CallService(MS_CLIST_DELETECONTACT, hContact, 0); - else - db_delete_contact(hContact); -} - -wchar_t* QSMainDlg::DoMeta(MCONTACT hContact) -{ - for (auto &it : m_rows) { - if (it->hContact != hContact) - continue; - - if (it->bIsMeta) { - if (it->wparam == 0) - it->wparam = ++hLastMeta; - } - else if (it->bIsSub) - it->lparam = FindMeta(db_mc_getMeta(hContact), it->wparam); - - if (it->wparam > 0) { - CMStringW tmp(FORMAT, L"[%d]", int(it->wparam)); - if (it->lparam > 0) - tmp.AppendFormat(L" %d", int(it->lparam)); - return tmp.Detach(); - } - break; - } - - return nullptr; -} - -void QSMainDlg::DrawSB() -{ - CStatusBarItem global(0, 0); - for (auto &it : m_sbdata) { - global.found += it->found; - global.liston += it->liston; - global.online += it->online; - global.total += it->total; - } - - CMStringW buf(FORMAT, TranslateT("%i users found (%i) Online: %i"), global.found, m_rows.getCount(), global.online); - - RECT rc; - HDC hdc = GetDC(hwndStatusBar); - DrawTextW(hdc, buf, buf.GetLength(), &rc, DT_CALCRECT); - ReleaseDC(hwndStatusBar, hdc); - - int all = rc.right - rc.left, i = 1; - - mir_ptr parts((int*)mir_alloc(sizeof(int) * (m_sbdata.getCount()+2))); - parts[0] = all; - for (auto &it : m_sbdata) { - UNREFERENCED_PARAMETER(it); - all += 55; - parts[i++] = all; - } - parts[i] = -1; - SendMessageW(hwndStatusBar, SB_SETPARTS, m_sbdata.getCount() + 2, LPARAM(parts.get())); - SendMessageW(hwndStatusBar, SB_SETTEXTW, 0, LPARAM(buf.c_str())); - - i = 1; - for (auto &it : m_sbdata) { - HICON hIcon; - wchar_t c, *pc; - if (it->bAccDel) { - c = '!'; - pc = TranslateT("deleted"); - hIcon = Skin_LoadProtoIcon(it->szProto, ID_STATUS_OFFLINE); - } - else if (it->bAccOff) { - c = '?'; - pc = TranslateT("disabled"); - hIcon = Skin_LoadProtoIcon(it->szProto, ID_STATUS_OFFLINE); - } - else { - c = ' '; - pc = TranslateT("active"); - hIcon = Skin_LoadProtoIcon(it->szProto, ID_STATUS_ONLINE); - } - - SendMessageW(hwndStatusBar, SB_SETICON, i, (LPARAM)hIcon); - - buf.Format(L"%c %d", c, it->found); - SendMessageW(hwndStatusBar, SB_SETTEXTW, i, LPARAM(buf.c_str())); - - auto *pa = Proto_GetAccount(it->szProto); - buf.Format(L"%s (%s): %d (%d); %s %d (%d))", pa->tszAccountName, pc, it->found, it->total, TranslateT("Online"), it->liston, it->online); - SendMessageW(hwndStatusBar, SB_SETTIPTEXTW, i, LPARAM(buf.c_str())); - i++; - } -} - -void QSMainDlg::FillGrid() -{ - m_grid.SetDraw(false); - - for (auto &it: m_rows) - ProcessLine(it); - - m_grid.SetDraw(true); - InvalidateRect(m_grid.GetHwnd(), 0, FALSE); - - Sort(); - UpdateSB(); - AdvancedFilter(); - - m_grid.SetCurSel(0); -} - -void QSMainDlg::FillProtoCombo() -{ - cmbProto.ResetContent(); - cmbProto.AddString(TranslateT("All")); - - for (auto &it : Accounts()) - cmbProto.AddString(it->tszAccountName, (LPARAM)it); - - cmbProto.SetCurSel(0); -} - -int QSMainDlg::FindItem(CRowItem *pRow) -{ - if (pRow == nullptr) - return -1; - - LV_FINDINFO fi = {}; - fi.flags = LVFI_PARAM; - fi.lParam = LPARAM(pRow); - return m_grid.FindItem(-1, &fi); -} - -int QSMainDlg::FindMeta(MCONTACT hMeta, WPARAM &metaNum) -{ - for (auto &it : m_rows) { - if (it->hContact != hMeta) - continue; - - // new meta - if (it->wparam == 0) { - it->wparam = ++hLastMeta; - it->lparam = 0; - } - metaNum = it->wparam; - it->lparam++; - return it->lparam; - } - - return 0; -} - -CRowItem* QSMainDlg::FindRow(MCONTACT hContact) -{ - for (auto &it : m_rows) - if (it->hContact == hContact) - return it; - - return nullptr; -} - -MCONTACT QSMainDlg::GetFocusedContact() -{ - int idx = m_grid.GetSelectionMark(); - if (idx == -1) - return -1; - - INT_PTR data = m_grid.GetItemData(idx); - return (data == -1) ? -1 : ((CRowItem *)data)->hContact; -} - -int QSMainDlg::GetLVSubItem(int x, int y) -{ - LV_HITTESTINFO info = {}; - info.pt.x = x; - info.pt.y = y; - ScreenToClient(m_grid.GetHwnd(), &info.pt); - if (m_grid.SubItemHitTest(&info) == -1) - return -1; - - return (info.flags & LVHT_ONITEM) ? info.iSubItem : -1; -} - -void QSMainDlg::PrepareTable(bool bReset) -{ - m_grid.DeleteAllItems(); - - HDITEM hdi = {}; - hdi.mask = HDI_FORMAT; - - int old = tableColumns; - tableColumns = 0; - - LV_COLUMN lvc = {}; - lvc.mask = LVCF_TEXT | LVCF_WIDTH; - for (auto &it : g_plugin.m_columns) { - if (it->bEnabled) - AddColumn(tableColumns++, it); - - it->SetSpecialColumns(); - } - - if (bReset) - for (int i = old + tableColumns - 1; i >= tableColumns; i--) - m_grid.DeleteColumn(i); -} - -bool QSMainDlg::PrepareToFill() -{ - if (g_plugin.m_columns.getCount() == 0) - return false; - - for (auto &it : g_plugin.m_columns) - if (it->bEnabled) - it->bInit = true; - - hLastMeta = 0; - - m_rows.destroy(); - for (auto &hContact : Contacts()) - m_rows.insert(new CRowItem(hContact, this)); - - return m_rows.getCount() != 0; -} - -void QSMainDlg::ProcessLine(CRowItem *pRow, bool test) -{ - if (pRow->bDeleted) - return; - - if (test) - pRow->bPattern = CheckPattern(pRow); - - if (pRow->bPattern) { - if (!pRow->bActive) { - if ((g_plugin.m_flags & QSO_SHOWOFFLINE) || pRow->status != ID_STATUS_OFFLINE) { - // check for proto in combo - if (!szFilterProto || !mir_strcmp(szFilterProto, pRow->szProto)) { - pRow->bActive = true; - AddContactToList(pRow->hContact, pRow); - } - } - } - } - else if (pRow->bActive) { - pRow->bActive = false; - m_grid.DeleteItem(FindItem(pRow)); - } -} - -void QSMainDlg::SaveColumnOrder() -{ - int idx = 0, col = 0; - for (auto &it : g_plugin.m_columns) { - if (it->bEnabled) { - it->width = m_grid.GetColumnWidth(col++); - g_plugin.SaveColumn(idx, *it); - } - idx++; - } -} - -void QSMainDlg::ShowContactMsgDlg(MCONTACT hContact) -{ - if (hContact) { - Clist_ContactDoubleClicked(hContact); - if (g_plugin.m_flags & QSO_AUTOCLOSE) - Close(); - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// contact menu - -static INT_PTR ColChangeFunc(void *pThis, WPARAM hContact, LPARAM, LPARAM param) -{ - ((QSMainDlg *)pThis)->ChangeCellValue(hContact, (int)param); - return 0; -} - -void QSMainDlg::ChangeCellValue(MCONTACT hContact, int col) -{ - auto &pCol = g_plugin.m_columns[col]; - - auto *pRow = FindRow(hContact); - if (pRow == nullptr) - return; - - const char *szModule = pCol.module; - if (szModule == nullptr) - szModule = pRow->szProto; - - auto &pVal = pRow->pValues[col]; - CMStringW wszTitle(FORMAT, TranslateT("Editing of column %s"), pCol.title); - - ENTER_STRING es = {}; - es.szModuleName = MODULENAME; - es.caption = TranslateT("Enter new cell value"); - es.ptszInitVal = pVal.text; - if (!EnterString(&es)) - return; - - replaceStrW(pVal.text, es.ptszResult); - if (pCol.datatype != QSTS_STRING) - pVal.data = _wtoi(pVal.text); - - switch (pCol.datatype) { - case QSTS_BYTE: - db_set_b(hContact, szModule, pCol.setting, pVal.data); - break; - case QSTS_WORD: - db_set_w(hContact, szModule, pCol.setting, pVal.data); - break; - case QSTS_DWORD: - case QSTS_SIGNED: - case QSTS_HEXNUM: - db_set_dw(hContact, szModule, pCol.setting, pVal.data); - break; - - case QSTS_STRING: - db_set_ws(hContact, szModule, pCol.setting, pVal.text); - break; - } - - UpdateLVCell(FindItem(pRow), col, pVal.text); -} - -void QSMainDlg::ShowContactMenu(MCONTACT hContact, int col) -{ - if (hContact == 0) - return; - - HANDLE srvhandle = 0; - - bool bDoit = false; - if (col >= 0) { - if ((col = ListViewToColumn(col)) == -1) - return; - - auto &pCol = g_plugin.m_columns[col]; - if (pCol.setting_type == QST_SETTING && pCol.datatype != QSTS_TIMESTAMP) { - bDoit = true; - - srvhandle = CreateServiceFunctionObjParam("QS/Dummy", &ColChangeFunc, this, col); - - if (mnuhandle == nullptr) { - CMenuItem mi(&g_plugin); - SET_UID(mi, 0xD384A798, 0x5D4C, 0x48B4, 0xB3, 0xE2, 0x30, 0x04, 0x6E, 0xD6, 0xF4, 0x81); - mi.name.a = LPGEN("Change setting through QS"); - mi.pszService = "QS/Dummy"; - mnuhandle = Menu_AddContactMenuItem(&mi); - } - else Menu_ModifyItem(mnuhandle, 0, INVALID_HANDLE_VALUE, 0); - } - } - - POINT pt; - GetCursorPos(&pt); - HMENU hMenu = Menu_BuildContactMenu(hContact); - if (hMenu) { - int iCmd = ::TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, m_grid.GetHwnd(), 0); - if (iCmd) { - if (Clist_MenuProcessCommand(iCmd, MPCF_CONTACTMENU, hContact)) { - if (g_plugin.m_flags & QSO_AUTOCLOSE) - CloseSrWindow(); - } - } - - ::DestroyMenu(hMenu); - } - - if (srvhandle) - DestroyServiceFunction(srvhandle); - if (bDoit) - Menu_ShowItem(mnuhandle, false); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// muptiple selection popup menu - -static HMENU MakeContainerMenu() -{ - HMENU hMenu = CreatePopupMenu(); - - for (int i = 0;; i++) { - char setting[10]; - _itoa_s(i, setting, 10); - ptrW wszName(db_get_wsa(0, "TAB_ContainersW", setting)); - if (wszName != nullptr) - AppendMenuW(hMenu, MF_STRING, 300 + i, wszName); - else - break; - } - - return hMenu; -} - -void QSMainDlg::ShowMultiPopup(int cnt) -{ - HMENU hMenu = CreatePopupMenu(); - AppendMenuW(hMenu, MF_DISABLED + MF_STRING, 0, CMStringW(FORMAT, TranslateT("Selected %d contacts"), cnt)); - AppendMenuW(hMenu, MF_SEPARATOR, 0, 0); - AppendMenuW(hMenu, MF_STRING, 101, TranslateT("&Delete")); - AppendMenuW(hMenu, MF_STRING, 102, TranslateT("&Copy")); - AppendMenuW(hMenu, MF_STRING, 103, TranslateT("C&onvert to Meta")); - - HMENU cntmenu = MakeContainerMenu(); - AppendMenuW(hMenu, MF_POPUP, UINT_PTR(cntmenu), TranslateT("Attach to &Tab container")); - - if (HMENU grpmenu = Clist_GroupBuildMenu(400)) - AppendMenuW(hMenu, MF_POPUP, UINT_PTR(grpmenu), TranslateT("&Move to Group")); - - POINT pt; - GetCursorPos(&pt); - - int iRes = TrackPopupMenu(hMenu, TPM_RETURNCMD+TPM_NONOTIFY, pt.x, pt.y, 0, m_hwnd, 0); - switch (iRes) { - case 101: - DeleteByList(); - break; - - case 102: - CopyMultiLines(); - break; - - case 103: - ConvertToMeta(); - break; - } - - if (iRes >= 300 && iRes <= 399) { - wchar_t buf[100]; - if (iRes == 300) // default container, just delete setting - buf[0] = 0; - else - GetMenuStringW(cntmenu, iRes, buf, _countof(buf), MF_BYCOMMAND); - - MoveToContainer(buf); - } - else if (iRes >= 400 && iRes <= 499) - MoveToGroup(Clist_GroupGetName(iRes - 400)); -} - -void QSMainDlg::ConvertToMeta() -{ - MCONTACT hMeta = 0; - - int nCount = m_grid.GetItemCount(); - for (int i = 0; i < nCount; i++) { - if (!m_grid.GetItemState(i, LVIS_SELECTED)) - continue; - - auto *pRow = GetRow(i); - if (MCONTACT tmp = db_mc_getMeta(pRow->hContact)) { - if (hMeta == 0) - hMeta = tmp; - else if (hMeta != tmp) { - MessageBoxW(m_hwnd, TranslateT("Some of selected contacts in different metacontacts already"), L"Quick Search", MB_ICONERROR); - return; - } - } - } - - if (hMeta != 0) - if (IDYES != MessageBoxW(0, TranslateT("One or more contacts already belong to the same metacontact. Try to convert anyway?"), L"Quick Search", MB_YESNO + MB_ICONWARNING)) - return; - - for (int i = 0; i < nCount; i++) { - if (!m_grid.GetItemState(i, LVIS_SELECTED)) - continue; - - auto *pRow = GetRow(i); - if (hMeta) - db_mc_addToMeta(pRow->hContact, hMeta); - else - db_mc_convertToMeta(pRow->hContact); - } -} - -void QSMainDlg::MoveToContainer(const wchar_t *pwszName) -{ - int grcol = -1; - for (auto &it : g_plugin.m_columns) { - if (it->isContainer) { - if (it->bEnabled) - grcol = g_plugin.m_columns.indexOf(&it); - else - it->bInit = false; - } - } - - int nCount = m_grid.GetItemCount(); - for (int i = 0; i < nCount; i++) { - if (!m_grid.GetItemState(i, LVIS_SELECTED)) - continue; - - auto *pRow = GetRow(i); - if (*pwszName == 0) - db_unset(pRow->hContact, "Tab_SRMsg", "containerW"); - else - db_set_ws(pRow->hContact, "Tab_SRMsg", "containerW", pwszName); - - if (grcol != -1) { - auto &pVal = pRow->pValues[grcol]; - replaceStrW(pVal.text, (*pwszName) ? pwszName : nullptr); - UpdateLVCell(i, grcol, pwszName); - } - } -} - -void QSMainDlg::MoveToGroup(const wchar_t *pwszName) -{ - int grcol = -1; - for (auto &it : g_plugin.m_columns) { - if (it->isGroup) { - if (it->bEnabled) - grcol = g_plugin.m_columns.indexOf(&it); - else - it->bInit = false; - } - } - - int nCount = m_grid.GetItemCount(); - for (int i = 0; i < nCount; i++) { - if (!m_grid.GetItemState(i, LVIS_SELECTED)) - continue; - - auto *pRow = GetRow(i); - Clist_SetGroup(pRow->hContact, pwszName); - - if (grcol != -1) { - auto &pVal = pRow->pValues[grcol]; - replaceStrW(pVal.text, pwszName); - UpdateLVCell(i, grcol, pwszName); - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// grid sorting - -static int CALLBACK CompareItem(LPARAM l1, LPARAM l2, LPARAM type) -{ - bool typ1, typ2; - UINT_PTR i1, i2; - int result = 0; - CRowItem *r1 = (CRowItem *)l1, *r2 = (CRowItem *)l2; - - if (type == StatusSort) { - i1 = r1->status, i2 = r2->status; - if (i1 == ID_STATUS_OFFLINE) i1 += 64; - if (i2 == ID_STATUS_OFFLINE) i2 += 64; - typ1 = typ2 = false; - } - else { - auto &res1 = r1->pValues[type], &res2 = r2->pValues[type]; - i1 = res1.data, i2 = res2.data; - typ1 = i1 == -1; typ2 = i1 == -1; - - if (typ1 && typ2) { // two strings - if (res1.text == 0 && res2.text == 0) - result = 0; - else if (res2.text == 0) - result = 1; - else if (res1.text == 0) - result = -1; - else - result = lstrcmpiW(res1.text, res2.text); - } - else if (typ1 || typ2) // string & num - result = (typ1) ? 1 : -1; - } - - if (!typ1 && !typ2) { // not strings - if (i1 > i2) - result = 1; - else if (i1 < i2) - result = -1; - else - result = 0; - } - - if (g_plugin.m_flags & QSO_SORTASC) - result = -result; - return result; -} - -void QSMainDlg::Sort() -{ - if (g_plugin.m_sortOrder >= tableColumns) - g_plugin.m_sortOrder = StatusSort; - m_grid.SortItems(&CompareItem, ListViewToColumn(g_plugin.m_sortOrder)); - - if (g_plugin.m_sortOrder != StatusSort && (g_plugin.m_flags & QSO_SORTBYSTATUS)) - m_grid.SortItems(&CompareItem, StatusSort); -} - -void QSMainDlg::UpdateLVCell(int item, int column, const wchar_t *pwszText) -{ - auto &pCol = g_plugin.m_columns[column]; - auto *pRow = GetRow(item); - - if (pwszText == nullptr) { - auto &pVal = pRow->pValues[column]; - replaceStrW(pVal.text, 0); - pVal.LoadOneItem(pRow->hContact, pCol, this); - pwszText = pVal.text; - } - - m_grid.SetItemText(item, ColumnToListView(column), pwszText); - - if (pCol.bFilter) - ProcessLine(pRow, true); - if (g_plugin.m_sortOrder == column) - Sort(); -} - -void QSMainDlg::UpdateSB() -{ - m_sbdata.destroy(); - - for (auto &it : m_rows) { - if (it->szProto == nullptr) - continue; - - CStatusBarItem tmp(it->szProto, it->flags); - auto *pItem = m_sbdata.find(&tmp); - if (pItem == nullptr) - m_sbdata.insert(pItem = new CStatusBarItem(it->szProto, it->flags)); - - pItem->total++; - - if (it->bActive) - pItem->found++; - - if (it->status != ID_STATUS_OFFLINE) { - pItem->online++; - if (it->bActive) - pItem->liston++; - } - } - - DrawSB(); -} +/* +Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org) + +This program is free software; you can redistribute it &/| +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY | FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "stdafx.h" + +///////////////////////////////////////////////////////////////////////////////////////// +// patterns + +bool QSMainDlg::CheckPattern(CRowItem *pRow) +{ + if (m_patterns.getCount() == 0) + return true; + + for (auto &p : m_patterns) + p->res = 0; + + int i = 0; + for (auto &it : g_plugin.m_columns) { + if (it->bEnabled && it->bFilter && pRow->pValues[i].text != nullptr) { + CMStringW buf(pRow->pValues[i].text); + buf.MakeLower(); + + for (auto &p : m_patterns) + if (!p->res && buf.Find(p->str) != -1) + p->res = true; + } + i++; + } + + bool result = true; + for (auto &p : m_patterns) + result = result && p->res; + return result; +} + +void QSMainDlg::MakePattern(const wchar_t *pwszPattern) +{ + m_patterns.destroy(); + if (mir_wstrlen(pwszPattern) == 0) + return; + + // m_wszPatternBuf works as a storage for patterns, we store pointers to it in m_patterns + m_wszPatternBuf = mir_wstrdup(pwszPattern); + CharLowerW(m_wszPatternBuf); + + for (wchar_t *p = m_wszPatternBuf; *p; ) { + auto *pWord = wcspbrk(p, L" \""); + if (pWord == nullptr) { + m_patterns.insert(new Pattern(p)); + return; + } + + bool isSpace = pWord[0] == ' '; + + // there's some valuable info between p and pWord + if (pWord != p) { + *pWord = 0; + m_patterns.insert(new Pattern(p)); + } + + if (isSpace) { + p = ltrimpw(pWord + 1); // skip all spaces + } + else { + auto *pEnd = wcschr(++pWord, '\"'); + + // treat the rest of line as one pattern + if (pEnd == nullptr) { + m_patterns.insert(new Pattern(pWord)); + return; + } + + *pEnd = 0; + m_patterns.insert(new Pattern(pWord)); + p = ltrimpw(pEnd + 1); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void QSMainDlg::AddColumn(int idx, ColumnItem *pCol) +{ + LV_COLUMN lvcol = {}; + lvcol.mask = LVCF_TEXT | LVCF_WIDTH; + lvcol.pszText = TranslateW(pCol->title); + lvcol.cx = pCol->width; + m_grid.InsertColumn(idx, &lvcol); + + HDITEM hdi; + hdi.mask = HDI_FORMAT; + if (pCol->bFilter) + hdi.fmt = HDF_LEFT | HDF_STRING | HDF_CHECKBOX | HDF_CHECKED; + else + hdi.fmt = HDF_LEFT | HDF_STRING | HDF_CHECKBOX; + SendMessage(m_grid.GetHeader(), HDM_SETITEM, idx, LPARAM(&hdi)); +} + +void QSMainDlg::AddContactToList(MCONTACT hContact, CRowItem *pRow) +{ + LV_ITEMW li = {}; + li.mask = LVIF_IMAGE | LVIF_PARAM; + li.iItem = 100000; + li.iImage = Clist_GetContactIcon(hContact); + li.lParam = LPARAM(pRow); + + li.iItem = m_grid.InsertItem(&li); + li.iImage = 0; + li.iSubItem = 0; + + for (int i = 0; i < g_plugin.m_columns.getCount(); i++) { + auto &col = g_plugin.m_columns[i]; + if (!col.bEnabled) + continue; + + // Client icons preprocess + li.pszText = pRow->pValues[i].text; + li.mask = LVIF_TEXT; + if ((col.isClient && (g_plugin.m_flags & QSO_CLIENTICONS) && li.pszText != 0) || col.isXstatus || col.isGender) + li.mask |= LVIF_IMAGE; + m_grid.SetItem(&li); + li.iSubItem++; + } +} + +void QSMainDlg::AdvancedFilter() +{ + m_grid.SetDraw(false); + + for (auto &it : m_rows) { + bool bShow = (szFilterProto == nullptr) || !mir_strcmp(szFilterProto, it->szProto); + if (bShow && !bShowOffline && it->status == ID_STATUS_OFFLINE) + bShow = false; + + if (it->bPattern) { + if (bShow) { + if (!it->bActive) + ProcessLine(it, false); + } + else { + it->bActive = false; + m_grid.DeleteItem(FindItem(it)); + } + } + } + + m_grid.SetDraw(true); + InvalidateRect(m_grid.GetHwnd(), 0, false); + + Sort(); + UpdateSB(); +} + +void QSMainDlg::ChangeStatusPicture(CRowItem *pRow, MCONTACT, LPARAM lParam) +{ + int idx = FindItem(pRow); + if (idx == -1) + return; + + LV_ITEMW li = {}; + li.iItem = idx; + li.mask = LVIF_IMAGE; + li.iImage = lParam; //CallService(MS_CLIST_GETCONTACTICON,hContact,0); + m_grid.SetItem(&li); +} + +void QSMainDlg::CopyMultiLines() +{ + CMStringW buf; + + int i = 0; + for (auto &it : g_plugin.m_columns) { + if (it->bEnabled) { + it->width = m_grid.GetColumnWidth(i); + if (it->width >= 10) + buf.AppendFormat(L"%s\t", it->title); + } + i++; + } + buf.Append(L"\r\n"); + + int nRows = m_grid.GetItemCount(); + int nSelected = m_grid.GetSelectedCount(); + + for (int j = 0; j < nRows; j++) { + if (nSelected > 1 && !m_grid.GetItemState(j, LVIS_SELECTED)) + continue; + + auto *pRow = GetRow(j); + + i = 0; + for (auto &it : g_plugin.m_columns) { + if (it->bEnabled && it->width >= 10) + buf.AppendFormat(L"%s\t", pRow->pValues[i].getText()); + i++; + } + buf.Append(L"\r\n"); + } + + Utils_ClipboardCopy(buf); +} + +void QSMainDlg::DeleteByList() +{ + if (IDOK != MessageBoxW(0, TranslateT("Do you really want to delete selected contacts?"), TranslateT("Warning"), MB_OKCANCEL + MB_ICONWARNING)) + return; + + m_grid.SetDraw(false); + + for (int i = m_grid.GetItemCount() - 1; i >= 0; i--) + if (m_grid.GetItemState(i, LVIS_SELECTED)) + db_delete_contact(GetRow(i)->hContact); + + m_grid.SetDraw(true); +} + +void QSMainDlg::DeleteOneContact(MCONTACT hContact) +{ + if (ServiceExists(MS_CLIST_DELETECONTACT)) + CallService(MS_CLIST_DELETECONTACT, hContact, 0); + else + db_delete_contact(hContact); +} + +wchar_t* QSMainDlg::DoMeta(MCONTACT hContact) +{ + for (auto &it : m_rows) { + if (it->hContact != hContact) + continue; + + if (it->bIsMeta) { + if (it->wparam == 0) + it->wparam = ++hLastMeta; + } + else if (it->bIsSub) + it->lparam = FindMeta(db_mc_getMeta(hContact), it->wparam); + + if (it->wparam > 0) { + CMStringW tmp(FORMAT, L"[%d]", int(it->wparam)); + if (it->lparam > 0) + tmp.AppendFormat(L" %d", int(it->lparam)); + return tmp.Detach(); + } + break; + } + + return nullptr; +} + +void QSMainDlg::DrawSB() +{ + CStatusBarItem global(0, 0); + for (auto &it : m_sbdata) { + global.found += it->found; + global.liston += it->liston; + global.online += it->online; + global.total += it->total; + } + + CMStringW buf(FORMAT, TranslateT("%i users found (%i) Online: %i"), global.found, m_rows.getCount(), global.online); + + RECT rc; + HDC hdc = GetDC(hwndStatusBar); + DrawTextW(hdc, buf, buf.GetLength(), &rc, DT_CALCRECT); + ReleaseDC(hwndStatusBar, hdc); + + int all = rc.right - rc.left, i = 1; + + mir_ptr parts((int*)mir_alloc(sizeof(int) * (m_sbdata.getCount()+2))); + parts[0] = all; + for (auto &it : m_sbdata) { + UNREFERENCED_PARAMETER(it); + all += 55; + parts[i++] = all; + } + parts[i] = -1; + SendMessageW(hwndStatusBar, SB_SETPARTS, m_sbdata.getCount() + 2, LPARAM(parts.get())); + SendMessageW(hwndStatusBar, SB_SETTEXTW, 0, LPARAM(buf.c_str())); + + i = 1; + for (auto &it : m_sbdata) { + HICON hIcon; + wchar_t c, *pc; + if (it->bAccDel) { + c = '!'; + pc = TranslateT("deleted"); + hIcon = Skin_LoadProtoIcon(it->szProto, ID_STATUS_OFFLINE); + } + else if (it->bAccOff) { + c = '?'; + pc = TranslateT("disabled"); + hIcon = Skin_LoadProtoIcon(it->szProto, ID_STATUS_OFFLINE); + } + else { + c = ' '; + pc = TranslateT("active"); + hIcon = Skin_LoadProtoIcon(it->szProto, ID_STATUS_ONLINE); + } + + SendMessageW(hwndStatusBar, SB_SETICON, i, (LPARAM)hIcon); + + buf.Format(L"%c %d", c, it->found); + SendMessageW(hwndStatusBar, SB_SETTEXTW, i, LPARAM(buf.c_str())); + + auto *pa = Proto_GetAccount(it->szProto); + buf.Format(L"%s (%s): %d (%d); %s %d (%d))", pa->tszAccountName, pc, it->found, it->total, TranslateT("Online"), it->liston, it->online); + SendMessageW(hwndStatusBar, SB_SETTIPTEXTW, i, LPARAM(buf.c_str())); + i++; + } +} + +void QSMainDlg::FillGrid() +{ + m_grid.SetDraw(false); + + for (auto &it: m_rows) + ProcessLine(it); + + m_grid.SetDraw(true); + InvalidateRect(m_grid.GetHwnd(), 0, FALSE); + + Sort(); + UpdateSB(); + AdvancedFilter(); + + m_grid.SetCurSel(0); +} + +void QSMainDlg::FillProtoCombo() +{ + cmbProto.ResetContent(); + cmbProto.AddString(TranslateT("All")); + + for (auto &it : Accounts()) + cmbProto.AddString(it->tszAccountName, (LPARAM)it); + + cmbProto.SetCurSel(0); +} + +int QSMainDlg::FindItem(CRowItem *pRow) +{ + if (pRow == nullptr) + return -1; + + LV_FINDINFO fi = {}; + fi.flags = LVFI_PARAM; + fi.lParam = LPARAM(pRow); + return m_grid.FindItem(-1, &fi); +} + +int QSMainDlg::FindMeta(MCONTACT hMeta, WPARAM &metaNum) +{ + for (auto &it : m_rows) { + if (it->hContact != hMeta) + continue; + + // new meta + if (it->wparam == 0) { + it->wparam = ++hLastMeta; + it->lparam = 0; + } + metaNum = it->wparam; + it->lparam++; + return it->lparam; + } + + return 0; +} + +CRowItem* QSMainDlg::FindRow(MCONTACT hContact) +{ + for (auto &it : m_rows) + if (it->hContact == hContact) + return it; + + return nullptr; +} + +MCONTACT QSMainDlg::GetFocusedContact() +{ + int idx = m_grid.GetSelectionMark(); + if (idx == -1) + return -1; + + INT_PTR data = m_grid.GetItemData(idx); + return (data == -1) ? -1 : ((CRowItem *)data)->hContact; +} + +int QSMainDlg::GetLVSubItem(int x, int y) +{ + LV_HITTESTINFO info = {}; + info.pt.x = x; + info.pt.y = y; + ScreenToClient(m_grid.GetHwnd(), &info.pt); + if (m_grid.SubItemHitTest(&info) == -1) + return -1; + + return (info.flags & LVHT_ONITEM) ? info.iSubItem : -1; +} + +void QSMainDlg::PrepareTable(bool bReset) +{ + m_grid.DeleteAllItems(); + + HDITEM hdi = {}; + hdi.mask = HDI_FORMAT; + + int old = tableColumns; + tableColumns = 0; + + LV_COLUMN lvc = {}; + lvc.mask = LVCF_TEXT | LVCF_WIDTH; + for (auto &it : g_plugin.m_columns) { + if (it->bEnabled) + AddColumn(tableColumns++, it); + + it->SetSpecialColumns(); + } + + if (bReset) + for (int i = old + tableColumns - 1; i >= tableColumns; i--) + m_grid.DeleteColumn(i); +} + +bool QSMainDlg::PrepareToFill() +{ + if (g_plugin.m_columns.getCount() == 0) + return false; + + for (auto &it : g_plugin.m_columns) + if (it->bEnabled) + it->bInit = true; + + hLastMeta = 0; + + m_rows.destroy(); + for (auto &hContact : Contacts()) + m_rows.insert(new CRowItem(hContact, this)); + + return m_rows.getCount() != 0; +} + +void QSMainDlg::ProcessLine(CRowItem *pRow, bool test) +{ + if (pRow->bDeleted) + return; + + if (test) + pRow->bPattern = CheckPattern(pRow); + + if (pRow->bPattern) { + if (!pRow->bActive) { + if ((g_plugin.m_flags & QSO_SHOWOFFLINE) || pRow->status != ID_STATUS_OFFLINE) { + // check for proto in combo + if (!szFilterProto || !mir_strcmp(szFilterProto, pRow->szProto)) { + pRow->bActive = true; + AddContactToList(pRow->hContact, pRow); + } + } + } + } + else if (pRow->bActive) { + pRow->bActive = false; + m_grid.DeleteItem(FindItem(pRow)); + } +} + +void QSMainDlg::SaveColumnOrder() +{ + int idx = 0, col = 0; + for (auto &it : g_plugin.m_columns) { + if (it->bEnabled) { + it->width = m_grid.GetColumnWidth(col++); + g_plugin.SaveColumn(idx, *it); + } + idx++; + } +} + +void QSMainDlg::ShowContactMsgDlg(MCONTACT hContact) +{ + if (hContact) { + Clist_ContactDoubleClicked(hContact); + if (g_plugin.m_flags & QSO_AUTOCLOSE) + Close(); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// contact menu + +static INT_PTR ColChangeFunc(void *pThis, WPARAM hContact, LPARAM, LPARAM param) +{ + ((QSMainDlg *)pThis)->ChangeCellValue(hContact, (int)param); + return 0; +} + +void QSMainDlg::ChangeCellValue(MCONTACT hContact, int col) +{ + auto &pCol = g_plugin.m_columns[col]; + + auto *pRow = FindRow(hContact); + if (pRow == nullptr) + return; + + const char *szModule = pCol.module; + if (szModule == nullptr) + szModule = pRow->szProto; + + auto &pVal = pRow->pValues[col]; + CMStringW wszTitle(FORMAT, TranslateT("Editing of column %s"), pCol.title); + + ENTER_STRING es = {}; + es.szModuleName = MODULENAME; + es.caption = TranslateT("Enter new cell value"); + es.ptszInitVal = pVal.text; + if (!EnterString(&es)) + return; + + replaceStrW(pVal.text, es.ptszResult); + if (pCol.datatype != QSTS_STRING) + pVal.data = _wtoi(pVal.text); + + switch (pCol.datatype) { + case QSTS_BYTE: + db_set_b(hContact, szModule, pCol.setting, pVal.data); + break; + case QSTS_WORD: + db_set_w(hContact, szModule, pCol.setting, pVal.data); + break; + case QSTS_DWORD: + case QSTS_SIGNED: + case QSTS_HEXNUM: + db_set_dw(hContact, szModule, pCol.setting, pVal.data); + break; + + case QSTS_STRING: + db_set_ws(hContact, szModule, pCol.setting, pVal.text); + break; + } + + UpdateLVCell(FindItem(pRow), col, pVal.text); +} + +void QSMainDlg::ShowContactMenu(MCONTACT hContact, int col) +{ + if (hContact == 0) + return; + + HANDLE srvhandle = 0; + + bool bDoit = false; + if (col >= 0) { + if ((col = ListViewToColumn(col)) == -1) + return; + + auto &pCol = g_plugin.m_columns[col]; + if (pCol.setting_type == QST_SETTING && pCol.datatype != QSTS_TIMESTAMP) { + bDoit = true; + + srvhandle = CreateServiceFunctionObjParam("QS/Dummy", &ColChangeFunc, this, col); + + if (mnuhandle == nullptr) { + CMenuItem mi(&g_plugin); + SET_UID(mi, 0xD384A798, 0x5D4C, 0x48B4, 0xB3, 0xE2, 0x30, 0x04, 0x6E, 0xD6, 0xF4, 0x81); + mi.name.a = LPGEN("Change setting through QS"); + mi.pszService = "QS/Dummy"; + mnuhandle = Menu_AddContactMenuItem(&mi); + } + else Menu_ModifyItem(mnuhandle, 0, INVALID_HANDLE_VALUE, 0); + } + } + + POINT pt; + GetCursorPos(&pt); + HMENU hMenu = Menu_BuildContactMenu(hContact); + if (hMenu) { + int iCmd = ::TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, m_grid.GetHwnd(), 0); + if (iCmd) { + if (Clist_MenuProcessCommand(iCmd, MPCF_CONTACTMENU, hContact)) { + if (g_plugin.m_flags & QSO_AUTOCLOSE) + CloseSrWindow(); + } + } + + ::DestroyMenu(hMenu); + } + + if (srvhandle) + DestroyServiceFunction(srvhandle); + if (bDoit) + Menu_ShowItem(mnuhandle, false); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// muptiple selection popup menu + +static HMENU MakeContainerMenu() +{ + HMENU hMenu = CreatePopupMenu(); + + for (int i = 0;; i++) { + char setting[10]; + _itoa_s(i, setting, 10); + ptrW wszName(db_get_wsa(0, "TAB_ContainersW", setting)); + if (wszName != nullptr) + AppendMenuW(hMenu, MF_STRING, 300 + i, wszName); + else + break; + } + + return hMenu; +} + +void QSMainDlg::ShowMultiPopup(int cnt) +{ + HMENU hMenu = CreatePopupMenu(); + AppendMenuW(hMenu, MF_DISABLED + MF_STRING, 0, CMStringW(FORMAT, TranslateT("Selected %d contacts"), cnt)); + AppendMenuW(hMenu, MF_SEPARATOR, 0, 0); + AppendMenuW(hMenu, MF_STRING, 101, TranslateT("&Delete")); + AppendMenuW(hMenu, MF_STRING, 102, TranslateT("&Copy")); + AppendMenuW(hMenu, MF_STRING, 103, TranslateT("C&onvert to Meta")); + + HMENU cntmenu = MakeContainerMenu(); + AppendMenuW(hMenu, MF_POPUP, UINT_PTR(cntmenu), TranslateT("Attach to &Tab container")); + + if (HMENU grpmenu = Clist_GroupBuildMenu(400)) + AppendMenuW(hMenu, MF_POPUP, UINT_PTR(grpmenu), TranslateT("&Move to Group")); + + POINT pt; + GetCursorPos(&pt); + + int iRes = TrackPopupMenu(hMenu, TPM_RETURNCMD+TPM_NONOTIFY, pt.x, pt.y, 0, m_hwnd, 0); + switch (iRes) { + case 101: + DeleteByList(); + break; + + case 102: + CopyMultiLines(); + break; + + case 103: + ConvertToMeta(); + break; + } + + if (iRes >= 300 && iRes <= 399) { + wchar_t buf[100]; + if (iRes == 300) // default container, just delete setting + buf[0] = 0; + else + GetMenuStringW(cntmenu, iRes, buf, _countof(buf), MF_BYCOMMAND); + + MoveToContainer(buf); + } + else if (iRes >= 400 && iRes <= 499) + MoveToGroup(Clist_GroupGetName(iRes - 400)); +} + +void QSMainDlg::ConvertToMeta() +{ + MCONTACT hMeta = 0; + + int nCount = m_grid.GetItemCount(); + for (int i = 0; i < nCount; i++) { + if (!m_grid.GetItemState(i, LVIS_SELECTED)) + continue; + + auto *pRow = GetRow(i); + if (MCONTACT tmp = db_mc_getMeta(pRow->hContact)) { + if (hMeta == 0) + hMeta = tmp; + else if (hMeta != tmp) { + MessageBoxW(m_hwnd, TranslateT("Some of selected contacts in different metacontacts already"), L"Quick Search", MB_ICONERROR); + return; + } + } + } + + if (hMeta != 0) + if (IDYES != MessageBoxW(0, TranslateT("One or more contacts already belong to the same metacontact. Try to convert anyway?"), L"Quick Search", MB_YESNO + MB_ICONWARNING)) + return; + + for (int i = 0; i < nCount; i++) { + if (!m_grid.GetItemState(i, LVIS_SELECTED)) + continue; + + auto *pRow = GetRow(i); + if (hMeta) + db_mc_addToMeta(pRow->hContact, hMeta); + else + db_mc_convertToMeta(pRow->hContact); + } +} + +void QSMainDlg::MoveToContainer(const wchar_t *pwszName) +{ + int grcol = -1; + for (auto &it : g_plugin.m_columns) { + if (it->isContainer) { + if (it->bEnabled) + grcol = g_plugin.m_columns.indexOf(&it); + else + it->bInit = false; + } + } + + int nCount = m_grid.GetItemCount(); + for (int i = 0; i < nCount; i++) { + if (!m_grid.GetItemState(i, LVIS_SELECTED)) + continue; + + auto *pRow = GetRow(i); + if (*pwszName == 0) + db_unset(pRow->hContact, "Tab_SRMsg", "containerW"); + else + db_set_ws(pRow->hContact, "Tab_SRMsg", "containerW", pwszName); + + if (grcol != -1) { + auto &pVal = pRow->pValues[grcol]; + replaceStrW(pVal.text, (*pwszName) ? pwszName : nullptr); + UpdateLVCell(i, grcol, pwszName); + } + } +} + +void QSMainDlg::MoveToGroup(const wchar_t *pwszName) +{ + int grcol = -1; + for (auto &it : g_plugin.m_columns) { + if (it->isGroup) { + if (it->bEnabled) + grcol = g_plugin.m_columns.indexOf(&it); + else + it->bInit = false; + } + } + + int nCount = m_grid.GetItemCount(); + for (int i = 0; i < nCount; i++) { + if (!m_grid.GetItemState(i, LVIS_SELECTED)) + continue; + + auto *pRow = GetRow(i); + Clist_SetGroup(pRow->hContact, pwszName); + + if (grcol != -1) { + auto &pVal = pRow->pValues[grcol]; + replaceStrW(pVal.text, pwszName); + UpdateLVCell(i, grcol, pwszName); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// grid sorting + +static int CALLBACK CompareItem(LPARAM l1, LPARAM l2, LPARAM type) +{ + bool typ1, typ2; + UINT_PTR i1, i2; + int result = 0; + CRowItem *r1 = (CRowItem *)l1, *r2 = (CRowItem *)l2; + + if (type == StatusSort) { + i1 = r1->status, i2 = r2->status; + if (i1 == ID_STATUS_OFFLINE) i1 += 64; + if (i2 == ID_STATUS_OFFLINE) i2 += 64; + typ1 = typ2 = false; + } + else { + auto &res1 = r1->pValues[type], &res2 = r2->pValues[type]; + i1 = res1.data, i2 = res2.data; + typ1 = i1 == -1; typ2 = i1 == -1; + + if (typ1 && typ2) { // two strings + if (res1.text == 0 && res2.text == 0) + result = 0; + else if (res2.text == 0) + result = 1; + else if (res1.text == 0) + result = -1; + else + result = lstrcmpiW(res1.text, res2.text); + } + else if (typ1 || typ2) // string & num + result = (typ1) ? 1 : -1; + } + + if (!typ1 && !typ2) { // not strings + if (i1 > i2) + result = 1; + else if (i1 < i2) + result = -1; + else + result = 0; + } + + if (g_plugin.m_flags & QSO_SORTASC) + result = -result; + return result; +} + +void QSMainDlg::Sort() +{ + if (g_plugin.m_sortOrder >= tableColumns) + g_plugin.m_sortOrder = StatusSort; + m_grid.SortItems(&CompareItem, ListViewToColumn(g_plugin.m_sortOrder)); + + if (g_plugin.m_sortOrder != StatusSort && (g_plugin.m_flags & QSO_SORTBYSTATUS)) + m_grid.SortItems(&CompareItem, StatusSort); +} + +void QSMainDlg::UpdateLVCell(int item, int column, const wchar_t *pwszText) +{ + auto &pCol = g_plugin.m_columns[column]; + auto *pRow = GetRow(item); + + if (pwszText == nullptr) { + auto &pVal = pRow->pValues[column]; + replaceStrW(pVal.text, 0); + pVal.LoadOneItem(pRow->hContact, pCol, this); + pwszText = pVal.text; + } + + m_grid.SetItemText(item, ColumnToListView(column), pwszText); + + if (pCol.bFilter) + ProcessLine(pRow, true); + if (g_plugin.m_sortOrder == column) + Sort(); +} + +void QSMainDlg::UpdateSB() +{ + m_sbdata.destroy(); + + for (auto &it : m_rows) { + if (it->szProto == nullptr) + continue; + + CStatusBarItem tmp(it->szProto, it->flags); + auto *pItem = m_sbdata.find(&tmp); + if (pItem == nullptr) + m_sbdata.insert(pItem = new CStatusBarItem(it->szProto, it->flags)); + + pItem->total++; + + if (it->bActive) + pItem->found++; + + if (it->status != ID_STATUS_OFFLINE) { + pItem->online++; + if (it->bActive) + pItem->liston++; + } + } + + DrawSB(); +} diff --git a/plugins/QuickSearch/src/window_row.cpp b/plugins/QuickSearch/src/window_row.cpp index d05ddb0c43..991dcafd68 100644 --- a/plugins/QuickSearch/src/window_row.cpp +++ b/plugins/QuickSearch/src/window_row.cpp @@ -1,224 +1,224 @@ -/* -Copyright (C) 2012-22 Miranda NG team (https://miranda-ng.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation version 2 -of the License. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -*/ - -#include "stdafx.h" - -CRowItem::CRowItem(MCONTACT _1, QSMainDlg *pDlg) : - hContact(_1) -{ - auto *pa = Proto_GetContactAccount(hContact); - if (pa != nullptr) { - szProto = pa->szModuleName; - if (!pa->IsEnabled()) - bAccOff = true; - - if (db_mc_isMeta(hContact)) - bIsMeta = true; - else if (db_mc_isSub(hContact)) - bIsSub = true; - } - else { - szProto = nullptr; - bAccDel = true; - } - - if (bAccDel || bAccOff) - status = ID_STATUS_OFFLINE; - else - status = Contact::GetStatus(hContact); - - if (int nCount = g_plugin.m_columns.getCount()) { - pValues = new Val[nCount]; - for (int i = 0; i < nCount; i++) - pValues[i].LoadOneItem(hContact, g_plugin.m_columns[i], pDlg); - } - else pValues = nullptr; -} - -CRowItem::~CRowItem() -{ - delete[] pValues; -} - -void CRowItem::GetCellColor(int idx, COLORREF &clrBack, COLORREF &clrText) -{ - if (g_plugin.m_flags & QSO_COLORIZE) { - if (bAccDel) { - clrBack = g_plugin.m_colors[bkg_del]; - clrText = g_plugin.m_colors[fgr_del]; - return; - } - if (bAccOff) { - clrBack = g_plugin.m_colors[bkg_dis]; - clrText = g_plugin.m_colors[fgr_dis]; - return; - } - if (bIsMeta) { - clrBack = g_plugin.m_colors[bkg_meta]; - clrText = g_plugin.m_colors[fgr_meta]; - return; - } - if (bIsSub) { - clrBack = g_plugin.m_colors[bkg_sub]; - clrText = g_plugin.m_colors[fgr_sub]; - return; - } - if (bInList) { - clrBack = g_plugin.m_colors[bkg_hid]; - clrText = g_plugin.m_colors[fgr_hid]; - return; - } - } - - if ((g_plugin.m_flags & QSO_DRAWGRID) == 0 && idx % 2 == 1) { - clrBack = g_plugin.m_colors[bkg_odd]; - clrText = g_plugin.m_colors[fgr_odd]; - } - else { - clrBack = g_plugin.m_colors[bkg_norm]; - clrText = g_plugin.m_colors[fgr_norm]; - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static wchar_t* int2strw(uint32_t num) -{ - wchar_t buf[64]; - _itow_s(num, buf, 10); - return mir_wstrdup(buf); -} - -static wchar_t* hex2strw(uint32_t num) -{ - wchar_t buf[64]; - _itow_s(num, buf, 16); - return mir_wstrdup(buf); -} - -void CRowItem::Val::LoadOneItem(MCONTACT hContact, const ColumnItem &pCol, QSMainDlg *pDlg) -{ - data = UINT_PTR(-1); - replaceStrW(text, nullptr); - - switch (pCol.setting_type) { - case QST_SCRIPT: - { - VARSW vars(pCol.script); - if (g_bVarsInstalled) - text = variables_parse(vars, 0, hContact); - else - text = vars.detach(); - } - break; - - case QST_SERVICE: - // !!!!!!!!!!!!!!!!!!! not implemented - break; - - case QST_CONTACTINFO: - text = Contact::GetInfo(pCol.cnftype, hContact); - if (text) - data = _wtoi(text); - break; - - case QST_OTHER: - switch (pCol.other) { - case QSTO_ACCOUNT: - if (auto *pa = Proto_GetContactAccount(hContact)) - text = mir_wstrdup(pa->tszAccountName); - break; - - case QSTO_LASTSEEN: - data = BuildLastSeenTimeInt(hContact, "SeenModule"); - text = BuildLastSeenTime(data); - break; - - case QSTO_DISPLAYNAME: - text = mir_wstrdup(Clist_GetContactDisplayName(hContact, 0)); - break; - - case QSTO_LASTEVENT: - if (MEVENT hDbEvent = db_event_last(hContact)) { - DBEVENTINFO dbei = {}; - db_event_get(hDbEvent, &dbei); - data = dbei.timestamp; - text = TimeToStrW(data); - } - else text = 0; - break; - - case QSTO_METACONTACT: - text = pDlg->DoMeta(hContact); - break; - - case QSTO_EVENTCOUNT: - data = db_event_count(hContact); - text = int2strw(data); - break; - } - break; - - case QST_SETTING: - auto *szNodule = pCol.module; - if (!mir_strlen(szNodule)) - szNodule = Proto_GetBaseAccountName(hContact); - - switch (pCol.datatype) { - case QSTS_STRING: - text = db_get_wsa(hContact, szNodule, pCol.setting); - break; - - case QSTS_BYTE: - data = db_get_b(hContact, szNodule, pCol.setting); - text = int2strw(data); - break; - - case QSTS_WORD: - data = db_get_w(hContact, szNodule, pCol.setting); - text = int2strw(data); - break; - - case QSTS_DWORD: - if (pCol.setting == nullptr) { - data = hContact; - text = hex2strw(data); - } - else { - data = db_get_dw(hContact, szNodule, pCol.setting); - text = int2strw(data); - } - break; - - case QSTS_SIGNED: - data = db_get_dw(hContact, szNodule, pCol.setting); - text = int2strw(data); - break; - - case QSTS_HEXNUM: - data = db_get_dw(hContact, szNodule, pCol.setting); - text = hex2strw(data); - break; - - case QSTS_TIMESTAMP: - data = db_get_dw(hContact, szNodule, pCol.setting); - if (data != 0) - text = TimeToStrW(data); - break; - } - } -} +/* +Copyright (C) 2012-23 Miranda NG team (https://miranda-ng.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "stdafx.h" + +CRowItem::CRowItem(MCONTACT _1, QSMainDlg *pDlg) : + hContact(_1) +{ + auto *pa = Proto_GetContactAccount(hContact); + if (pa != nullptr) { + szProto = pa->szModuleName; + if (!pa->IsEnabled()) + bAccOff = true; + + if (db_mc_isMeta(hContact)) + bIsMeta = true; + else if (db_mc_isSub(hContact)) + bIsSub = true; + } + else { + szProto = nullptr; + bAccDel = true; + } + + if (bAccDel || bAccOff) + status = ID_STATUS_OFFLINE; + else + status = Contact::GetStatus(hContact); + + if (int nCount = g_plugin.m_columns.getCount()) { + pValues = new Val[nCount]; + for (int i = 0; i < nCount; i++) + pValues[i].LoadOneItem(hContact, g_plugin.m_columns[i], pDlg); + } + else pValues = nullptr; +} + +CRowItem::~CRowItem() +{ + delete[] pValues; +} + +void CRowItem::GetCellColor(int idx, COLORREF &clrBack, COLORREF &clrText) +{ + if (g_plugin.m_flags & QSO_COLORIZE) { + if (bAccDel) { + clrBack = g_plugin.m_colors[bkg_del]; + clrText = g_plugin.m_colors[fgr_del]; + return; + } + if (bAccOff) { + clrBack = g_plugin.m_colors[bkg_dis]; + clrText = g_plugin.m_colors[fgr_dis]; + return; + } + if (bIsMeta) { + clrBack = g_plugin.m_colors[bkg_meta]; + clrText = g_plugin.m_colors[fgr_meta]; + return; + } + if (bIsSub) { + clrBack = g_plugin.m_colors[bkg_sub]; + clrText = g_plugin.m_colors[fgr_sub]; + return; + } + if (bInList) { + clrBack = g_plugin.m_colors[bkg_hid]; + clrText = g_plugin.m_colors[fgr_hid]; + return; + } + } + + if ((g_plugin.m_flags & QSO_DRAWGRID) == 0 && idx % 2 == 1) { + clrBack = g_plugin.m_colors[bkg_odd]; + clrText = g_plugin.m_colors[fgr_odd]; + } + else { + clrBack = g_plugin.m_colors[bkg_norm]; + clrText = g_plugin.m_colors[fgr_norm]; + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static wchar_t* int2strw(uint32_t num) +{ + wchar_t buf[64]; + _itow_s(num, buf, 10); + return mir_wstrdup(buf); +} + +static wchar_t* hex2strw(uint32_t num) +{ + wchar_t buf[64]; + _itow_s(num, buf, 16); + return mir_wstrdup(buf); +} + +void CRowItem::Val::LoadOneItem(MCONTACT hContact, const ColumnItem &pCol, QSMainDlg *pDlg) +{ + data = UINT_PTR(-1); + replaceStrW(text, nullptr); + + switch (pCol.setting_type) { + case QST_SCRIPT: + { + VARSW vars(pCol.script); + if (g_bVarsInstalled) + text = variables_parse(vars, 0, hContact); + else + text = vars.detach(); + } + break; + + case QST_SERVICE: + // !!!!!!!!!!!!!!!!!!! not implemented + break; + + case QST_CONTACTINFO: + text = Contact::GetInfo(pCol.cnftype, hContact); + if (text) + data = _wtoi(text); + break; + + case QST_OTHER: + switch (pCol.other) { + case QSTO_ACCOUNT: + if (auto *pa = Proto_GetContactAccount(hContact)) + text = mir_wstrdup(pa->tszAccountName); + break; + + case QSTO_LASTSEEN: + data = BuildLastSeenTimeInt(hContact, "SeenModule"); + text = BuildLastSeenTime(data); + break; + + case QSTO_DISPLAYNAME: + text = mir_wstrdup(Clist_GetContactDisplayName(hContact, 0)); + break; + + case QSTO_LASTEVENT: + if (MEVENT hDbEvent = db_event_last(hContact)) { + DBEVENTINFO dbei = {}; + db_event_get(hDbEvent, &dbei); + data = dbei.timestamp; + text = TimeToStrW(data); + } + else text = 0; + break; + + case QSTO_METACONTACT: + text = pDlg->DoMeta(hContact); + break; + + case QSTO_EVENTCOUNT: + data = db_event_count(hContact); + text = int2strw(data); + break; + } + break; + + case QST_SETTING: + auto *szNodule = pCol.module; + if (!mir_strlen(szNodule)) + szNodule = Proto_GetBaseAccountName(hContact); + + switch (pCol.datatype) { + case QSTS_STRING: + text = db_get_wsa(hContact, szNodule, pCol.setting); + break; + + case QSTS_BYTE: + data = db_get_b(hContact, szNodule, pCol.setting); + text = int2strw(data); + break; + + case QSTS_WORD: + data = db_get_w(hContact, szNodule, pCol.setting); + text = int2strw(data); + break; + + case QSTS_DWORD: + if (pCol.setting == nullptr) { + data = hContact; + text = hex2strw(data); + } + else { + data = db_get_dw(hContact, szNodule, pCol.setting); + text = int2strw(data); + } + break; + + case QSTS_SIGNED: + data = db_get_dw(hContact, szNodule, pCol.setting); + text = int2strw(data); + break; + + case QSTS_HEXNUM: + data = db_get_dw(hContact, szNodule, pCol.setting); + text = hex2strw(data); + break; + + case QSTS_TIMESTAMP: + data = db_get_dw(hContact, szNodule, pCol.setting); + if (data != 0) + text = TimeToStrW(data); + break; + } + } +} -- cgit v1.2.3