#ifndef CODESEARCHPAGE_H #define CODESEARCHPAGE_H #include #include #include #include #include #include "ElaTableView.h" #include "ElaText.h" #include "ElaLineEdit.h" #include "ElaPushButton.h" #include "ElaTreeView.h" #include "ElaComboBox.h" #include "ElaPivot.h" #include "utils/callchainanalyzer.h" // 图标按钮(基于 QLabel):显示图标 + 悬停提示,鼠标点击触发信号 class IconButton : public QLabel { Q_OBJECT public: explicit IconButton(const QString &pixmapPath, const QString &tip, QWidget *parent = nullptr) : QLabel(parent) { const QPixmap pm(pixmapPath); setPixmap(pm.scaled(22, 22, Qt::KeepAspectRatio, Qt::SmoothTransformation)); setToolTip(tip); setCursor(Qt::ArrowCursor); setFixedSize(28, 28); setAlignment(Qt::AlignCenter); } signals: void clicked(); protected: void mousePressEvent(QMouseEvent *event) override { emit clicked(); QLabel::mousePressEvent(event); } }; class CodeSearchPage : public QWidget { Q_OBJECT public: enum Mode { ConvertMode, SearchMode }; explicit CodeSearchPage(QWidget *parent = nullptr); ~CodeSearchPage(); /// 静默刷新索引(无弹窗,转码完成后自动调用) void refreshIndexSilent(); /// 转码后静默异步刷新:依次(后台线程)刷新各模式索引,全部完成后清除 m_indexing void buildSilentChain(const QList &modes, int idx); protected: void showEvent(QShowEvent *event) override; private slots: void onBrowsePath(); void onRefreshIndex(); void onFunctionDoubleClicked(const QModelIndex &index); void onExpandAll(); void onCollapseAll(); void onImportChainFiles(); void onExportChain(); void onQueryByInput(); void savePathsToConfig(); void onPivotClicked(int index); private: void initUI(); void loadFunctionList(); void populateTree(const QList &rootNodes); void autoResizeColumns(ElaTreeView *tree); void addTreeItem(QStandardItem *parentItem, const CallChainAnalyzer::TreeNode &node); QString resolveChineseName(const QString &displayName) const; QString lookupUFT3FunctionNo(const QString &funcName); void collectChainFiles(const CallChainAnalyzer::TreeNode &node, QSet &out); static void collectChainLines(const CallChainAnalyzer::TreeNode &node, int depth, QStringList &lines); static QString sanitizeDirName(const QString &name); void runQuery(const QString &displayName); void autoBuildIndexIfNeeded(); void applyMode(); CallChainAnalyzer *currentAnalyzer() const; /// 后台线程异步构建索引(避免界面卡顿),构建期间显示进度框;完成后回调 onDone(ok, message) void runIndexBuild(CallChainAnalyzer *ca, const QString &title, std::function onDone); Mode m_mode = ConvertMode; ElaLineEdit *m_pathEdit; ElaPushButton *m_browseBtn; ElaPushButton *m_refreshBtn; ElaPivot *m_modePivot; IconButton *m_expandBtn; IconButton *m_collapseBtn; ElaPushButton *m_importBtn; ElaPushButton *m_exportChainBtn; ElaComboBox *m_queryCombo; ElaLineEdit *m_queryEdit; ElaPushButton *m_queryBtn; ElaTableView *m_funcTable; QWidget *m_leftPanel; ElaTreeView *m_callTree[2]; QStandardItemModel *m_funcModel; QStandardItemModel *m_treeModel[2]; QLabel *m_bottomTip; // 底部静态提示(仿 UF20 功能查询页) CallChainAnalyzer *m_analyzers[2]; // 两种模式各自的分析器(独立索引) QString m_pathByMode[2]; // 两种模式各自的代码检索路径 QString m_indexedPathByMode[2]; // 两种模式各自已构建索引的路径 bool m_userReSelectedByMode[2] = {false, false}; // 各自改路径后需手动刷新 QStringList m_currentChainFilePaths; // 当前调用链路中所有非"原代码已支持"的文件 QList m_currentChainRoots; // 当前调用链路森林(支持往前查),供导出文本用 QString m_searchRootPath; // 当前索引根路径(导出基准) QString m_currentQueryName; // 当前查询的函数名称(导出目录名) QString m_highlightName; // 当前查询的函数/功能名(调用链树中对应行蓝色高亮) bool m_indexing = false; // 后台索引构建进行中,防止重复触发 }; #endif // CODESEARCHPAGE_H