diff options
Diffstat (limited to 'plugins/QuickSearch/src')
-rw-r--r-- | plugins/QuickSearch/src/main.cpp | 376 | ||||
-rw-r--r-- | plugins/QuickSearch/src/options.cpp | 1038 | ||||
-rw-r--r-- | plugins/QuickSearch/src/stdafx.cxx | 34 | ||||
-rw-r--r-- | plugins/QuickSearch/src/utils.cpp | 1112 | ||||
-rw-r--r-- | plugins/QuickSearch/src/version.h | 2 | ||||
-rw-r--r-- | plugins/QuickSearch/src/window.cpp | 1752 | ||||
-rw-r--r-- | plugins/QuickSearch/src/window_misc.cpp | 1750 | ||||
-rw-r--r-- | plugins/QuickSearch/src/window_row.cpp | 448 |
8 files changed, 3256 insertions, 3256 deletions
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 <http://www.gnu.org/licenses/>. -*/ - -#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<CMPlugin>(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 <http://www.gnu.org/licenses/>.
+*/
+
+#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<CMPlugin>(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 <http://www.gnu.org/licenses/>. -*/ - -#include "stdafx.h" - -class COptionsDlg : public CDlgBase -{ - OBJLIST<ColumnItem> 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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "stdafx.h"
+
+class COptionsDlg : public CDlgBase
+{
+ OBJLIST<ColumnItem> 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 <http://www.gnu.org/licenses/>. -*/ - +/*
+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 <http://www.gnu.org/licenses/>.
+*/
+
#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 <http://www.gnu.org/licenses/>. -*/ - -#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<ColumnItem> &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<ColumnItem> &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<char>*)param; - pList->insert(mir_strdup(szSetting)); - } - return 0; -} - -void CMPlugin::SaveOptions() -{ - // remove old settings - LIST<char> 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 <http://www.gnu.org/licenses/>.
+*/
+
+#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<ColumnItem> &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<ColumnItem> &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<char>*)param;
+ pList->insert(mir_strdup(szSetting));
+ }
+ return 0;
+}
+
+void CMPlugin::SaveOptions()
+{
+ // remove old settings
+ LIST<char> 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 <http://www.gnu.org/licenses/>. -*/ - -#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 <http://www.gnu.org/licenses/>.
+*/
+
+#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 <http://www.gnu.org/licenses/>. -*/ - -#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<int> 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 <http://www.gnu.org/licenses/>.
+*/
+
+#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<int> 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 <http://www.gnu.org/licenses/>. -*/ - -#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 <http://www.gnu.org/licenses/>.
+*/
+
+#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;
+ }
+ }
+}
|