summaryrefslogtreecommitdiff
path: root/plugins/QuickSearch/src
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/QuickSearch/src')
-rw-r--r--plugins/QuickSearch/src/main.cpp376
-rw-r--r--plugins/QuickSearch/src/options.cpp1038
-rw-r--r--plugins/QuickSearch/src/stdafx.cxx34
-rw-r--r--plugins/QuickSearch/src/utils.cpp1112
-rw-r--r--plugins/QuickSearch/src/version.h2
-rw-r--r--plugins/QuickSearch/src/window.cpp1752
-rw-r--r--plugins/QuickSearch/src/window_misc.cpp1750
-rw-r--r--plugins/QuickSearch/src/window_row.cpp448
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;
+ }
+ }
+}