Skip to content

Commit

Permalink
feat: add full-text search status widget
Browse files Browse the repository at this point in the history
- Add CheckBoxWidthTextIndex widget for full-text search settings
- Add TextIndexStatusBar to display indexing progress and status
- Add task progress tracking and status persistence
- Refactor settings dialog widget registration mechanism
- Remove /root from index skip list

This change improves the full-text search user experience by adding
visual feedback for indexing status and progress.

Log:
  • Loading branch information
Johnson-zs committed Nov 30, 2024
1 parent 7a60b1b commit 763e8f9
Show file tree
Hide file tree
Showing 16 changed files with 356 additions and 14 deletions.
4 changes: 4 additions & 0 deletions src/dfm-base/dialogs/settingsdialog/settingdialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,10 @@ SettingDialog::SettingDialog(QWidget *parent)
: DSettingsDialog(parent)
{
parentWid = FMWindowsIns.findWindowId(parent);
}

void SettingDialog::initialze()
{
// TODO(xust): move to server plugin.
widgetFactory()->registerWidget("mountCheckBox", &SettingDialog::createAutoMountCheckBox);
widgetFactory()->registerWidget("openCheckBox", &SettingDialog::createAutoMountOpenCheckBox);
Expand Down
1 change: 1 addition & 0 deletions src/dfm-base/dialogs/settingsdialog/settingdialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ class SettingDialog : public DSettingsDialog
{
public:
explicit SettingDialog(QWidget *parent = nullptr);
void initialze();
static void setItemVisiable(const QString &key, bool visiable);

private:
Expand Down
20 changes: 19 additions & 1 deletion src/dfm-base/utils/dialogmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,12 @@ void DialogManager::addTask(const JobHandlePointer task)
taskdialog->addTask(task);
}

void DialogManager::registerSettingWidget(const QString &viewType,
std::function<DSettingsWidgetFactory::WidgetCreateHandler> handler)
{
settingWidgetCreators[viewType] = handler;
}

void DialogManager::showSetingsDialog(FileManagerWindow *window)
{
Q_ASSERT(window);
Expand All @@ -267,9 +273,21 @@ void DialogManager::showSetingsDialog(FileManagerWindow *window)
qCWarning(logDFMBase) << "isSettingDialogShown true";
return;
}

window->setProperty("isSettingDialogShown", true);
DSettingsDialog *dsd = new SettingDialog(window);
SettingDialog *dsd = new SettingDialog(window);

// 在初始化前注册所有缓存的自定义控件创建器
auto factory = dsd->widgetFactory();
for (auto iter = settingWidgetCreators.constBegin();
iter != settingWidgetCreators.constEnd();
++iter) {
factory->registerWidget(iter.key(), iter.value());
}

dsd->initialze();
dsd->show();

connect(dsd, &DSettingsDialog::finished, [window] {
window->setProperty("isSettingDialogShown", false);
});
Expand Down
11 changes: 10 additions & 1 deletion src/dfm-base/utils/dialogmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@

#include <dfm-mount/base/dmount_global.h>

#include <QObject>
#include <DSettingsWidgetFactory>
#include <DDialog>

#include <QObject>

using namespace DTK_NAMESPACE::Widget;

namespace dfmbase {
Expand Down Expand Up @@ -81,6 +83,10 @@ class DialogManager : public QObject
int showAskIfAddExcutableFlagAndRunDialog();
void showDeleteSystemPathWarnDialog(quint64 winId);

// 注册自定义控件创建器
void registerSettingWidget(const QString &viewType,
std::function<DSettingsWidgetFactory::WidgetCreateHandler> handler);

private:
explicit DialogManager(QObject *parent = nullptr);
~DialogManager();
Expand All @@ -89,6 +95,9 @@ class DialogManager : public QObject
QIcon infoIcon;
QIcon warningIcon;
QIcon errorIcon;

// 存储自定义控件创建器的映射
QMap<QString, std::function<DSettingsWidgetFactory::WidgetCreateHandler>> settingWidgetCreators;
};

}
Expand Down
11 changes: 8 additions & 3 deletions src/plugins/filemanager/dfmplugin-search/search.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <dfm-base/settingdialog/settingjsongenerator.h>
#include <dfm-base/base/configs/settingbackend.h>
#include <dfm-base/base/configs/dconfig/dconfigmanager.h>
#include <dfm-base/utils/dialogmanager.h>

using CreateTopWidgetCallback = std::function<QWidget *()>;
using ShowTopWidgetCallback = std::function<bool(QWidget *, const QUrl &)>;
Expand Down Expand Up @@ -145,9 +146,13 @@ void Search::regSearchSettingConfig()
});
}

SettingJsonGenerator::instance()->addCheckBoxConfig(SearchSettings::kFulltextSearch,
tr("Full-Text search"),
false);
QString textIndexKey { SearchSettings::kFulltextSearch };
DialogManager::instance()->registerSettingWidget("checkBoxWidthTextIndex", &SearchHelper::createCheckBoxWidthTextIndex);
SettingJsonGenerator::instance()->addConfig(SearchSettings::kFulltextSearch,
{ { "key", textIndexKey.mid(textIndexKey.lastIndexOf(".") + 1) },
{ "text", tr("Full-Text search") },
{ "type", "checkBoxWidthTextIndex" },
{ "default", false } });
SettingJsonGenerator::instance()->addCheckBoxConfig(SearchSettings::kDisplaySearchHistory,
tr("Display search history"),
true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,3 @@ void MainController::onFinished(QString taskId)

emit searchCompleted(taskId);
}

void MainController::onIndexFullTextSearchChanged(bool enable)
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ class MainController : public QObject

private slots:
void onFinished(QString taskId);
void onIndexFullTextSearchChanged(bool enable);

signals:
void matched(QString taskId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ void SearchManager::onDConfigValueChanged(const QString &config, const QString &
data.insert("mode", enabled ? SearchReportData::kTurnOn : SearchReportData::kTurnOff);
dpfSignalDispatcher->publish("dfmplugin_search", "signal_ReportLog_Commit", QString("Search"), data);

if (mainController)
mainController->onIndexFullTextSearchChanged(enabled);
emit enableFullTextSearchChanged(enabled);
}

SearchManager::SearchManager(QObject *parent)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public Q_SLOTS:
void matched(const QString &taskId);
void searchCompleted(const QString &taskId);
void searchStoped(const QString &taskId);
void enableFullTextSearchChanged(bool enable);

void fileAdd(const QUrl &url);
void fileDelete(const QUrl &url);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
// SPDX-FileCopyrightText: 2024 - 2027 UnionTech Software Technology Co., Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later
#include "checkboxwidthtextindex.h"

#include "utils/textindexclient.h"
#include "searchmanager/searchmanager.h"

#include <QVBoxLayout>
#include <QJsonDocument>
#include <QJsonObject>
#include <QFile>
#include <QStandardPaths>

namespace dfmplugin_search {

TextIndexStatusBar::TextIndexStatusBar(QWidget *parent)
: QWidget { parent }
{
setContentsMargins(4, 0, 0, 0);

// 创建水平布局
QHBoxLayout *layout = new QHBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(5);
setLayout(layout);

// 创建控件
spinner = new DTK_NAMESPACE::Widget::DSpinner(this);
spinner->setFixedSize(16, 16);

iconLabel = new DTK_NAMESPACE::Widget::DTipLabel("", this);
iconLabel->setFixedSize(16, 16);
iconLabel->setPixmap(QIcon::fromTheme("dialog-ok").pixmap(16, 16));

msgLabel = new DTK_NAMESPACE::Widget::DTipLabel("", this);
msgLabel->setAlignment(Qt::AlignLeft);
msgLabel->setWordWrap(true);

// 添加到布局
layout->addWidget(spinner);
layout->addWidget(iconLabel);
layout->addWidget(msgLabel, 1);
layout->addStretch();

// 初始状态
spinner->hide();
iconLabel->show();
hide();
}

void TextIndexStatusBar::setRunning(bool running)
{
if (running) {
spinner->show();
spinner->start();
iconLabel->hide();
} else {
spinner->hide();
spinner->stop();
iconLabel->show();
}
}

void TextIndexStatusBar::setStatus(Status status, const QVariant &data)
{
currentStatus = status;

switch (status) {
case Status::Indexing:
setRunning(true);
updateIndexingProgress(data.toLongLong());
break;
case Status::Completed: {
setRunning(false);
QString lastTime = getLastUpdateTime();
msgLabel->setText(tr("Index update completed, last update time: %1").arg(lastTime));
iconLabel->setPixmap(QIcon::fromTheme("dialog-ok").pixmap(16, 16));
break;
}
case Status::Failed:
setRunning(false);
msgLabel->setText(tr("Index update failed, please turn on the \"Full-Text search\" switch again"));
iconLabel->setPixmap(QIcon::fromTheme("dialog-error").pixmap(16, 16));
break;
case Status::Hidden:
hide();
break;
}
}

void TextIndexStatusBar::updateIndexingProgress(qlonglong count)
{
if (currentStatus == Status::Indexing) {
msgLabel->setText(tr("Building index, %1 files indexed").arg(count));
}
}

QString TextIndexStatusBar::getLastUpdateTime()
{
static const QString kPath = QStandardPaths::standardLocations(QStandardPaths::ConfigLocation).first()
+ "/deepin/dde-file-manager/index";
// 读取 index_status.json
QFile file(kPath + "/index_status.json");
if (!file.open(QIODevice::ReadOnly)) {
return QString();
}

QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
file.close();

if (doc.isObject()) {
QJsonObject obj = doc.object();
if (obj.contains("lastUpdateTime")) {
QDateTime time = QDateTime::fromString(obj["lastUpdateTime"].toString(), Qt::ISODate);
return time.toString("yyyy-MM-dd hh:mm:ss");
}
}
return QString();
}

TextIndexStatusBar::Status TextIndexStatusBar::status() const
{
return currentStatus;
}

CheckBoxWidthTextIndex::CheckBoxWidthTextIndex(QWidget *parent)
: QWidget { parent }
{
setContentsMargins(0, 0, 0, 0);
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
setLayout(layout);

checkBox = new QCheckBox(this);
statusBar = new TextIndexStatusBar(this);
layout->addWidget(checkBox);
layout->addWidget(statusBar);

connect(checkBox, &QCheckBox::stateChanged, this, [this](int state) {
if (state == Qt::Checked) {
statusBar->show();
auto client = TextIndexClient::instance();
auto running = client->hasRunningRootTask();
if (running.has_value()) {
if (running.value()) {
statusBar->setStatus(TextIndexStatusBar::Status::Indexing);
} else {
QString lastTime = statusBar->getLastUpdateTime();
statusBar->setStatus(lastTime.isEmpty() ? TextIndexStatusBar::Status::Failed : TextIndexStatusBar::Status::Completed);
}
}
} else {
statusBar->setStatus(TextIndexStatusBar::Status::Hidden);
}
emit stateChanged(state);
});

auto client = TextIndexClient::instance();
connect(client, &TextIndexClient::taskProgressChanged,
this, [this](TextIndexClient::TaskType type, const QString &path, qlonglong count) {
fmDebug() << "Index task changed:" << type << path << count;
if (checkBox->isChecked() && path == "/") {
if (statusBar->status() != TextIndexStatusBar::Status::Indexing) {
statusBar->setStatus(TextIndexStatusBar::Status::Indexing);
}
statusBar->updateIndexingProgress(count);
}
});

connect(client, &TextIndexClient::taskFinished,
this, [this](TextIndexClient::TaskType type, const QString &path, bool success) {
if (checkBox->isChecked() && path == "/") {
statusBar->setStatus(success ? TextIndexStatusBar::Status::Completed : TextIndexStatusBar::Status::Failed);
}
});

connect(SearchManager::instance(), &SearchManager::enableFullTextSearchChanged,
this, [this](bool enable) {
setChecked(enable);
});
}

void CheckBoxWidthTextIndex::setDisplayText(const QString &text)
{
if (checkBox)
checkBox->setText(text);
}

void CheckBoxWidthTextIndex::setChecked(bool checked)
{
if (checkBox)
checkBox->setChecked(checked);
}

} // namespace dfmplugin_search
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// SPDX-FileCopyrightText: 2024 - 2027 UnionTech Software Technology Co., Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef CHECKBOXWIDTHTEXTINDEX_H
#define CHECKBOXWIDTHTEXTINDEX_H

#include <DTipLabel>
#include <DSpinner>

#include <QCheckBox>

namespace dfmplugin_search {

class TextIndexStatusBar : public QWidget
{
Q_OBJECT

public:
enum class Status {
Indexing, // 正在更新
Completed, // 更新完成
Failed, // 更新失败
Hidden // 隐藏状态
};

explicit TextIndexStatusBar(QWidget *parent = nullptr);
void setStatus(Status status, const QVariant &data = QVariant());
void updateIndexingProgress(qlonglong count);
void setRunning(bool running);
QString getLastUpdateTime();
Status status() const;

private:
Status currentStatus { Status::Hidden };
DTK_NAMESPACE::Widget::DSpinner *spinner { nullptr };
DTK_NAMESPACE::Widget::DTipLabel *iconLabel { nullptr };
DTK_NAMESPACE::Widget::DTipLabel *msgLabel { nullptr };
};

class CheckBoxWidthTextIndex : public QWidget
{
Q_OBJECT
public:
explicit CheckBoxWidthTextIndex(QWidget *parent = nullptr);
void setDisplayText(const QString &text);
void setChecked(bool checked);

Q_SIGNALS:
void stateChanged(int);

private:
QCheckBox *checkBox { nullptr };
TextIndexStatusBar *statusBar { nullptr };
};
} // namespace dfmplugin_search
#endif // CHECKBOXWIDTHTEXTINDEX_H
Loading

0 comments on commit 763e8f9

Please sign in to comment.