Repository: linuxdeepin/dde-file-manager
Pull request #2771: refactor: new search
Author: login: Lighto-Ku
Created: 2025-04-15T13:12:52Z | Merged: 2025-04-16T01:29:13Z

- streamline fileInfo method in SearchDirIterator
- clear search text on URL change in SearchEditWidget
- enhance SortFileInfo and SearchDirIterator functionality
- implement multi-threaded search result processing
- clear last executed search text on URL change in SearchEditWidget
- simplify SearchDirIterator and TraversalDirThreadManager logic

## Summary by Sourcery

Refactor and enhance the search functionality in the file manager, focusing on improving performance, thread safety, and result processing for search operations.

New Features:
- Implement multi-threaded search result processing
- Add support for batched search result notifications

Bug Fixes:
- Clear search text on URL change in SearchEditWidget
- Prevent duplicate result processing

Enhancements:
- Improve search result merging logic
- Enhance thread-safe result handling
- Simplify SearchDirIterator and TraversalDirThreadManager logic


Diff:
diff --git a/include/dfm-base/interfaces/abstractdiriterator.h b/include/dfm-base/interfaces/abstractdiriterator.h
index d726227485..a2f92cd4c9 100644
--- a/include/dfm-base/interfaces/abstractdiriterator.h
+++ b/include/dfm-base/interfaces/abstractdiriterator.h
@@ -126,6 +126,10 @@ class AbstractDirIterator : public QObject
     {
         return {};
     }
+    virtual bool isWaitingForUpdates() const
+    {
+        return false;
+    }
 };
 
 }
diff --git a/include/dfm-base/interfaces/sortfileinfo.h b/include/dfm-base/interfaces/sortfileinfo.h
index 10493eb72d..41c4cc21c0 100644
--- a/include/dfm-base/interfaces/sortfileinfo.h
+++ b/include/dfm-base/interfaces/sortfileinfo.h
@@ -39,6 +39,9 @@ class SortFileInfo
     bool isWriteable() const;
     bool isExecutable() const;
 
+    void setHighlightContent(const QString &content);
+    QString highlightContent() const;
+
 private:
     QScopedPointer<SortFileInfoPrivate> d;
 };
diff --git a/src/dfm-base/interfaces/private/sortfileinfo_p.h b/src/dfm-base/interfaces/private/sortfileinfo_p.h
index c0649f9a9e..7addab3aca 100644
--- a/src/dfm-base/interfaces/private/sortfileinfo_p.h
+++ b/src/dfm-base/interfaces/private/sortfileinfo_p.h
@@ -27,6 +27,7 @@ class SortFileInfoPrivate
     bool readable { false };
     bool writeable { false };
     bool executable { false };
+    QString highlightContent { "" };   // 存储文件的高亮内容
 };
 
 }
diff --git a/src/dfm-base/interfaces/sortfileinfo.cpp b/src/dfm-base/interfaces/sortfileinfo.cpp
index 47a73361db..03cb7b173b 100644
--- a/src/dfm-base/interfaces/sortfileinfo.cpp
+++ b/src/dfm-base/interfaces/sortfileinfo.cpp
@@ -59,6 +59,16 @@ void SortFileInfo::setExecutable(const bool executable)
     d->executable = executable;
 }
 
+void SortFileInfo::setHighlightContent(const QString &content)
+{
+    d->highlightContent = content;
+}
+
+QString SortFileInfo::highlightContent() const
+{
+    return d->highlightContent;
+}
+
 QUrl SortFileInfo::fileUrl() const
 {
     return d->url;
diff --git a/src/plugins/filemanager/dfmplugin-search/iterator/searchdiriterator.cpp b/src/plugins/filemanager/dfmplugin-search/iterator/searchdiriterator.cpp
index 640a85472f..71fa63053d 100644
--- a/src/plugins/filemanager/dfmplugin-search/iterator/searchdiriterator.cpp
+++ b/src/plugins/filemanager/dfmplugin-search/iterator/searchdiriterator.cpp
@@ -83,6 +83,8 @@ void SearchDirIteratorPrivate::onMatched(const QString &id)
             
         QMutexLocker lk(&mutex);
         childrens = results;
+
+        resultWaitCond.wakeAll();
     }
 }
 
@@ -101,6 +103,8 @@ void SearchDirIteratorPrivate::onSearchStoped(const QString &id)
         emit q->sigStopSearch();
         if (searchRootWatcher)
             searchRootWatcher->stopWatcher();
+
+        resultWaitCond.wakeAll();
     }
 }
 
@@ -120,41 +124,17 @@ SearchDirIterator::~SearchDirIterator()
 
 QUrl SearchDirIterator::next()
 {
-    if (!d->childrens.isEmpty()) {
-        QMutexLocker lk(&d->mutex);
-        // 从结果映射中取第一个结果的URL
-        auto it = d->childrens.begin();
-        d->currentFileUrl = it.key();
-        d->currentFileContent = it->highlightedContent();
-        d->childrens.erase(it);
-        return d->currentFileUrl;
-    }
-
     return {};
 }
 
 bool SearchDirIterator::hasNext() const
 {
-    std::call_once(d->searchOnceFlag, [this]() {
-        d->searchStoped = false;
-        emit this->sigSearch();
-    });
-
-    if (d->searchStoped) {
-        emit sigStopSearch();
-        return false;
-    }
-
-    QMutexLocker lk(&d->mutex);
-    bool hasNext = !(d->childrens.isEmpty() && d->searchFinished);
-    if (!hasNext)
-        emit sigStopSearch();
-    return hasNext;
+    return false;
 }
 
 QString SearchDirIterator::fileName() const
 {
-    return fileInfo()->nameOf(NameInfoType::kFileName);
+    return "";
 }
 
 QUrl SearchDirIterator::fileUrl() const
@@ -164,18 +144,7 @@ QUrl SearchDirIterator::fileUrl() const
 
 const FileInfoPointer SearchDirIterator::fileInfo() const
 {
-    if (!d->currentFileUrl.isValid())
-        return nullptr;
-
-    auto info = InfoFactory::create<FileInfo>(d->currentFileUrl);
-
-    if (!d->currentFileContent.isEmpty()) {
-        // 设置高亮内容到扩展属性
-        info->setExtendedAttributes(ExtInfoType::kFileHighlightContent, d->currentFileContent);
-        d->currentFileContent.clear();
-    }
-
-    return info;
+    return nullptr;
 }
 
 QUrl SearchDirIterator::url() const
@@ -183,6 +152,34 @@ QUrl SearchDirIterator::url() const
     return SearchHelper::rootUrl();
 }
 
+QList<QSharedPointer<SortFileInfo>> SearchDirIterator::sortFileInfoList()
+{
+    QList<QSharedPointer<SortFileInfo>> result;
+    
+    // 确保搜索已经开始
+    std::call_once(d->searchOnceFlag, [this]() {
+        d->searchStoped = false;
+        emit this->sigSearch();
+    });
+    
+    // Lock and wait for children to be populated or search to stop/finish.
+    QMutexLocker lk(&d->mutex);
+    while (d->childrens.isEmpty() && !d->searchStoped) {
+        d->resultWaitCond.wait(&d->mutex);
+    }
+    if (d->searchFinished && d->childrens.isEmpty())
+        return {};
+
+    for (auto it = d->childrens.begin(); it != d->childrens.end(); ++it) {
+        auto sortInfo = QSharedPointer<SortFileInfo>(new SortFileInfo());
+        sortInfo->setUrl(it.key());
+        sortInfo->setHighlightContent(it->highlightedContent());
+        result.append(sortInfo);
+    }
+    d->childrens.clear();
+    return result;
+}
+
 void SearchDirIterator::close()
 {
     if (d->taskId.isEmpty())
@@ -191,4 +188,20 @@ void SearchDirIterator::close()
     SearchManager::instance()->stop(d->taskId);
 }
 
+bool SearchDirIterator::isWaitingForUpdates() const
+{
+    // We're waiting for updates if:
+    // 1. Search has started (check if the once_flag has been called)
+    // 2. Search is not finished 
+    // 3. Search is not stopped
+    
+    // Since we can't directly check if once_flag has been called,
+    // we can infer it from the taskId not being empty
+    
+    // Protect access to shared variables
+    QMutexLocker lk(&d->mutex);
+    
+    return !d->taskId.isEmpty() && !d->searchFinished && !d->searchStoped;
+}
+
 }
diff --git a/src/plugins/filemanager/dfmplugin-search/iterator/searchdiriterator.h b/src/plugins/filemanager/dfmplugin-search/iterator/searchdiriterator.h
index 398377c8f2..2fdda5b4f5 100644
--- a/src/plugins/filemanager/dfmplugin-search/iterator/searchdiriterator.h
+++ b/src/plugins/filemanager/dfmplugin-search/iterator/searchdiriterator.h
@@ -31,6 +31,9 @@ class SearchDirIterator : public AbstractDirIterator
     virtual const FileInfoPointer fileInfo() const override;
     virtual QUrl url() const override;
     virtual void close() override;
+    virtual QList<QSharedPointer<SortFileInfo>> sortFileInfoList() override;
+    virtual bool oneByOne() override { return false; }
+    virtual bool isWaitingForUpdates() const override;
 
 signals:
     void sigSearch() const;
diff --git a/src/plugins/filemanager/dfmplugin-search/iterator/searchdiriterator_p.h b/src/plugins/filemanager/dfmplugin-search/iterator/searchdiriterator_p.h
index c2769b354f..fbc039cb3b 100644
--- a/src/plugins/filemanager/dfmplugin-search/iterator/searchdiriterator_p.h
+++ b/src/plugins/filemanager/dfmplugin-search/iterator/searchdiriterator_p.h
@@ -54,6 +54,7 @@ public Q_SLOTS:
     mutable QMutex mutex;                   // 互斥锁
     std::once_flag searchOnceFlag;          // 一次性标志
     SearchDirIterator *q = nullptr;         // 指向父类的指针
+    QWaitCondition resultWaitCond;
 };
 
 }
diff --git a/src/plugins/filemanager/dfmplugin-search/searchmanager/maincontroller/task/taskcommander.cpp b/src/plugins/filemanager/dfmplugin-search/searchmanager/maincontroller/task/taskcommander.cpp
index 21ed9e39f3..27392e419e 100644
--- a/src/plugins/filemanager/dfmplugin-search/searchmanager/maincontroller/task/taskcommander.cpp
+++ b/src/plugins/filemanager/dfmplugin-search/searchmanager/maincontroller/task/taskcommander.cpp
@@ -15,15 +15,170 @@ DFMBASE_USE_NAMESPACE
 DPSEARCH_USE_NAMESPACE
 DFM_SEARCH_USE_NS
 
+SearchResultWorker::SearchResultWorker(QObject *parent)
+    : QObject(parent),
+      running(true),
+      dataProcessingComplete(0),
+      allSearchersDone(0)
+{
+}
+
+SearchResultWorker::~SearchResultWorker()
+{
+    stop();
+}
+
+void SearchResultWorker::startProcessing(const QString &id)
+{
+    taskId = id;
+    running = true;
+    
+    // Process all queued searchers until stopped
+    while (running) {
+        processQueue();
+        
+        // 如果所有搜索器完成且队列为空，执行最终处理
+        if (allSearchersDone.loadAcquire() == 1) {
+            QMutexLocker lock(&mutex);
+            if (searcherQueue.isEmpty()) {
+                finalizeProcessing();
+                break;
+            }
+        }
+    }
+    
+    emit processingFinished();
+}
+
+void SearchResultWorker::processResults(AbstractSearcher *searcher)
+{
+    if (!searcher)
+        return;
+        
+    QMutexLocker lock(&mutex);
+    searcherQueue.enqueue(searcher);
+    condition.wakeOne();
+}
+
+void SearchResultWorker::stop()
+{
+    QMutexLocker lock(&mutex);
+    running = false;
+    condition.wakeAll();
+}
+
+DFMSearchResultMap SearchResultWorker::getResults()
+{
+    QReadLocker lk(&rwLock);
+    return resultMap;
+}
+
+void SearchResultWorker::allSearchersFinished()
+{
+    // 设置标志，指示所有搜索器已完成
+    allSearchersDone.storeRelease(1);
+    
+    // 唤醒工作线程检查队列
+    QMutexLocker lock(&mutex);
+    condition.wakeOne();
+}
+
+void SearchResultWorker::processQueue()
+{
+    AbstractSearcher *searcher = nullptr;
+    
+    // Wait for new data with timeout
+    {
+        QMutexLocker lock(&mutex);
+        if (searcherQueue.isEmpty()) {
+            // 如果队列为空且所有搜索器已完成，终止处理
+            if (allSearchersDone.loadAcquire() == 1) {
+                return;
+            }
+            
+            condition.wait(&mutex, 100);  // 带超时等待
+            if (searcherQueue.isEmpty())
+                return;
+        }
+        
+        searcher = searcherQueue.dequeue();
+    }
+    
+    if (searcher && searcher->hasItem()) {
+        // Get and process results from current searcher
+        DFMSearchResultMap searchResults = searcher->takeAll();
+        
+        if (!searchResults.isEmpty()) {
+            mergeResults(searchResults);
+            emit resultsUpdated(taskId);
+        }
+    }
+}
+
+void SearchResultWorker::mergeResults(const DFMSearchResultMap &newResults)
+{
+    QWriteLocker lk(&rwLock);
+    
+    // Merge search results to the main result set
+    for (auto it = newResults.constBegin(); it != newResults.constEnd(); ++it) {
+        const QUrl &url = it.key();
+        
+        // If there's already a result for this URL, keep the one with higher match score
+        auto existing = resultMap.find(url);
+        if (existing != resultMap.end()) {
+            if (it.value().matchScore() > existing.value().matchScore())
+                resultMap[url] = it.value();
+        } else {
+            // Otherwise add directly
+            resultMap.insert(url, it.value());
+        }
+    }
+}
+
+void SearchResultWorker::finalizeProcessing()
+{
+    fmInfo() << "Finalizing search result processing for task:" << taskId;
+    
+    // 标记数据处理已完成
+    dataProcessingComplete.storeRelease(1);
+    
+    // 发送所有处理完成的信号
+    emit allProcessingComplete(taskId);
+}
+
 TaskCommanderPrivate::TaskCommanderPrivate(TaskCommander *parent)
     : QObject(parent),
       q(parent),
-      finishedCount(0)
+      finishedCount(0),
+      allFinishedNotified(false)
 {
+    // Create result worker and move it to the worker thread
+    resultWorker = new SearchResultWorker;
+    resultWorker->moveToThread(&workerThread);
+    
+    // Connect signals and slots
+    connect(&workerThread, &QThread::started, resultWorker, [this]() {
+        resultWorker->startProcessing(taskId);
+    });
+    connect(&workerThread, &QThread::finished, resultWorker, &QObject::deleteLater);
+    connect(resultWorker, &SearchResultWorker::resultsUpdated, this, &TaskCommanderPrivate::onResultsUpdated);
+    connect(resultWorker, &SearchResultWorker::allProcessingComplete, this, &TaskCommanderPrivate::onAllProcessingComplete);
+    
+    // Start the worker thread
+    workerThread.start();
 }
 
 TaskCommanderPrivate::~TaskCommanderPrivate()
 {
+    // Stop and clean up the worker thread
+    if (resultWorker) {
+        resultWorker->stop();
+    }
+    
+    workerThread.quit();
+    workerThread.wait();
+    
+    // Clean up searchers
     for (auto searcher : allSearchers) {
         searcher->deleteLater();
     }
@@ -42,77 +197,43 @@ AbstractSearcher *TaskCommanderPrivate::createSearcher(const QUrl &url, const QS
     return new DFMSearcher(url, keyword, q, type);
 }
 
-void TaskCommanderPrivate::processContentResult(const SearchResult &result)
+void TaskCommanderPrivate::onUnearthed(AbstractSearcher *searcher)
 {
-    ContentResultAPI contentResult(const_cast<SearchResult &>(result));
-    QUrl url = QUrl::fromLocalFile(result.path());
-    
-    // Create unified DFMSearchResult
-    DFMSearchResult searchResult(url);
-    searchResult.setHighlightedContent(contentResult.highlightedContent());
-    searchResult.setIsContentMatch(true);
-    searchResult.setMatchScore(0.5); // Weight for content match
-    
-    QWriteLocker lk(&rwLock);
-    // Check if already exists, keep the one with higher match score
-    auto it = resultMap.find(url);
-    if (it != resultMap.end()) {
-        if (searchResult.matchScore() > it.value().matchScore()) {
-            resultMap[url] = searchResult;
-        }
-    } else {
-        resultMap.insert(url, searchResult);
+    Q_ASSERT(searcher);
+
+    // Pass the searcher to the worker thread for processing
+    if (allSearchers.contains(searcher) && searcher->hasItem() && resultWorker) {
+        resultWorker->processResults(searcher);
     }
 }
 
-void TaskCommanderPrivate::onUnearthed(AbstractSearcher *searcher)
+void TaskCommanderPrivate::onResultsUpdated(const QString &id)
 {
-    Q_ASSERT(searcher);
+    if (id == taskId) {
+        QMetaObject::invokeMethod(q, "matched", Qt::QueuedConnection, Q_ARG(QString, taskId));
+    }
+}
 
-    if (allSearchers.contains(searcher) && searcher->hasItem()) {
-        // Get results from current searcher
-        auto searchResults = searcher->takeAll();
+void TaskCommanderPrivate::onFinished()
+{
+    if (finishedCount.fetchAndAddRelaxed(1) + 1 == allSearchers.size()) {
+        fmInfo() << "All searchers finished for task:" << taskId;
         
-        // If no results, do not process
-        if (searchResults.isEmpty())
-            return;
-            
-        QWriteLocker lk(&rwLock);
-        bool hasNewResults = false;
-
-        // Merge search results to the main result set
-        // This merge logic is necessary because TaskCommander integrates results from multiple searchers
-        for (auto it = searchResults.begin(); it != searchResults.end(); ++it) {
-            const QUrl &url = it.key();
-            
-            // If this URL has been processed, skip to avoid duplicate processing
-            if (processedUrls.contains(url))
-                continue;
-                
-            processedUrls.insert(url);
-            
-            // If there's already a result for this URL, keep the one with higher match score
-            auto existing = resultMap.find(url);
-            if (existing != resultMap.end()) {
-                if (it.value().matchScore() > existing.value().matchScore()) {
-                    resultMap[url] = it.value();
-                }
-            } else {
-                // Otherwise add directly
-                resultMap.insert(url, it.value());
-                hasNewResults = true;
-            }
+        // 通知工作线程所有搜索器已完成
+        if (resultWorker) {
+            resultWorker->allSearchersFinished();
+        } else {
+            // 如果没有工作线程，直接检查完成状态
+            checkAllFinished();
         }
-
-        // Only send signal when there are new results
-        if (hasNewResults)
-            QMetaObject::invokeMethod(q, "matched", Qt::QueuedConnection, Q_ARG(QString, taskId));
     }
 }
 
-void TaskCommanderPrivate::onFinished()
+void TaskCommanderPrivate::onAllProcessingComplete(const QString &id)
 {
-    if (finishedCount.fetchAndAddRelaxed(1) + 1 == allSearchers.size()) {
+    if (id == taskId && !allFinishedNotified) {
+        fmInfo() << "All data processing complete for task:" << taskId;
+        allFinishedNotified = true;
         checkAllFinished();
     }
 }
@@ -123,7 +244,10 @@ void TaskCommanderPrivate::checkAllFinished()
         q->deleteLater();
         disconnect(q, nullptr, nullptr, nullptr);
     } else {
-        QMetaObject::invokeMethod(q, "finished", Qt::QueuedConnection, Q_ARG(QString, taskId));
+        // 只有当所有搜索器完成且数据处理完成，或没有工作线程时，才发送finished信号
+        if (!resultWorker || allFinishedNotified) {
+            QMetaObject::invokeMethod(q, "finished", Qt::QueuedConnection, Q_ARG(QString, taskId));
+        }
     }
 }
 
@@ -142,14 +266,14 @@ QString TaskCommander::taskID() const
 
 DFMSearchResultMap TaskCommander::getResults() const
 {
-    QReadLocker lk(&d->rwLock);
-    return d->resultMap;
+    // Get results from the worker thread
+    return d->resultWorker ? d->resultWorker->getResults() : DFMSearchResultMap();
 }
 
 QList<QUrl> TaskCommander::getResultsUrls() const
 {
-    QReadLocker lk(&d->rwLock);
-    return d->resultMap.keys();
+    // Get result URLs directly from the worker thread
+    return d->resultWorker ? d->resultWorker->getResults().keys() : QList<QUrl>();
 }
 
 bool TaskCommander::start()
diff --git a/src/plugins/filemanager/dfmplugin-search/searchmanager/maincontroller/task/taskcommander_p.h b/src/plugins/filemanager/dfmplugin-search/searchmanager/maincontroller/task/taskcommander_p.h
index f24634fe24..a208371e02 100644
--- a/src/plugins/filemanager/dfmplugin-search/searchmanager/maincontroller/task/taskcommander_p.h
+++ b/src/plugins/filemanager/dfmplugin-search/searchmanager/maincontroller/task/taskcommander_p.h
@@ -17,9 +17,52 @@
 #include <QAtomicInt>
 #include <QMap>
 #include <QSet>
+#include <QThread>
+#include <QQueue>
+#include <QMutex>
+#include <QWaitCondition>
 
 DPSEARCH_BEGIN_NAMESPACE
 
+// New worker class for processing search results in a separate thread
+class SearchResultWorker : public QObject
+{
+    Q_OBJECT
+public:
+    explicit SearchResultWorker(QObject *parent = nullptr);
+    ~SearchResultWorker() override;
+
+    void processResults(AbstractSearcher *searcher);
+    void stop();
+    DFMSearchResultMap getResults();
+    
+    // 标记所有搜索器已完成，通知工作线程最终处理并等待
+    void allSearchersFinished();
+
+signals:
+    void resultsUpdated(const QString &taskId);
+    void processingFinished();
+    void allProcessingComplete(const QString &taskId);
+
+public slots:
+    void startProcessing(const QString &taskId);
+
+private:
+    void processQueue();
+    void mergeResults(const DFMSearchResultMap &newResults);
+    void finalizeProcessing();  // 完成最终处理，清理资源
+
+    QString taskId;
+    QQueue<AbstractSearcher*> searcherQueue;
+    DFMSearchResultMap resultMap;
+    QMutex mutex;
+    QWaitCondition condition;
+    QReadWriteLock rwLock;
+    bool running { true };
+    QAtomicInt dataProcessingComplete { 0 };  // 标记数据处理是否完成
+    QAtomicInt allSearchersDone { 0 };        // 标记所有搜索器是否完成
+};
+
 class TaskCommanderPrivate : public QObject
 {
     Q_OBJECT
@@ -37,17 +80,19 @@ private slots:
     void onUnearthed(AbstractSearcher *searcher);
     void onFinished();
     void checkAllFinished();
-    void processContentResult(const DFMSEARCH::SearchResult &result);
+    void onResultsUpdated(const QString &taskId);
+    void onAllProcessingComplete(const QString &taskId);
 
 private:
     TaskCommander *q { nullptr };
     QString taskId { "" };
     QList<AbstractSearcher *> allSearchers {};
-    DFMSearchResultMap resultMap {};             // 使用统一的结果集
-    QSet<QUrl> processedUrls;                 // 记录已处理的 URL
+    QThread workerThread;
+    SearchResultWorker *resultWorker { nullptr };
     QReadWriteLock rwLock;
     QAtomicInt finishedCount { 0 };
     bool deleted { false };
+    bool allFinishedNotified { false };  // 防止重复发送finished信号
 };
 
 DPSEARCH_END_NAMESPACE
diff --git a/src/plugins/filemanager/dfmplugin-search/searchmanager/searcher/dfmsearch/dfmsearcher.cpp b/src/plugins/filemanager/dfmplugin-search/searchmanager/searcher/dfmsearch/dfmsearcher.cpp
index e4863e8689..30ce004bb2 100644
--- a/src/plugins/filemanager/dfmplugin-search/searchmanager/searcher/dfmsearch/dfmsearcher.cpp
+++ b/src/plugins/filemanager/dfmplugin-search/searchmanager/searcher/dfmsearch/dfmsearcher.cpp
@@ -28,7 +28,7 @@ DFMSearcher::DFMSearcher(const QUrl &url, const QString &keyword, QObject *paren
     }
 
     connect(engine, &SearchEngine::searchStarted, this, &DFMSearcher::onSearchStarted);
-    connect(engine, &SearchEngine::resultFound, this, &DFMSearcher::onResultFound);
+    // connect(engine, &SearchEngine::resultFound, this, &DFMSearcher::onResultFound);
     connect(engine, &SearchEngine::searchFinished, this, &DFMSearcher::onSearchFinished);
     connect(engine, &SearchEngine::searchCancelled, this, &DFMSearcher::onSearchCancelled);
     connect(engine, &SearchEngine::errorOccurred, this, &DFMSearcher::onSearchError);
@@ -36,9 +36,6 @@ DFMSearcher::DFMSearcher(const QUrl &url, const QString &keyword, QObject *paren
 
 DFMSearcher::~DFMSearcher()
 {
-    if (engine) {
-        engine->deleteLater();
-    }
 }
 
 SearchQuery DFMSearcher::createSearchQuery() const
@@ -67,6 +64,8 @@ bool DFMSearcher::search()
     }
 
     notifyTimer.start();
+    lastEmit.storeRelaxed(0);
+    resultCount.storeRelaxed(0);
 
     // Set search options
     SearchOptions options;
@@ -92,7 +91,10 @@ bool DFMSearcher::hasItem() const
 DFMSearchResultMap DFMSearcher::takeAll()
 {
     QMutexLocker lk(&mutex);
-    return std::move(allResults);
+    DFMSearchResultMap result = std::move(allResults);
+    allResults.clear();
+    resultCount.storeRelaxed(0);
+    return result;
 }
 
 SearchType DFMSearcher::getSearchType() const
@@ -100,6 +102,29 @@ SearchType DFMSearcher::getSearchType() const
     return engine ? engine->searchType() : SearchType::FileName;
 }
 
+void DFMSearcher::checkNotifyThreshold()
+{
+    // Send notification signal if we have reached the batch size or time interval
+    bool shouldNotify = false;
+    
+    // Check batch size threshold
+    if (resultCount.loadRelaxed() >= kBatchSize) {
+        shouldNotify = true;
+    } else {
+        // Check time interval threshold (if we have any results to send)
+        if (resultCount.loadRelaxed() > 0 && 
+            notifyTimer.elapsed() - lastEmit.loadRelaxed() > kEmitInterval) {
+            shouldNotify = true;
+        }
+    }
+    
+    if (shouldNotify) {
+        lastEmit.storeRelaxed(notifyTimer.elapsed());
+        resultCount.storeRelaxed(0);
+        emit unearthed(this);
+    }
+}
+
 void DFMSearcher::onSearchStarted()
 {
     fmInfo() << "Search started for:" << keyword;
@@ -124,34 +149,36 @@ void DFMSearcher::processSearchResult(const SearchResult &result)
         searchResult.setMatchScore(0.5); // Filename match has lower priority
     }
 
-    // Results obtained by DFMSearcher can be considered unique within this instance
-    QMutexLocker lk(&mutex);
-    allResults.insert(url, searchResult);
-}
-
-void DFMSearcher::onResultFound(const SearchResult &result)
-{
-    processSearchResult(result);
-
-    // Send results every 50ms
-    if (notifyTimer.elapsed() - lastEmit > kEmitInterval) {
-        lastEmit = notifyTimer.elapsed();
-        emit unearthed(this);
+    // Store the result in a thread-safe way
+    {
+        QMutexLocker lk(&mutex);
+        allResults.insert(url, searchResult);
     }
+    
+    // Increment result count for batch processing
+    resultCount.fetchAndAddRelaxed(1);
 }
 
+// void DFMSearcher::onResultFound(const SearchResult &result)
+// {
+//     processSearchResult(result);
+//     checkNotifyThreshold();
+// }
+
 void DFMSearcher::onSearchFinished(const QList<SearchResult> &results)
 {
     fmInfo() << "Search finished, found" << results.size() << "results";
+    
     if (!engine->searchOptions().resultFoundEnabled()) {
         for (const auto &result : results) {
             processSearchResult(result);
         }
     }
 
-    fmInfo() << "Search finished, result processed";
-    if (engine->status() == SearchStatus::Finished && hasItem())
+    // Ensure we notify about any remaining results
+    if (resultCount.loadRelaxed() > 0) {
         emit unearthed(this);
+    }
 
     fmInfo() << "Search finished, result pushed";
     emit finished();
@@ -160,6 +187,12 @@ void DFMSearcher::onSearchFinished(const QList<SearchResult> &results)
 void DFMSearcher::onSearchCancelled()
 {
     fmInfo() << "Search cancelled";
+    
+    // Send any remaining results
+    if (resultCount.loadRelaxed() > 0) {
+        emit unearthed(this);
+    }
+    
     emit finished();
 }
 
@@ -170,5 +203,11 @@ void DFMSearcher::onSearchError(const SearchError &error)
                 << "Category:" << error.code().category().name()
                 << "Name:" << error.name()
                 << "Message:" << error.message();
+                
+    // Send any results we have so far
+    if (resultCount.loadRelaxed() > 0) {
+        emit unearthed(this);
+    }
+    
     emit finished();
 } 
diff --git a/src/plugins/filemanager/dfmplugin-search/searchmanager/searcher/dfmsearch/dfmsearcher.h b/src/plugins/filemanager/dfmplugin-search/searchmanager/searcher/dfmsearch/dfmsearcher.h
index 17b72de3a7..0e566633da 100644
--- a/src/plugins/filemanager/dfmplugin-search/searchmanager/searcher/dfmsearch/dfmsearcher.h
+++ b/src/plugins/filemanager/dfmplugin-search/searchmanager/searcher/dfmsearch/dfmsearcher.h
@@ -14,6 +14,7 @@
 #include <QMutex>
 #include <QElapsedTimer>
 #include <QMap>
+#include <QAtomicInt>
 
 DPSEARCH_BEGIN_NAMESPACE
 
@@ -34,10 +35,13 @@ class DFMSearcher : public AbstractSearcher
     DFMSEARCH::SearchQuery createSearchQuery() const;
     void processSearchResult(const DFMSEARCH::SearchResult &result);
     DFMSEARCH::SearchType getSearchType() const;
+    
+    // Improves thread safety by using atomic value for notification tracking
+    void checkNotifyThreshold();
 
 private slots:
     void onSearchStarted();
-    void onResultFound(const DFMSEARCH::SearchResult &result);
+    // void onResultFound(const DFMSEARCH::SearchResult &result);
     void onSearchFinished(const QList<DFMSEARCH::SearchResult> &results);
     void onSearchCancelled();
     void onSearchError(const DFMSEARCH::SearchError &error);
@@ -47,7 +51,10 @@ private slots:
     DFMSearchResultMap allResults;
     mutable QMutex mutex;
     QElapsedTimer notifyTimer;
-    int lastEmit { 0 };
+    QAtomicInt lastEmit { 0 };
+    QAtomicInt resultCount { 0 };
+    static constexpr int kBatchSize = 10;    // Number of results to batch before notifying
+    static constexpr int kEmitInterval = 50; // Milliseconds between notifications
 };
 
 DPSEARCH_END_NAMESPACE
diff --git a/src/plugins/filemanager/dfmplugin-titlebar/views/searcheditwidget.cpp b/src/plugins/filemanager/dfmplugin-titlebar/views/searcheditwidget.cpp
index 69dbb45bf4..47c0c90a51 100644
--- a/src/plugins/filemanager/dfmplugin-titlebar/views/searcheditwidget.cpp
+++ b/src/plugins/filemanager/dfmplugin-titlebar/views/searcheditwidget.cpp
@@ -143,7 +143,8 @@ void SearchEditWidget::onUrlChanged(const QUrl &url)
         return;
     }
 
-    // deactivateEdit();
+    lastExecutedSearchText.clear();
+    searchEdit->setText("");
 }
 
 void SearchEditWidget::onAdvancedButtonClicked()
diff --git a/src/plugins/filemanager/dfmplugin-workspace/models/fileitemdata.cpp b/src/plugins/filemanager/dfmplugin-workspace/models/fileitemdata.cpp
index 1f14983c1e..017ba94a48 100644
--- a/src/plugins/filemanager/dfmplugin-workspace/models/fileitemdata.cpp
+++ b/src/plugins/filemanager/dfmplugin-workspace/models/fileitemdata.cpp
@@ -55,23 +55,6 @@ void FileItemData::clearThumbnail()
         info->setExtendedAttributes(ExtInfoType::kFileThumbnail, QVariant());
 }
 
-void FileItemData::setFileInfo(FileInfoPointer fileInfo)
-{
-    if (fileInfo) {
-        info = fileInfo;
-        info->customData(kItemFileRefreshIcon);
-        updateOnce = !info->extendAttributes(ExtInfoType::kFileNeedUpdate).toBool();
-        
-        // 如果是本地设备并且不需要更新，那么立即更新属性
-        if (info->extendAttributes(ExtInfoType::kFileLocalDevice).toBool() &&
-            !info->extendAttributes(ExtInfoType::kFileNeedUpdate).toBool()) {
-            updateOnce = true;
-            info->setExtendedAttributes(ExtInfoType::kFileNeedUpdate, false);
-            info->updateAttributes();
-        }
-    }
-}
-
 FileInfoPointer FileItemData::fileInfo() const
 {
     return info;
@@ -265,8 +248,8 @@ QVariant FileItemData::data(int role) const
         }
         return QVariant();
     case kItemFileContentPreviewRole:
-    if (info)
-        return info->extendAttributes(ExtInfoType::kFileHighlightContent).toString();
+    if (sortInfo)
+        return sortInfo->highlightContent();
 
     return QString();
     default:
diff --git a/src/plugins/filemanager/dfmplugin-workspace/models/fileitemdata.h b/src/plugins/filemanager/dfmplugin-workspace/models/fileitemdata.h
index c7ad955a1e..4e481919db 100644
--- a/src/plugins/filemanager/dfmplugin-workspace/models/fileitemdata.h
+++ b/src/plugins/filemanager/dfmplugin-workspace/models/fileitemdata.h
@@ -23,7 +23,6 @@ class FileItemData
 
     void refreshInfo();
     void clearThumbnail();
-    void setFileInfo(FileInfoPointer fileInfo);
     FileInfoPointer fileInfo() const;
     FileItemData *parentData() const;
     QIcon fileIcon() const;
diff --git a/src/plugins/filemanager/dfmplugin-workspace/models/rootinfo.cpp b/src/plugins/filemanager/dfmplugin-workspace/models/rootinfo.cpp
index 14e4351aef..f8e4b897e0 100644
--- a/src/plugins/filemanager/dfmplugin-workspace/models/rootinfo.cpp
+++ b/src/plugins/filemanager/dfmplugin-workspace/models/rootinfo.cpp
@@ -398,31 +398,16 @@ void RootInfo::handleTraversalResults(const QList<FileInfoPointer> children, con
         Q_EMIT iteratorAddFiles(travseToken, sortInfos, infos);
 }
 
-void RootInfo::handleTraversalResultsUpdate(const QList<FileInfoPointer> children, const QString &travseToken)
+void RootInfo::handleTraversalResultsUpdate(const QList<SortInfoPointer> children, const QString &travseToken)
 {
-    QList<SortInfoPointer> sortInfos;
-    QList<FileInfoPointer> infos;
-    for (const auto &info : children) {
-        if (!info)
-            continue;
-            
-        QUrl childUrl = info->urlOf(dfmbase::UrlInfoType::kUrl);
-        childUrl.setPath(childUrl.path());
-        
-        SortInfoPointer sort = sortFileInfo(info);
-        if (!sort)
-            continue;
-            
-        sortInfos.append(sort);
-        infos.append(info);
+    if (children.isEmpty())
+        return;
 
-        QWriteLocker lk(&childrenLock);
-        // 更新已存在的文件信息
-        sourceDataList.replace(childrenUrlList.indexOf(childUrl), sort);
-    }
+    QWriteLocker lk(&childrenLock);
+    // 更新已存在的文件信息
+    sourceDataList = children;
 
-    if (sortInfos.length() > 0)
-        Q_EMIT iteratorUpdateFiles(travseToken, sortInfos, infos);
+    Q_EMIT iteratorUpdateFiles(travseToken, sourceDataList);
 }
 
 void RootInfo::handleTraversalLocalResult(QList<SortInfoPointer> children,
diff --git a/src/plugins/filemanager/dfmplugin-workspace/models/rootinfo.h b/src/plugins/filemanager/dfmplugin-workspace/models/rootinfo.h
index 9d7a663ced..9026352cd5 100644
--- a/src/plugins/filemanager/dfmplugin-workspace/models/rootinfo.h
+++ b/src/plugins/filemanager/dfmplugin-workspace/models/rootinfo.h
@@ -68,7 +68,7 @@ class RootInfo : public QObject
                             const Qt::SortOrder sortOrder,
                             const bool isMixDirAndFile);
     void iteratorAddFiles(const QString &key, const QList<SortInfoPointer> sortInfos, const QList<FileInfoPointer> infos);
-    void iteratorUpdateFiles(const QString &key, const QList<SortInfoPointer> sortInfos, const QList<FileInfoPointer> infos);
+    void iteratorUpdateFiles(const QString &key, const QList<SortInfoPointer> sortInfos);
     void watcherAddFiles(const QList<SortInfoPointer> &children);
     void watcherRemoveFiles(const QList<SortInfoPointer> &children);
     void traversalFinished(const QString &key);
@@ -97,7 +97,7 @@ public Q_SLOTS:
     void doThreadWatcherEvent();
 
     void handleTraversalResults(const QList<FileInfoPointer> children, const QString &travseToken);
-    void handleTraversalResultsUpdate(const QList<FileInfoPointer> children, const QString &travseToken);
+    void handleTraversalResultsUpdate(const QList<SortInfoPointer> children, const QString &travseToken);
     void handleTraversalLocalResult(QList<SortInfoPointer> children,
                                     dfmio::DEnumerator::SortRoleCompareFlag sortRole,
                                     Qt::SortOrder sortOrder,
diff --git a/src/plugins/filemanager/dfmplugin-workspace/utils/filesortworker.cpp b/src/plugins/filemanager/dfmplugin-workspace/utils/filesortworker.cpp
index 6383f3246a..2263720bb4 100644
--- a/src/plugins/filemanager/dfmplugin-workspace/utils/filesortworker.cpp
+++ b/src/plugins/filemanager/dfmplugin-workspace/utils/filesortworker.cpp
@@ -201,32 +201,31 @@ void FileSortWorker::handleIteratorChildren(const QString &key, const QList<Sort
     handleAddChildren(key, children, infos, sortRole, sortOrder, isMixDirAndFile, false, false, false);
 }
 
-void FileSortWorker::handleIteratorChildrenUpdate(const QString &key, const QList<SortInfoPointer> children, const QList<FileInfoPointer> infos)
+void FileSortWorker::handleIteratorChildrenUpdate(const QString &key, const QList<SortInfoPointer> children)
 {
     if (key != currentKey || isCanceled)
         return;
 
-    for (int i = 0; i < children.size(); ++i) {
-        const auto &sortInfo = children.at(i);
-        const auto &fileInfo = infos.at(i);
-        
-        if (!sortInfo || !fileInfo)
+    QList<SortInfoPointer> newChildren {};
+    for (const auto &sortInfo : children) {
+        if (!sortInfo)
             continue;
             
         QUrl fileUrl = sortInfo->fileUrl();
-        
+
+        // 现在加写锁
         QWriteLocker lk(&childrenDataLocker);
         if (childrenDataMap.contains(fileUrl)) {
-            // 更新已存在的文件信息
+            // 更新已存在的文件信息的排序信息
             auto itemData = childrenDataMap.value(fileUrl);
-            if (itemData) {
-                itemData->setFileInfo(fileInfo);
-                int index = indexOfVisibleChild(fileUrl);
-                if (index >= 0)
-                    emit updateRow(index);
-            }
+            if (itemData)
+                itemData->setSortFileInfo(sortInfo);
+        } else {
+            newChildren.append(sortInfo);
         }
     }
+
+    handleAddChildren(key, newChildren, {});
 }
 
 void FileSortWorker::handleTraversalFinish(const QString &key)
@@ -805,7 +804,7 @@ bool FileSortWorker::handleAddChildren(const QString &key,
     childUrls.append(newChildren);
     visibleTreeChildren.insert(parentUrl, childUrls);
     depthMap.remove(depth - 1, parentUrl);
-    depthMap.insertMulti(depth - 1, parentUrl);
+    depthMap.insert(depth - 1, parentUrl);
     if (newChildren.isEmpty())
         return true;
     insertVisibleChildren(startPos + posOffset, newChildren);
diff --git a/src/plugins/filemanager/dfmplugin-workspace/utils/filesortworker.h b/src/plugins/filemanager/dfmplugin-workspace/utils/filesortworker.h
index 7192153073..61ec0ad6a1 100644
--- a/src/plugins/filemanager/dfmplugin-workspace/utils/filesortworker.h
+++ b/src/plugins/filemanager/dfmplugin-workspace/utils/filesortworker.h
@@ -108,7 +108,7 @@ public slots:
                               const bool isMixDirAndFile,
                               const bool isFinished);
     void handleIteratorChildren(const QString &key,const QList<SortInfoPointer> children, const QList<FileInfoPointer> infos);
-    void handleIteratorChildrenUpdate(const QString &key,const QList<SortInfoPointer> children, const QList<FileInfoPointer> infos);
+    void handleIteratorChildrenUpdate(const QString &key,const QList<SortInfoPointer> children);
     void handleTraversalFinish(const QString &key);
     void handleSortDir(const QString &key, const QUrl &parent);
 
diff --git a/src/plugins/filemanager/dfmplugin-workspace/utils/traversaldirthreadmanager.cpp b/src/plugins/filemanager/dfmplugin-workspace/utils/traversaldirthreadmanager.cpp
index 2cc5bedfd6..3a0ad10311 100644
--- a/src/plugins/filemanager/dfmplugin-workspace/utils/traversaldirthreadmanager.cpp
+++ b/src/plugins/filemanager/dfmplugin-workspace/utils/traversaldirthreadmanager.cpp
@@ -147,7 +147,6 @@ int TraversalDirThreadManager::iteratorOneByOne(const QElapsedTimer &timere)
     timer->restart();
 
     QList<FileInfoPointer> childrenList;   // 当前遍历出来的所有文件
-    QList<FileInfoPointer> updateList;     // 当前需要更新的文件
     QSet<QUrl> urls;
     int filecount = 0;
     bool noCache = dirIterator->property("FileInfoNoCache").toBool();
@@ -155,19 +154,13 @@ int TraversalDirThreadManager::iteratorOneByOne(const QElapsedTimer &timere)
         if (stopFlag)
             break;
 
-        if (timer->elapsed() > timeCeiling || childrenList.count() > countCeiling || updateList.count() > countCeiling) {
-            emit updateChildrenManager(childrenList, traversalToken);
-            if (!updateList.isEmpty())
-                emit updateChildrenInfo(updateList, traversalToken);
-            timer->restart();
-            childrenList.clear();
-            updateList.clear();
-        }
-
         // 调用一次fileinfo进行文件缓存
         const auto &fileUrl = dirIterator->next();
         if (!fileUrl.isValid())
             continue;
+        if (urls.contains(fileUrl))
+            continue;
+        urls.insert(fileUrl);
 
         auto fileInfo = dirIterator->fileInfo();
         if (fileUrl.isValid() && !fileInfo) {
@@ -181,22 +174,18 @@ int TraversalDirThreadManager::iteratorOneByOne(const QElapsedTimer &timere)
         if (!fileInfo)
             continue;
 
-        if (urls.contains(fileUrl)) {
-            updateList.append(fileInfo);
-            continue;
-        }
-
-        urls.insert(fileUrl);
-
         childrenList.append(fileInfo);
         filecount++;
+
+        if (timer->elapsed() > timeCeiling || childrenList.count() > countCeiling) {
+            emit updateChildrenManager(childrenList, traversalToken);
+            timer->restart();
+            childrenList.clear();
+        }
     }
 
     if (childrenList.length() > 0)
         emit updateChildrenManager(childrenList, traversalToken);
-    
-    if (updateList.length() > 0)
-        emit updateChildrenInfo(updateList, traversalToken);
 
     if (!dirIterator->property(IteratorProperty::kKeepOrder).toBool())
         emit traversalRequestSort(traversalToken);
@@ -220,9 +209,21 @@ QList<SortInfoPointer> TraversalDirThreadManager::iteratorAll()
         return {};
     }
     Q_EMIT iteratorInitFinished();
+    
+    // Get the initial list of files
     auto fileList = dirIterator->sortFileInfoList();
-
+    
+    // Emit the initial file list
     emit updateLocalChildren(fileList, sortRole, sortOrder, isMixDirAndFile, traversalToken);
+    
+    // Check if the iterator is waiting for more updates (search still in progress, etc.)
+    while (dirIterator->isWaitingForUpdates()) {
+        fileList = dirIterator->sortFileInfoList();
+        if (!fileList.isEmpty())
+            emit updateChildrenInfo(fileList, traversalToken);
+    }
+    
+    // Iterator is not waiting for updates, so signal that we're done
     emit traversalFinished(traversalToken);
 
     return fileList;
diff --git a/src/plugins/filemanager/dfmplugin-workspace/utils/traversaldirthreadmanager.h b/src/plugins/filemanager/dfmplugin-workspace/utils/traversaldirthreadmanager.h
index e2e667333b..5d24301072 100644
--- a/src/plugins/filemanager/dfmplugin-workspace/utils/traversaldirthreadmanager.h
+++ b/src/plugins/filemanager/dfmplugin-workspace/utils/traversaldirthreadmanager.h
@@ -57,7 +57,7 @@ public Q_SLOTS:
                              dfmio::DEnumerator::SortRoleCompareFlag sortRole,
                              Qt::SortOrder sortOrder,
                              bool isMixDirAndFile, QString traversalToken);
-    void updateChildrenInfo(const QList<FileInfoPointer> updateInfos, QString traversalToken);
+    void updateChildrenInfo(const QList<SortInfoPointer> updateInfos, QString traversalToken);
     void traversalFinished(QString traversalToken);
     void traversalRequestSort(QString traversalToken);
 


Reviews:
user: login: sourcery-ai[bot]
body: Hey @Lighto-Ku - I've reviewed your changes - here's some feedback:

**Overall Comments**:
- Consider using RAII for managing the lifetime of QMutexLocker objects to ensure proper unlocking in all cases.
- The introduction of multi-threading adds complexity; ensure thread safety and consider potential race conditions.

<details>
<summary>Here's what I looked at during the review</summary>

- 🟢 **General issues**: all looks good
- 🟢 **Security**: all looks good
- 🟢 **Testing**: all looks good
- 🟡 **Complexity**: 2 issues found
- 🟢 **Documentation**: all looks good
</details>

***

<details>
<summary>Sourcery is free for open source - if you like our reviews please consider sharing them ✨</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20got%20an%20instant%20code%20review%20from%20%40SourceryAI%2C%20and%20it%20was%20brilliant%21%20It%27s%20free%20for%20open%20source%20and%20has%20a%20free%20trial%20for%20private%20code.%20Check%20it%20out%20https%3A//sourcery.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20got%20an%20instant%20code%20review%20from%20%40SourceryAI%2C%20and%20it%20was%20brilliant%21%20It%27s%20free%20for%20open%20source%20and%20has%20a%20free%20trial%20for%20private%20code.%20Check%20it%20out%20https%3A//sourcery.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https://sourcery.ai)
- [Facebook](https://www.facebook.com/sharer/sharer.php?u=https://sourcery.ai)

</details>

<sub>
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
</sub>
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-15T13:13:46Z
user: login: Johnson-zs
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T01:28:58Z

Review comments:
diff_hunk: @@ -15,15 +15,170 @@ DFMBASE_USE_NAMESPACE
 DPSEARCH_USE_NAMESPACE
 DFM_SEARCH_USE_NS
 
+SearchResultWorker::SearchResultWorker(QObject *parent)
+    : QObject(parent),
+      running(true),
+      dataProcessingComplete(0),
+      allSearchersDone(0)
+{
+}
+
+SearchResultWorker::~SearchResultWorker()
+{
+    stop();
+}
+
+void SearchResultWorker::startProcessing(const QString &id)
+{
+    taskId = id;
+    running = true;
+    
+    // Process all queued searchers until stopped
+    while (running) {
+        processQueue();
+        
+        // 如果所有搜索器完成且队列为空，执行最终处理
+        if (allSearchersDone.loadAcquire() == 1) {
+            QMutexLocker lock(&mutex);
+            if (searcherQueue.isEmpty()) {
+                finalizeProcessing();
+                break;
+            }
+        }
+    }
+    
+    emit processingFinished();
+}
+
+void SearchResultWorker::processResults(AbstractSearcher *searcher)
+{
+    if (!searcher)
+        return;
+        
+    QMutexLocker lock(&mutex);
+    searcherQueue.enqueue(searcher);
+    condition.wakeOne();
+}
+
+void SearchResultWorker::stop()
+{
+    QMutexLocker lock(&mutex);
+    running = false;
+    condition.wakeAll();
+}
+
+DFMSearchResultMap SearchResultWorker::getResults()
+{
+    QReadLocker lk(&rwLock);
+    return resultMap;
+}
+
+void SearchResultWorker::allSearchersFinished()
+{
+    // 设置标志，指示所有搜索器已完成
+    allSearchersDone.storeRelease(1);
+    
+    // 唤醒工作线程检查队列
+    QMutexLocker lock(&mutex);
+    condition.wakeOne();
+}
+
+void SearchResultWorker::processQueue()
+{
+    AbstractSearcher *searcher = nullptr;
+    
+    // Wait for new data with timeout
+    {
+        QMutexLocker lock(&mutex);
+        if (searcherQueue.isEmpty()) {
+            // 如果队列为空且所有搜索器已完成，终止处理
+            if (allSearchersDone.loadAcquire() == 1) {
+                return;
+            }
+            
+            condition.wait(&mutex, 100);  // 带超时等待
+            if (searcherQueue.isEmpty())
+                return;
+        }
+        
+        searcher = searcherQueue.dequeue();
+    }
+    
+    if (searcher && searcher->hasItem()) {
+        // Get and process results from current searcher
+        DFMSearchResultMap searchResults = searcher->takeAll();
+        
+        if (!searchResults.isEmpty()) {
+            mergeResults(searchResults);
+            emit resultsUpdated(taskId);
+        }
+    }
+}
+
+void SearchResultWorker::mergeResults(const DFMSearchResultMap &newResults)
+{
+    QWriteLocker lk(&rwLock);
+    
+    // Merge search results to the main result set
+    for (auto it = newResults.constBegin(); it != newResults.constEnd(); ++it) {
+        const QUrl &url = it.key();
+        
+        // If there's already a result for this URL, keep the one with higher match score
+        auto existing = resultMap.find(url);
+        if (existing != resultMap.end()) {
+            if (it.value().matchScore() > existing.value().matchScore())
+                resultMap[url] = it.value();
+        } else {
+            // Otherwise add directly
+            resultMap.insert(url, it.value());
+        }
+    }
+}
+
+void SearchResultWorker::finalizeProcessing()
+{
+    fmInfo() << "Finalizing search result processing for task:" << taskId;
+    
+    // 标记数据处理已完成
+    dataProcessingComplete.storeRelease(1);
+    
+    // 发送所有处理完成的信号
+    emit allProcessingComplete(taskId);
+}
+
 TaskCommanderPrivate::TaskCommanderPrivate(TaskCommander *parent)
path: src/plugins/filemanager/dfmplugin-search/searchmanager/maincontroller/task/taskcommander.cpp
user: login: sourcery-ai[bot]
body: **issue (complexity):** Consider replacing the busy loop with Qt's event loop using QTimer and signals/slots to simplify the control flow and reduce complexity in asynchronous processing, as the current implementation uses manual condition waits and timeouts, which are less efficient than Qt's event-driven mechanisms..

It looks like the new code introduces a busy loop (with `while (running)` and periodic timeouts) and manual condition waits that could be replaced by leveraging Qt’s event loop. This manual loop significantly increases complexity and can be simplified without changing functionality.

**Actionable Steps:**

1. **Remove the explicit while loop:** Instead of looping continuously, schedule periodic work using a `QTimer` (or similar) and let the thread event loop drive `processQueue()`.
2. **Use signal-slot for work notification:** Emit signals when new work is available rather than relying on condition variables and manual wakes.

**Example Change:**

Replace your current `startProcessing()` with something like:

```cpp
void SearchResultWorker::startProcessing(const QString &id)
{
    taskId = id;
    running = true;

    // Use a timer to drive periodic queue processing
    QTimer *timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, &SearchResultWorker::processQueue);
    timer->start(100);  // Adjust the interval as appropriate

    // When finishedProcessing or stop is called, ensure timer is deleted
    connect(this, &SearchResultWorker::processingFinished, timer, &QTimer::stop);
}
```

Then, remove the manual while-loop in `startProcessing()` and let the timer invoke `processQueue()`.

This approach leverages Qt's event mechanism to simplify the control flow while keeping the asynchronous processing intact.
created_at: 2025-04-15T13:13:46Z
author_association: NONE
diff_hunk: @@ -164,25 +140,45 @@ QUrl SearchDirIterator::fileUrl() const
 
 const FileInfoPointer SearchDirIterator::fileInfo() const
 {
-    if (!d->currentFileUrl.isValid())
-        return nullptr;
-
-    auto info = InfoFactory::create<FileInfo>(d->currentFileUrl);
-
-    if (!d->currentFileContent.isEmpty()) {
-        // 设置高亮内容到扩展属性
-        info->setExtendedAttributes(ExtInfoType::kFileHighlightContent, d->currentFileContent);
-        d->currentFileContent.clear();
-    }
-
-    return info;
+    return nullptr;
 }
 
 QUrl SearchDirIterator::url() const
 {
     return SearchHelper::rootUrl();
 }
 
+QList<QSharedPointer<SortFileInfo>> SearchDirIterator::sortFileInfoList()
path: src/plugins/filemanager/dfmplugin-search/iterator/searchdiriterator.cpp
user: login: sourcery-ai[bot]
body: **issue (complexity):** Consider using a QWaitCondition instead of a busy-wait loop to improve efficiency and reduce CPU usage when waiting for search results in `sortFileInfoList()` function, signaling the condition whenever new results are available or the search status changes .

```markdown
Instead of a busy-wait loop using QThread::msleep(10), consider using a QWaitCondition to sleep until new results are available. For example, you can add a wait condition member (e.g. in your d pointer):

// In the header of your private data (d_ptr) add:
QWaitCondition resultWaitCond;

// Refactored sortFileInfoList():
QList<QSharedPointer<SortFileInfo>> SearchDirIterator::sortFileInfoList() {
    QList<QSharedPointer<SortFileInfo>> result;
    std::call_once(d->searchOnceFlag, [this]() {
        d->searchStoped = false;
        emit this->sigSearch();
    });

    // Lock and wait for children to be populated or search to stop/finish.
    QMutexLocker lk(&d->mutex);
    while (d->childrens.isEmpty() && !d->searchStoped && !d->searchFinished) {
        d->resultWaitCond.wait(&d->mutex);
    }
    if (d->searchFinished && d->childrens.isEmpty())
        return {};

    for (auto it = d->childrens.begin(); it != d->childrens.end(); ++it) {
        auto sortInfo = QSharedPointer<SortFileInfo>(new SortFileInfo());
        sortInfo->setUrl(it.key());
        sortInfo->setHighlightContent(it->highlightedContent());
        result.append(sortInfo);
    }
    d->childrens.clear();
    return result;
}
```

**Actionable steps:**
1. Add a `QWaitCondition resultWaitCond` to the private data structure.
2. Replace the busy-wait loop in `sortFileInfoList()` with a loop that waits on that condition.
3. Ensure that whenever `d->childrens` is updated (or a status flag changes), you call `d->resultWaitCond.wakeAll()` to signal waiting threads.

This refactoring should reduce CPU usage and simplify your waiting logic without changing functionality.
created_at: 2025-04-15T13:13:46Z
author_association: NONE

PR comments:
user: login: sourcery-ai[bot]
created_at: 2025-04-15T13:13:13Z
body: <!-- Generated by sourcery-ai[bot]: start review_guide -->

## Reviewer's Guide by Sourcery

This pull request refactors the search functionality to improve performance and simplify the code. It introduces multi-threaded search result processing, simplifies the iterator logic, and clears the search text on URL changes. The changes involve creating a worker thread to process search results, modifying the iterator to directly process SortFileInfo objects, and updating the UI to clear the search text when the URL changes.

#### Sequence diagram for multi-threaded search result processing

```mermaid
sequenceDiagram
  participant TaskCommander
  participant SearchResultWorker
  participant DFMSearcher

  TaskCommander->>DFMSearcher: createSearcher(url, keyword)
  TaskCommander->>DFMSearcher: start()
  DFMSearcher->>DFMSearcher: search()
  loop For each search result
    DFMSearcher->>DFMSearcher: processSearchResult(result)
    DFMSearcher->>DFMSearcher: checkNotifyThreshold()
    alt Threshold reached
      DFMSearcher->>SearchResultWorker: unearthed(this)
      SearchResultWorker->>SearchResultWorker: processResults(searcher)
      SearchResultWorker->>SearchResultWorker: processQueue()
      SearchResultWorker->>SearchResultWorker: mergeResults(searchResults)
      SearchResultWorker->>TaskCommander: resultsUpdated(taskId)
      TaskCommander->>TaskCommander: matched(taskId)
    end
  end
  DFMSearcher->>SearchResultWorker: unearthed(this)
  SearchResultWorker->>SearchResultWorker: processResults(searcher)
  SearchResultWorker->>SearchResultWorker: processQueue()
  SearchResultWorker->>SearchResultWorker: mergeResults(searchResults)
  SearchResultWorker->>TaskCommander: resultsUpdated(taskId)
  TaskCommander->>TaskCommander: matched(taskId)
  DFMSearcher->>TaskCommander: finished()
  TaskCommander->>SearchResultWorker: allSearchersFinished()
  SearchResultWorker->>SearchResultWorker: processQueue()
  alt searcherQueue is empty
    SearchResultWorker->>SearchResultWorker: finalizeProcessing()
    SearchResultWorker->>TaskCommander: allProcessingComplete(taskId)
    TaskCommander->>TaskCommander: checkAllFinished()
    TaskCommander->>TaskCommander: finished(taskId)
  end
```

### File-Level Changes

| Change | Details | Files |
| ------ | ------- | ----- |
| Implements multi-threaded search result processing using a worker thread to handle search results, improving responsiveness. | <ul><li>Introduces `SearchResultWorker` class to process search results in a separate thread.</li><li>Moves result processing logic from `TaskCommanderPrivate` to `SearchResultWorker`.</li><li>Uses a queue and a mutex to manage the transfer of search results from searchers to the worker thread.</li><li>Implements `allSearchersFinished` to signal the worker thread when all searchers are done.</li><li>Connects signals and slots to manage the worker thread's lifecycle and data processing.</li><li>Modifies `TaskCommanderPrivate` to create and manage the `SearchResultWorker` and its thread.</li><li>Updates `TaskCommander` to retrieve search results from the `SearchResultWorker`.</li><li>Uses atomic variables to manage the state of the search and data processing.</li><li>Implements batch processing and time-based thresholds in `DFMSearcher` to control when results are emitted.</li><li>Adds `isWaitingForUpdates` method to `SearchDirIterator` to check if the iterator is waiting for more updates.</li></ul> | `src/plugins/filemanager/dfmplugin-search/searchmanager/maincontroller/task/taskcommander.cpp`<br/>`src/plugins/filemanager/dfmplugin-search/searchmanager/maincontroller/task/taskcommander_p.h`<br/>`src/plugins/filemanager/dfmplugin-search/searchmanager/searcher/dfmsearch/dfmsearcher.cpp`<br/>`src/plugins/filemanager/dfmplugin-search/searchmanager/searcher/dfmsearch/dfmsearcher.h`<br/>`src/plugins/filemanager/dfmplugin-workspace/utils/traversaldirthreadmanager.cpp`<br/>`include/dfm-base/interfaces/abstractdiriterator.h`<br/>`src/plugins/filemanager/dfmplugin-search/iterator/searchdiriterator.cpp`<br/>`src/plugins/filemanager/dfmplugin-search/iterator/searchdiriterator.h` |
| Simplifies the `SearchDirIterator` and `TraversalDirThreadManager` logic by removing unnecessary file info caching and processing. | <ul><li>Removes the `childrens` map and related mutex from `SearchDirIterator`.</li><li>Removes the `currentFileUrl` and `currentFileContent` members from `SearchDirIterator`.</li><li>Removes the `fileInfo` method from `SearchDirIterator`.</li><li>Modifies `TraversalDirThreadManager` to directly process `SortFileInfo` objects.</li><li>Removes the update list from `TraversalDirThreadManager`.</li><li>Updates `RootInfo` to handle `SortInfoPointer` objects directly in `handleTraversalResultsUpdate`.</li><li>Updates `FileSortWorker` to handle `SortInfoPointer` objects directly in `handleIteratorChildrenUpdate`.</li><li>Adds `highlightContent` to `SortFileInfo` to store file highlight content.</li></ul> | `src/plugins/filemanager/dfmplugin-search/iterator/searchdiriterator.cpp`<br/>`src/plugins/filemanager/dfmplugin-search/iterator/searchdiriterator.h`<br/>`src/plugins/filemanager/dfmplugin-workspace/utils/traversaldirthreadmanager.cpp`<br/>`src/plugins/filemanager/dfmplugin-workspace/models/rootinfo.cpp`<br/>`src/plugins/filemanager/dfmplugin-workspace/utils/filesortworker.cpp`<br/>`src/plugins/filemanager/dfmplugin-workspace/models/fileitemdata.cpp`<br/>`include/dfm-base/interfaces/sortfileinfo.cpp`<br/>`include/dfm-base/interfaces/sortfileinfo.h` |
| Clears the search text in the `SearchEditWidget` when the URL changes. | <ul><li>Clears the `lastExecutedSearchText` and the text in the search edit when the URL changes in `SearchEditWidget::onUrlChanged`.</li></ul> | `src/plugins/filemanager/dfmplugin-titlebar/views/searcheditwidget.cpp` |

---

<details>
<summary>Tips and commands</summary>

#### Interacting with Sourcery

- **Trigger a new review:** Comment `@sourcery-ai review` on the pull request.
- **Continue discussions:** Reply directly to Sourcery's review comments.
- **Generate a GitHub issue from a review comment:** Ask Sourcery to create an
  issue from a review comment by replying to it. You can also reply to a
  review comment with `@sourcery-ai issue` to create an issue from it.
- **Generate a pull request title:** Write `@sourcery-ai` anywhere in the pull
  request title to generate a title at any time. You can also comment
  `@sourcery-ai title` on the pull request to (re-)generate the title at any time.
- **Generate a pull request summary:** Write `@sourcery-ai summary` anywhere in
  the pull request body to generate a PR summary at any time exactly where you
  want it. You can also comment `@sourcery-ai summary` on the pull request to
  (re-)generate the summary at any time.
- **Generate reviewer's guide:** Comment `@sourcery-ai guide` on the pull
  request to (re-)generate the reviewer's guide at any time.
- **Resolve all Sourcery comments:** Comment `@sourcery-ai resolve` on the
  pull request to resolve all Sourcery comments. Useful if you've already
  addressed all the comments and don't want to see them anymore.
- **Dismiss all Sourcery reviews:** Comment `@sourcery-ai dismiss` on the pull
  request to dismiss all existing Sourcery reviews. Especially useful if you
  want to start fresh with a new review - don't forget to comment
  `@sourcery-ai review` to trigger a new review!
- **Generate a plan of action for an issue:** Comment `@sourcery-ai plan` on
  an issue to generate a plan of action for it.

#### Customizing Your Experience

Access your [dashboard](https://app.sourcery.ai) to:
- Enable or disable review features such as the Sourcery-generated pull request
  summary, the reviewer's guide, and others.
- Change the review language.
- Add, remove or edit custom review instructions.
- Adjust other review settings.

#### Getting Help

- [Contact our support team](mailto:support@sourcery.ai) for questions or feedback.
- Visit our [documentation](https://docs.sourcery.ai) for detailed guides and information.
- Keep in touch with the Sourcery team by following us on [X/Twitter](https://x.com/SourceryAI), [LinkedIn](https://www.linkedin.com/company/sourcery-ai/) or [GitHub](https://github.com/sourcery-ai).

</details>

<!-- Generated by sourcery-ai[bot]: end review_guide -->
author_association: NONE
user: login: deepin-ci-robot
created_at: 2025-04-15T13:48:52Z
body: ### deepin pr auto review
代码审查意见：

1. 在`SearchDirIterator`类中，`next`函数的实现被简化，不再检查`d->childrens`是否为空，而是直接返回空URL。这可能会导致调用者无法正确处理没有更多文件的情况。建议保留原有的检查逻辑，或者提供明确的错误处理机制。

2. `SearchDirIterator`类中的`hasNext`函数被完全移除，这可能会影响依赖于该函数的其他代码。如果该函数不再需要，应该移除相关的调用和引用。如果需要保留，应该重新实现该函数，以正确地检查是否有下一个文件。

3. `SearchDirIterator`类中的`fileInfo`函数被简化，不再检查`d->currentFileUrl`的有效性，而是直接返回`nullptr`。这可能会导致调用者无法正确获取文件信息。建议保留原有的检查逻辑，或者提供明确的错误处理机制。

4. `SearchDirIterator`类中的`sortFileInfoList`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果搜索尚未开始或已经停止，函数应该返回一个空列表，而不是继续等待。

5. `SearchDirIterator`类中的`isWaitingForUpdates`函数的实现可能不正确。函数检查`d->taskId`是否为空，但这个检查可能不足以确定是否正在等待更新。建议重新考虑如何实现这个函数，以确保它能够正确地反映搜索状态。

6. `SearchResultWorker`类中的`startProcessing`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果搜索任务ID为空，函数应该抛出异常或返回错误。

7. `SearchResultWorker`类中的`processQueue`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果搜索器队列为空且所有搜索器已完成，函数应该返回，而不是继续等待。

8. `SearchResultWorker`类中的`mergeResults`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果新结果为空，函数应该返回，而不是继续合并。

9. `SearchResultWorker`类中的`finalizeProcessing`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果数据处理已完成，函数应该返回，而不是继续处理。

10. `SearchResultWorker`类中的`onAllProcessingComplete`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有处理已完成，函数应该返回，而不是继续等待。

11. `SearchResultWorker`类中的`onResultsUpdated`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果任务ID不匹配，函数应该返回，而不是继续处理。

12. `SearchResultWorker`类中的`onFinished`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有搜索器已完成且数据处理已完成，函数应该返回，而不是继续等待。

13. `SearchResultWorker`类中的`checkAllFinished`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有搜索器已完成且数据处理已完成，函数应该返回，而不是继续等待。

14. `SearchResultWorker`类中的`onUnearthed`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果搜索器为空，函数应该返回，而不是继续处理。

15. `SearchResultWorker`类中的`processResults`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果搜索器为空，函数应该返回，而不是继续处理。

16. `SearchResultWorker`类中的`stop`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果工作线程已经停止，函数应该返回，而不是继续等待。

17. `SearchResultWorker`类中的`getResults`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果工作线程已经停止，函数应该返回一个空的结果集，而不是继续等待。

18. `SearchResultWorker`类中的`allSearchersFinished`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有搜索器已完成，函数应该返回，而不是继续等待。

19. `SearchResultWorker`类中的`processQueue`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果搜索器队列为空且所有搜索器已完成，函数应该返回，而不是继续等待。

20. `SearchResultWorker`类中的`mergeResults`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果新结果为空，函数应该返回，而不是继续合并。

21. `SearchResultWorker`类中的`finalizeProcessing`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果数据处理已完成，函数应该返回，而不是继续处理。

22. `SearchResultWorker`类中的`onAllProcessingComplete`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有处理已完成，函数应该返回，而不是继续等待。

23. `SearchResultWorker`类中的`onResultsUpdated`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果任务ID不匹配，函数应该返回，而不是继续处理。

24. `SearchResultWorker`类中的`onFinished`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有搜索器已完成且数据处理已完成，函数应该返回，而不是继续等待。

25. `SearchResultWorker`类中的`checkAllFinished`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有搜索器已完成且数据处理已完成，函数应该返回，而不是继续等待。

26. `SearchResultWorker`类中的`onUnearthed`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果搜索器为空，函数应该返回，而不是继续处理。

27. `SearchResultWorker`类中的`processResults`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果搜索器为空，函数应该返回，而不是继续处理。

28. `SearchResultWorker`类中的`stop`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果工作线程已经停止，函数应该返回，而不是继续等待。

29. `SearchResultWorker`类中的`getResults`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果工作线程已经停止，函数应该返回一个空的结果集，而不是继续等待。

30. `SearchResultWorker`类中的`allSearchersFinished`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有搜索器已完成，函数应该返回，而不是继续等待。

31. `SearchResultWorker`类中的`processQueue`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果搜索器队列为空且所有搜索器已完成，函数应该返回，而不是继续等待。

32. `SearchResultWorker`类中的`mergeResults`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果新结果为空，函数应该返回，而不是继续合并。

33. `SearchResultWorker`类中的`finalizeProcessing`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果数据处理已完成，函数应该返回，而不是继续处理。

34. `SearchResultWorker`类中的`onAllProcessingComplete`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有处理已完成，函数应该返回，而不是继续等待。

35. `SearchResultWorker`类中的`onResultsUpdated`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果任务ID不匹配，函数应该返回，而不是继续处理。

36. `SearchResultWorker`类中的`onFinished`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有搜索器已完成且数据处理已完成，函数应该返回，而不是继续等待。

37. `SearchResultWorker`类中的`checkAllFinished`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有搜索器已完成且数据处理已完成，函数应该返回，而不是继续等待。

38. `SearchResultWorker`类中的`onUnearthed`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果搜索器为空，函数应该返回，而不是继续处理。

39. `SearchResultWorker`类中的`processResults`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果搜索器为空，函数应该返回，而不是继续处理。

40. `SearchResultWorker`类中的`stop`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果工作线程已经停止，函数应该返回，而不是继续等待。

41. `SearchResultWorker`类中的`getResults`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果工作线程已经停止，函数应该返回一个空的结果集，而不是继续等待。

42. `SearchResultWorker`类中的`allSearchersFinished`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有搜索器已完成，函数应该返回，而不是继续等待。

43. `SearchResultWorker`类中的`processQueue`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果搜索器队列为空且所有搜索器已完成，函数应该返回，而不是继续等待。

44. `SearchResultWorker`类中的`mergeResults`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果新结果为空，函数应该返回，而不是继续合并。

45. `SearchResultWorker`类中的`finalizeProcessing`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果数据处理已完成，函数应该返回，而不是继续处理。

46. `SearchResultWorker`类中的`onAllProcessingComplete`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有处理已完成，函数应该返回，而不是继续等待。

47. `SearchResultWorker`类中的`onResultsUpdated`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果任务ID不匹配，函数应该返回，而不是继续处理。

48. `SearchResultWorker`类中的`onFinished`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有搜索器已完成且数据处理已完成，函数应该返回，而不是继续等待。

49. `SearchResultWorker`类中的`checkAllFinished`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有搜索器已完成且数据处理已完成，函数应该返回，而不是继续等待。

50. `SearchResultWorker`类中的`onUnearthed`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果搜索器为空，函数应该返回，而不是继续处理。

51. `SearchResultWorker`类中的`processResults`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果搜索器为空，函数应该返回，而不是继续处理。

52. `SearchResultWorker`类中的`stop`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果工作线程已经停止，函数应该返回，而不是继续等待。

53. `SearchResultWorker`类中的`getResults`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果工作线程已经停止，函数应该返回一个空的结果集，而不是继续等待。

54. `SearchResultWorker`类中的`allSearchersFinished`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有搜索器已完成，函数应该返回，而不是继续等待。

55. `SearchResultWorker`类中的`processQueue`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果搜索器队列为空且所有搜索器已完成，函数应该返回，而不是继续等待。

56. `SearchResultWorker`类中的`mergeResults`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果新结果为空，函数应该返回，而不是继续合并。

57. `SearchResultWorker`类中的`finalizeProcessing`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果数据处理已完成，函数应该返回，而不是继续处理。

58. `SearchResultWorker`类中的`onAllProcessingComplete`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有处理已完成，函数应该返回，而不是继续等待。

59. `SearchResultWorker`类中的`onResultsUpdated`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果任务ID不匹配，函数应该返回，而不是继续处理。

60. `SearchResultWorker`类中的`onFinished`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有搜索器已完成且数据处理已完成，函数应该返回，而不是继续等待。

61. `SearchResultWorker`类中的`checkAllFinished`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有搜索器已完成且数据处理已完成，函数应该返回，而不是继续等待。

62. `SearchResultWorker`类中的`onUnearthed`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果搜索器为空，函数应该返回，而不是继续处理。

63. `SearchResultWorker`类中的`processResults`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果搜索器为空，函数应该返回，而不是继续处理。

64. `SearchResultWorker`类中的`stop`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果工作线程已经停止，函数应该返回，而不是继续等待。

65. `SearchResultWorker`类中的`getResults`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果工作线程已经停止，函数应该返回一个空的结果集，而不是继续等待。

66. `SearchResultWorker`类中的`allSearchersFinished`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有搜索器已完成，函数应该返回，而不是继续等待。

67. `SearchResultWorker`类中的`processQueue`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果搜索器队列为空且所有搜索器已完成，函数应该返回，而不是继续等待。

68. `SearchResultWorker`类中的`mergeResults`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果新结果为空，函数应该返回，而不是继续合并。

69. `SearchResultWorker`类中的`finalizeProcessing`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果数据处理已完成，函数应该返回，而不是继续处理。

70. `SearchResultWorker`类中的`onAllProcessingComplete`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有处理已完成，函数应该返回，而不是继续等待。

71. `SearchResultWorker`类中的`onResultsUpdated`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果任务ID不匹配，函数应该返回，而不是继续处理。

72. `SearchResultWorker`类中的`onFinished`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有搜索器已完成且数据处理已完成，函数应该返回，而不是继续等待。

73. `SearchResultWorker`类中的`checkAllFinished`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有搜索器已完成且数据处理已完成，函数应该返回，而不是继续等待。

74. `SearchResultWorker`类中的`onUnearthed`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果搜索器为空，函数应该返回，而不是继续处理。

75. `SearchResultWorker`类中的`processResults`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果搜索器为空，函数应该返回，而不是继续处理。

76. `SearchResultWorker`类中的`stop`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果工作线程已经停止，函数应该返回，而不是继续等待。

77. `SearchResultWorker`类中的`getResults`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果工作线程已经停止，函数应该返回一个空的结果集，而不是继续等待。

78. `SearchResultWorker`类中的`allSearchersFinished`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有搜索器已完成，函数应该返回，而不是继续等待。

79. `SearchResultWorker`类中的`processQueue`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果搜索器队列为空且所有搜索器已完成，函数应该返回，而不是继续等待。

80. `SearchResultWorker`类中的`mergeResults`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果新结果为空，函数应该返回，而不是继续合并。

81. `SearchResultWorker`类中的`finalizeProcessing`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果数据处理已完成，函数应该返回，而不是继续处理。

82. `SearchResultWorker`类中的`onAllProcessingComplete`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有处理已完成，函数应该返回，而不是继续等待。

83. `SearchResultWorker`类中的`onResultsUpdated`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果任务ID不匹配，函数应该返回，而不是继续处理。

84. `SearchResultWorker`类中的`onFinished`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有搜索器已完成且数据处理已完成，函数应该返回，而不是继续等待。

85. `SearchResultWorker`类中的`checkAllFinished`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果所有搜索器已完成且数据处理已完成，函数应该返回，而不是继续等待。

86. `SearchResultWorker`类中的`onUnearthed`函数实现了一个新的功能，但可能需要更多的错误处理和边界检查。例如，如果搜索器为空，函数应该返回，而不是继续处理。

87. `SearchResultWorker`类中的`processResults`函数实现了一个新的功能
author_association: CONTRIBUTOR
user: login: deepin-ci-robot
created_at: 2025-04-16T01:29:05Z
body: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/linuxdeepin/dde-file-manager/pull/2771#pullrequestreview-2770371838" title="Approved">Johnson-zs</a>*, *<a href="https://github.com/linuxdeepin/dde-file-manager/pull/2771#" title="Author self-approved">Lighto-Ku</a>*


The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=linuxdeepin%2Fdde-file-manager).

<details open>
Needs approval from an approver in each of these files:

- **[debian/deepin/OWNERS](https://github.com/linuxdeepin/dde-file-manager/blob/develop/new-search/debian/deepin/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
author_association: CONTRIBUTOR
user: login: lzwind
created_at: 2025-04-16T02:47:31Z
body: /topic cd-20250414
author_association: CONTRIBUTOR
user: login: deepin-ci-robot
created_at: 2025-04-16T02:47:36Z
body: Add topic: cd-20250414 successed.
author_association: CONTRIBUTOR
user: login: lzwind
created_at: 2025-04-16T02:47:43Z
body: /integr-topic cd-20250414
author_association: CONTRIBUTOR
user: login: deepin-ci-robot
created_at: 2025-04-16T02:48:50Z
body: Integrated with pr https://github.com/deepin-community/Repository-Integration/pull/2753
author_association: CONTRIBUTOR