Feature: Add log search bar with prev/next/clear for m_CList_Message

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
yuanyuanxiang
2026-07-15 19:22:55 +02:00
parent f24e7acc48
commit b97f086c0c
8 changed files with 407 additions and 12 deletions

View File

@@ -62,6 +62,7 @@
#include "common/file_upload.h"
#include "SplashDlg.h"
#include "SearchBarDlg.h"
#include "LogSearchBar.h"
#include <ServerServiceWrapper.h>
#include "CDlgFileSend.h"
#include "CClientListDlg.h"
@@ -689,6 +690,10 @@ CMy2015RemoteDlg::~CMy2015RemoteDlg()
m_pSearchBar->DestroyWindow();
SAFE_DELETE(m_pSearchBar);
}
if (m_pLogSearchBar) {
m_pLogSearchBar->DestroyWindow();
SAFE_DELETE(m_pLogSearchBar);
}
}
// DLL 请求限流成员函数实现 (根据配置限制请求频率)
@@ -932,6 +937,7 @@ BEGIN_MESSAGE_MAP(CMy2015RemoteDlg, CDialogEx)
ON_COMMAND(ID_MSGLOG_DELETE, &CMy2015RemoteDlg::OnMsglogDelete)
ON_COMMAND(ID_MSGLOG_COPY, &CMy2015RemoteDlg::OnMsglogCopy)
ON_COMMAND(ID_MSGLOG_CLEAR, &CMy2015RemoteDlg::OnMsglogClear)
ON_COMMAND(ID_MSGLOG_SEARCH, &CMy2015RemoteDlg::OnMsglogSearch)
ON_COMMAND(ID_ONLINE_ADD_WATCH, &CMy2015RemoteDlg::OnOnlineAddWatch)
ON_COMMAND(ID_ONLINE_LOGIN_NOTIFY, &CMy2015RemoteDlg::OnOnlineLoginNotify)
ON_NOTIFY(NM_CUSTOMDRAW, IDC_ONLINE, &CMy2015RemoteDlg::OnNMCustomdrawOnline)
@@ -1429,6 +1435,9 @@ VOID CMy2015RemoteDlg::InitControl()
m_nSplitPos = max(60, min(m_nSplitPos, 600));
m_SplitterBar.Create(this);
m_pLogSearchBar = new CLogSearchBar();
m_pLogSearchBar->Create(this, &m_CList_Message);
// 不在这里调 ApplyThumbnailSettings —— 调用方在 LoadThumbnailSettingsFromCfg
// 之后统一 Apply避免"先用默认值 Apply 一次,再读 INI 后再 Apply 一次"的双绘)。
}
@@ -1670,6 +1679,23 @@ LRESULT CMy2015RemoteDlg::OnShowMessage(WPARAM wParam, LPARAM lParam)
// 消息日志最大条数,达到上限时删除最旧的记录
#define MAX_MESSAGE_COUNT 1000
namespace {
bool MsgHasKW(const CString& s, const CString* kw, int n) {
for (int i = 0; i < n; i++)
if (s.Find(kw[i]) >= 0) return true;
return false;
}
int MsgColorLevel(const CString& type, const CString& msg) {
const CString redKW[] = { _L("严禁"), _L("禁止") };
const CString orangeKW[] = { _L("失败"), _L("警告") };
const CString greenKW[] = { _L("成功"), _L("") };
if (MsgHasKW(type, redKW, _countof(redKW)) || MsgHasKW(msg, redKW, _countof(redKW))) return 1;
if (MsgHasKW(type, orangeKW, _countof(orangeKW)) || MsgHasKW(msg, orangeKW, _countof(orangeKW))) return 2;
if (MsgHasKW(msg, greenKW, _countof(greenKW))) return 3;
return 0;
}
}
VOID CMy2015RemoteDlg::ShowMessage(CString strType, CString strMsg)
{
AUTO_TICK(200, "");
@@ -1682,9 +1708,10 @@ VOID CMy2015RemoteDlg::ShowMessage(CString strType, CString strMsg)
m_CList_Message.DeleteItem(count - 1);
}
m_CList_Message.InsertItem(0, strType); //向控件中设置数据
m_CList_Message.SetItemText(0,1,strTime);
m_CList_Message.SetItemText(0,2,strMsg);
m_CList_Message.InsertItem(0, strType);
m_CList_Message.SetItemText(0, 1, strTime);
m_CList_Message.SetItemText(0, 2, strMsg);
m_CList_Message.SetItemData(0, (DWORD_PTR)MsgColorLevel(strType, strMsg));
CString strStatusMsg;
@@ -1759,9 +1786,12 @@ LRESULT CMy2015RemoteDlg::OnShowErrMessage(WPARAM wParam, LPARAM lParam)
m_CList_Message.DeleteItem(count - 1);
}
m_CList_Message.InsertItem(0, title ? _L(*title) : _TR("操作错误"));
CString strTitle = title ? _L(*title) : _TR("操作错误");
CString strText = text ? _L(*text) : _TR("内部错误");
m_CList_Message.InsertItem(0, strTitle);
m_CList_Message.SetItemText(0, 1, strTime);
m_CList_Message.SetItemText(0, 2, text ? _L(*text) : _TR("内部错误"));
m_CList_Message.SetItemText(0, 2, strText);
m_CList_Message.SetItemData(0, (DWORD_PTR)MsgColorLevel(strTitle, strText));
if(title)delete title;
if(text)delete text;
@@ -3225,7 +3255,8 @@ void CMy2015RemoteDlg::OnSize(UINT nType, int cx, int cy)
lastType = nType;
BOOL hideLog = THIS_CFG.GetInt("settings", "HideMsg", 0) == 1;
const int SPLITTER_H = 6;
const int SPLITTER_H = 6;
const int LOG_SEARCH_H = 26; // 日志搜索条高度
// 日志区有效高度 = m_nSplitPos不含分割条分割条紧贴日志区上方
int splitPos = hideLog ? 0 : m_nSplitPos;
@@ -3252,6 +3283,22 @@ void CMy2015RemoteDlg::OnSize(UINT nType, int cx, int cy)
}
LeaveCriticalSection(&m_cs);
if (m_pLogSearchBar && m_pLogSearchBar->GetSafeHwnd()) {
if (hideLog || !m_bLogSearchVisible) {
m_pLogSearchBar->ShowWindow(SW_HIDE);
} else {
m_pLogSearchBar->ShowWindow(SW_SHOW);
// 右对齐,最多 380px左侧留出 180px 给分组信息
int barW = min(260, max(60, cx - 182));
int barX = cx - 2 - barW;
// 叠在在线列表底部右角:紧贴分割条上方,向上偏移一个条高
int barY = cy - 20 - splitPos - SPLITTER_H - LOG_SEARCH_H + 5;
m_pLogSearchBar->MoveWindow(barX, barY, barW, LOG_SEARCH_H);
// 保证搜索条在列表控件上层BringWindowToTop 仅影响 Z-order不影响焦点
m_pLogSearchBar->BringWindowToTop();
}
}
if (m_SplitterBar.m_hWnd != NULL) {
if (hideLog) {
m_SplitterBar.ShowWindow(SW_HIDE);
@@ -9196,10 +9243,40 @@ void CMy2015RemoteDlg::OnNMCustomdrawMessage(NMHDR* pNMHDR, LRESULT* pResult)
case CDDS_ITEMPREPAINT: {
int nRow = static_cast<int>(pLVCD->nmcd.dwItemSpec);
int nLastRow = m_CList_Message.GetItemCount() - 1;
if (nRow == nLastRow && nLastRow >= 0) {
pLVCD->clrText = RGB(255, 0, 0);
// 搜索命中行深蓝高亮(不依赖 CDIS_SELECTED直接读搜索栏当前命中行号
if (m_pLogSearchBar) {
int nHit = m_pLogSearchBar->GetHighlightedRow();
if (nHit >= 0 && nRow == nHit) {
pLVCD->clrTextBk = RGB(0, 80, 180);
pLVCD->clrText = RGB(255, 255, 255);
*pResult = CDRF_NEWFONT;
return;
}
}
// 关键字着色:必须同时设 clrText + clrTextBk否则系统预填的蓝色会泄漏
int colorLevel = (int)m_CList_Message.GetItemData(nRow);
COLORREF bkDefault = ::GetSysColor(COLOR_WINDOW);
if (colorLevel == 1) {
pLVCD->clrText = RGB(220, 0, 0);
pLVCD->clrTextBk = bkDefault;
*pResult = CDRF_NEWFONT;
return;
}
if (colorLevel == 2) {
pLVCD->clrText = RGB(200, 100, 0);
pLVCD->clrTextBk = bkDefault;
*pResult = CDRF_NEWFONT;
return;
}
if (colorLevel == 3) {
pLVCD->clrText = RGB(0, 140, 0);
pLVCD->clrTextBk = bkDefault;
*pResult = CDRF_NEWFONT;
return;
}
break;
}
}
}
@@ -9213,6 +9290,9 @@ void CMy2015RemoteDlg::OnRClickMessage(NMHDR* pNMHDR, LRESULT* pResult)
menu.AppendMenu(MF_STRING, ID_MSGLOG_DELETE, _TR("删除选中"));
menu.AppendMenu(MF_STRING, ID_MSGLOG_COPY, _TR("复制选中"));
menu.AppendMenu(MF_STRING, ID_MSGLOG_CLEAR, _TR("清空日志"));
menu.AppendMenu(MF_SEPARATOR);
menu.AppendMenu(MF_STRING, ID_MSGLOG_SEARCH,
m_bLogSearchVisible ? _TR("隐藏搜索") : _TR("搜索日志"));
// 没有选中项时禁用"删除选中"
if (m_CList_Message.GetSelectedCount() == 0) {
@@ -9237,7 +9317,7 @@ void CMy2015RemoteDlg::OnMsglogDelete()
while (pos) {
selected.push_back(m_CList_Message.GetNextSelectedItem(pos));
}
// 倒序删除
// 倒序删除,避免索引变化
for (auto it = selected.rbegin(); it != selected.rend(); ++it) {
m_CList_Message.DeleteItem(*it);
}
@@ -9280,6 +9360,14 @@ void CMy2015RemoteDlg::OnMsglogClear()
m_CList_Message.DeleteAllItems();
}
void CMy2015RemoteDlg::OnMsglogSearch()
{
m_bLogSearchVisible = !m_bLogSearchVisible;
// 复用 OnSize 里的布局逻辑
CRect rc;
GetClientRect(&rc);
OnSize(SIZE_RESTORED, rc.Width(), rc.Height());
}
void CMy2015RemoteDlg::OnOnlineAddWatch()
{