aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSaturneric <[email protected]>2022-05-13 17:43:56 +0000
committerSaturneric <[email protected]>2022-05-13 17:43:56 +0000
commit93ac14374580d6a173b83bef0dba0ff73ff77f5a (patch)
treedb4926fd694f660c48d2e18bb2bf6eaa4aaeae6d
parentperf: improve core performance (diff)
downloadGpgFrontend-93ac14374580d6a173b83bef0dba0ff73ff77f5a.tar.gz
GpgFrontend-93ac14374580d6a173b83bef0dba0ff73ff77f5a.zip
feat: add a simple TaskRunner system
1. solve multiple threads problem.
-rw-r--r--src/core/thread/CtxCheckTask.cpp (renamed from src/core/thread/CtxCheckThread.cpp)8
-rw-r--r--src/core/thread/CtxCheckTask.h (renamed from src/core/thread/CtxCheckThread.h)11
-rw-r--r--src/core/thread/FileReadTask.cpp88
-rw-r--r--src/core/thread/FileReadTask.h (renamed from src/ui/thread/FileReadThread.h)46
-rw-r--r--src/core/thread/Task.cpp74
-rw-r--r--src/core/thread/Task.h113
-rw-r--r--src/core/thread/TaskRunner.cpp66
-rw-r--r--src/core/thread/TaskRunner.h75
-rw-r--r--src/core/thread/TaskRunnerGetter.cpp46
-rw-r--r--src/core/thread/TaskRunnerGetter.h56
-rw-r--r--src/main.cpp1
-rw-r--r--src/ui/GpgFrontendUIInit.cpp27
-rw-r--r--src/ui/UserInterfaceUtils.cpp67
-rw-r--r--src/ui/thread/FileReadThread.cpp87
-rw-r--r--src/ui/widgets/KeyList.cpp24
-rw-r--r--src/ui/widgets/PlainTextEditorPage.cpp60
-rw-r--r--src/ui/widgets/PlainTextEditorPage.h31
-rw-r--r--src/ui/widgets/TextEdit.cpp4
18 files changed, 655 insertions, 229 deletions
diff --git a/src/core/thread/CtxCheckThread.cpp b/src/core/thread/CtxCheckTask.cpp
index edec8855..ee170fbc 100644
--- a/src/core/thread/CtxCheckThread.cpp
+++ b/src/core/thread/CtxCheckTask.cpp
@@ -24,20 +24,20 @@
*
*/
-#include "core/thread/CtxCheckThread.h"
+#include "core/thread/CtxCheckTask.h"
#include "core/GpgContext.h"
#include "core/GpgCoreInit.h"
#include "core/common/CoreCommonUtil.h"
#include "core/function/gpg/GpgKeyGetter.h"
-GpgFrontend::CtxCheckThread::CtxCheckThread() : QThread(nullptr) {
- connect(this, &CtxCheckThread::SignalGnupgNotInstall,
+GpgFrontend::Thread::CtxCheckTask::CtxCheckTask() {
+ connect(this, &CtxCheckTask::SignalGnupgNotInstall,
CoreCommonUtil::GetInstance(),
&CoreCommonUtil::SignalGnupgNotInstall);
}
-void GpgFrontend::CtxCheckThread::run() {
+void GpgFrontend::Thread::CtxCheckTask::Run() {
// init logging
init_logging();
diff --git a/src/core/thread/CtxCheckThread.h b/src/core/thread/CtxCheckTask.h
index c597141f..06ddfd82 100644
--- a/src/core/thread/CtxCheckThread.h
+++ b/src/core/thread/CtxCheckTask.h
@@ -28,20 +28,21 @@
#define GPGFRONTEND_CTXCHECKTRHEAD_H
#include "core/GpgFrontendCore.h"
+#include "core/thread/Task.h"
-namespace GpgFrontend {
+namespace GpgFrontend::Thread {
/**
* @brief
*
*/
-class GPGFRONTEND_CORE_EXPORT CtxCheckThread : public QThread {
+class GPGFRONTEND_CORE_EXPORT CtxCheckTask : public Task {
Q_OBJECT
public:
/**
* @brief Construct a new Ctx Check Thread object
*
*/
- CtxCheckThread();
+ CtxCheckTask();
signals:
/**
@@ -55,8 +56,8 @@ class GPGFRONTEND_CORE_EXPORT CtxCheckThread : public QThread {
* @brief
*
*/
- void run() override;
+ void Run() override;
};
-} // namespace GpgFrontend
+} // namespace GpgFrontend::Thread
#endif // GPGFRONTEND_CTXCHECKTRHEAD_H
diff --git a/src/core/thread/FileReadTask.cpp b/src/core/thread/FileReadTask.cpp
new file mode 100644
index 00000000..3a235390
--- /dev/null
+++ b/src/core/thread/FileReadTask.cpp
@@ -0,0 +1,88 @@
+/**
+ * Copyright (C) 2021 Saturneric
+ *
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GpgFrontend is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from
+ * the gpg4usb project, which is under GPL-3.0-or-later.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "core/thread/FileReadTask.h"
+
+#include <utility>
+
+namespace GpgFrontend::UI {
+
+FileReadTask::FileReadTask(std::string path) {
+ connect(this, &FileReadTask::SignalFileBytesReadNext, this,
+ &FileReadTask::read_bytes);
+
+#ifdef WINDOWS
+ std::filesystem::path read_file_path(
+ QString::fromStdString(path).toStdU16String());
+#else
+ std::filesystem::path read_file_path(
+ QString::fromStdString(path).toStdString());
+#endif
+ read_file_path_ = read_file_path;
+}
+
+void FileReadTask::Run() {
+ SetFinishAfterRun(false);
+
+ if (is_regular_file(read_file_path_)) {
+ LOG(INFO) << "read open file" << read_file_path_;
+
+ target_file_.setFileName(
+ QString::fromStdString(read_file_path_.u8string()));
+ target_file_.open(QIODevice::ReadOnly);
+
+ if (!(target_file_.isOpen() && target_file_.isReadable())) {
+ LOG(ERROR) << "file not open or not readable";
+ if (target_file_.isOpen()) target_file_.close();
+ return;
+ }
+ LOG(INFO) << "started reading" << read_file_path_;
+ read_bytes();
+ } else {
+ emit SignalFileBytesReadEnd();
+ }
+}
+
+void FileReadTask::read_bytes() {
+ QByteArray read_buffer;
+ if (!target_file_.atEnd() &&
+ (read_buffer = target_file_.read(buffer_size_)).size() > 0) {
+ LOG(INFO) << "read bytes" << read_buffer.size();
+ emit SignalFileBytesRead(std::move(read_buffer));
+ } else {
+ LOG(INFO) << "read bytes end";
+ emit SignalFileBytesReadEnd();
+ // finish task
+ emit SignalTaskFinished();
+ }
+}
+
+FileReadTask::~FileReadTask() {
+ LOG(INFO) << "close file" << read_file_path_;
+ if (target_file_.isOpen()) target_file_.close();
+}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/thread/FileReadThread.h b/src/core/thread/FileReadTask.h
index e7573af8..d4e61cbe 100644
--- a/src/ui/thread/FileReadThread.h
+++ b/src/core/thread/FileReadTask.h
@@ -27,7 +27,8 @@
#ifndef GPGFRONTEND_FILEREADTHREAD_H
#define GPGFRONTEND_FILEREADTHREAD_H
-#include "ui/GpgFrontendUI.h"
+#include "core/GpgFrontendCore.h"
+#include "core/thread/Task.h"
namespace GpgFrontend::UI {
@@ -35,41 +36,28 @@ namespace GpgFrontend::UI {
* @brief
*
*/
-class FileReadThread : public QThread {
+class GPGFRONTEND_CORE_EXPORT FileReadTask : public GpgFrontend::Thread::Task {
Q_OBJECT
-
public:
- /**
- * @brief Construct a new File Read Thread object
- *
- * @param path
- */
- explicit FileReadThread(std::string path);
-
- signals:
+ explicit FileReadTask(std::string path);
- /**
- * @brief
- *
- * @param block
- */
- void SignalSendReadBlock(const std::string& block);
+ virtual ~FileReadTask() override;
- /**
- * @brief
- *
- */
- void SignalReadDone();
+ void Run() override;
- protected:
- /**
- * @brief
- *
- */
- void run() override;
+ signals:
+ void SignalFileBytesRead(QByteArray bytes);
+ void SignalFileBytesReadEnd();
+ void SignalFileBytesReadNext();
private:
- std::string path_; ///<
+ std::filesystem::path read_file_path_;
+ QFile target_file_;
+ const size_t buffer_size_ = 4096;
+ QEventLoop looper;
+
+ private slots:
+ void read_bytes();
};
} // namespace GpgFrontend::UI
diff --git a/src/core/thread/Task.cpp b/src/core/thread/Task.cpp
new file mode 100644
index 00000000..9626ba69
--- /dev/null
+++ b/src/core/thread/Task.cpp
@@ -0,0 +1,74 @@
+/**
+ * Copyright (C) 2021 Saturneric
+ *
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GpgFrontend is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from
+ * the gpg4usb project, which is under GPL-3.0-or-later.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "core/thread/Task.h"
+
+#include <functional>
+
+#include "core/thread/TaskRunner.h"
+
+GpgFrontend::Thread::Task::Task() { init(); }
+
+GpgFrontend::Thread::Task::Task(TaskCallback callback)
+ : callback_(std::move(callback)) {
+ init();
+}
+
+GpgFrontend::Thread::Task::Task(TaskRunnable runnable, TaskCallback callback)
+ : runnable_(runnable), callback_(std::move(callback)) {
+ init();
+}
+
+GpgFrontend::Thread::Task::~Task() = default;
+
+void GpgFrontend::Thread::Task::SetFinishAfterRun(bool finish_after_run) {
+ this->finish_after_run_ = finish_after_run;
+}
+
+void GpgFrontend::Thread::Task::SetRTN(int rtn) { this->rtn_ = rtn; }
+
+void GpgFrontend::Thread::Task::init() {
+ LOG(INFO) << "called";
+ connect(this, &Task::SignalTaskFinished, this, &Task::before_finish_task);
+ connect(this, &Task::SignalTaskFinished, this, &Task::deleteLater);
+}
+
+void GpgFrontend::Thread::Task::before_finish_task() {
+ LOG(INFO) << "called";
+ if (callback_) callback_(rtn_);
+}
+
+void GpgFrontend::Thread::Task::run() {
+ LOG(INFO) << "called";
+ Run();
+ if (finish_after_run_) emit SignalTaskFinished();
+}
+
+void GpgFrontend::Thread::Task::Run() {
+ if (runnable_) {
+ rtn_ = runnable_();
+ }
+}
diff --git a/src/core/thread/Task.h b/src/core/thread/Task.h
new file mode 100644
index 00000000..4b536176
--- /dev/null
+++ b/src/core/thread/Task.h
@@ -0,0 +1,113 @@
+/**
+ * Copyright (C) 2021 Saturneric
+ *
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GpgFrontend is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from
+ * the gpg4usb project, which is under GPL-3.0-or-later.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_TASK_H
+#define GPGFRONTEND_TASK_H
+
+#include <functional>
+
+#include "core/GpgFrontendCore.h"
+
+namespace GpgFrontend::Thread {
+
+class TaskRunner;
+
+class GPGFRONTEND_CORE_EXPORT Task : public QObject, public QRunnable {
+ Q_OBJECT
+ public:
+ using TaskRunnable = std::function<int()>; ///<
+ using TaskCallback = std::function<void(int)>; ///<
+ friend class TaskRunner;
+
+ /**
+ * @brief Construct a new Task object
+ *
+ */
+ Task();
+
+ /**
+ * @brief Construct a new Task object
+ *
+ * @param callback The callback function to be executed.
+ * callback must not be nullptr, and not tp opreate UI object.
+ */
+ Task(TaskCallback callback);
+
+ /**
+ * @brief Construct a new Task object
+ *
+ * @param runnable
+ */
+ Task(
+ TaskRunnable runnable, TaskCallback callback = [](int) {});
+
+ /**
+ * @brief Destroy the Task object
+ *
+ */
+ virtual ~Task() override;
+
+ /**
+ * @brief Run - run the task
+ *
+ */
+ virtual void Run();
+
+ signals:
+ void SignalTaskFinished();
+
+ protected:
+ void SetFinishAfterRun(bool finish_after_run);
+
+ void SetRTN(int rtn);
+
+ private:
+ TaskCallback callback_; ///<
+ TaskRunnable runnable_; ///<
+ bool finish_after_run_ = true; ///<
+ int rtn_ = 0; ///<
+
+ /**
+ * @brief
+ *
+ */
+ void before_finish_task();
+
+ /**
+ * @brief
+ *
+ */
+ void init();
+
+ /**
+ * @brief
+ *
+ */
+ virtual void run() override;
+};
+} // namespace GpgFrontend::Thread
+
+#endif // GPGFRONTEND_TASK_H \ No newline at end of file
diff --git a/src/core/thread/TaskRunner.cpp b/src/core/thread/TaskRunner.cpp
new file mode 100644
index 00000000..2223bdda
--- /dev/null
+++ b/src/core/thread/TaskRunner.cpp
@@ -0,0 +1,66 @@
+/**
+ * Copyright (C) 2021 Saturneric
+ *
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GpgFrontend is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from
+ * the gpg4usb project, which is under GPL-3.0-or-later.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "core/thread/TaskRunner.h"
+
+#include "core/thread/Task.h"
+#include "easylogging++.h"
+
+GpgFrontend::Thread::TaskRunner::TaskRunner() = default;
+
+GpgFrontend::Thread::TaskRunner::~TaskRunner() = default;
+
+void GpgFrontend::Thread::TaskRunner::PostTask(Task* task) {
+ LOG(INFO) << "called";
+ if (task == nullptr) return;
+ task->setParent(nullptr);
+ task->moveToThread(this);
+ {
+ std::lock_guard<std::mutex> lock(tasks_mutex_);
+ tasks.push(task);
+ }
+ quit();
+}
+
+void GpgFrontend::Thread::TaskRunner::run() {
+ LOG(INFO) << "called";
+ while (true) {
+ if (tasks.empty()) {
+ LOG(INFO) << "TaskRunner: No tasks to run";
+ exec();
+ } else {
+ LOG(INFO) << "TaskRunner: Running task, queue size:" << tasks.size();
+
+ Task* task = nullptr;
+ {
+ std::lock_guard<std::mutex> lock(tasks_mutex_);
+ task = std::move(tasks.front());
+ tasks.pop();
+ }
+ if (task != nullptr) task->run();
+ }
+ }
+}
diff --git a/src/core/thread/TaskRunner.h b/src/core/thread/TaskRunner.h
new file mode 100644
index 00000000..14eaeae7
--- /dev/null
+++ b/src/core/thread/TaskRunner.h
@@ -0,0 +1,75 @@
+/**
+ * Copyright (C) 2021 Saturneric
+ *
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GpgFrontend is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from
+ * the gpg4usb project, which is under GPL-3.0-or-later.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_TASKRUNNER_H
+#define GPGFRONTEND_TASKRUNNER_H
+
+#include <mutex>
+#include <queue>
+
+#include "core/GpgFrontendCore.h"
+
+namespace GpgFrontend::Thread {
+
+class Task;
+
+class GPGFRONTEND_CORE_EXPORT TaskRunner : public QThread {
+ Q_OBJECT
+ public:
+ /**
+ * @brief Construct a new Task Runner object
+ *
+ */
+ TaskRunner();
+
+ /**
+ * @brief Destroy the Task Runner object
+ *
+ */
+ virtual ~TaskRunner() override;
+
+ /**
+ * @brief
+ *
+ */
+ void run() override;
+
+ public slots:
+
+ /**
+ * @brief
+ *
+ * @param task
+ */
+ void PostTask(Task* task);
+
+ private:
+ std::queue<Task*> tasks; ///< The task queue
+ std::mutex tasks_mutex_; ///< The task queue mutex
+};
+} // namespace GpgFrontend::Thread
+
+#endif // GPGFRONTEND_TASKRUNNER_H \ No newline at end of file
diff --git a/src/core/thread/TaskRunnerGetter.cpp b/src/core/thread/TaskRunnerGetter.cpp
new file mode 100644
index 00000000..186483ec
--- /dev/null
+++ b/src/core/thread/TaskRunnerGetter.cpp
@@ -0,0 +1,46 @@
+/**
+ * Copyright (C) 2021 Saturneric
+ *
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GpgFrontend is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from
+ * the gpg4usb project, which is under GPL-3.0-or-later.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "core/thread/TaskRunnerGetter.h"
+
+GpgFrontend::Thread::TaskRunnerGetter::TaskRunnerGetter(int channel)
+ : SingletonFunctionObject<TaskRunnerGetter>(channel) {}
+
+GpgFrontend::Thread::TaskRunner*
+GpgFrontend::Thread::TaskRunnerGetter::GetTaskRunner(
+ TaskRunnerType runner_type) {
+ while (true) {
+ auto it = task_runners_.find(runner_type);
+ if (it != task_runners_.end()) {
+ return it->second;
+ } else {
+ auto runner = new TaskRunner();
+ task_runners_[runner_type] = runner;
+ runner->start();
+ continue;
+ }
+ }
+}
diff --git a/src/core/thread/TaskRunnerGetter.h b/src/core/thread/TaskRunnerGetter.h
new file mode 100644
index 00000000..722484b5
--- /dev/null
+++ b/src/core/thread/TaskRunnerGetter.h
@@ -0,0 +1,56 @@
+/**
+ * Copyright (C) 2021 Saturneric
+ *
+ * This file is part of GpgFrontend.
+ *
+ * GpgFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GpgFrontend is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from
+ * the gpg4usb project, which is under GPL-3.0-or-later.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_TASKRUNNERGETTER_H
+#define GPGFRONTEND_TASKRUNNERGETTER_H
+
+#include "core/GpgFrontendCore.h"
+#include "core/GpgFunctionObject.h"
+#include "core/thread/TaskRunner.h"
+
+namespace GpgFrontend::Thread {
+
+class GPGFRONTEND_CORE_EXPORT TaskRunnerGetter
+ : public GpgFrontend::SingletonFunctionObject<TaskRunnerGetter> {
+ public:
+ enum TaskRunnerType {
+ kTaskRunnerType_Default,
+ kTaskRunnerType_GPG,
+ kTaskRunnerType_IO,
+ };
+
+ TaskRunnerGetter(int channel = SingletonFunctionObject::GetDefaultChannel());
+
+ TaskRunner *GetTaskRunner(
+ TaskRunnerType runner_type = kTaskRunnerType_Default);
+
+ private:
+ std::map<TaskRunnerType, TaskRunner *> task_runners_;
+};
+
+} // namespace GpgFrontend::Thread
+
+#endif // GPGFRONTEND_TASKRUNNERGETTER_H \ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index 24f2b7fa..fd20a664 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -36,7 +36,6 @@
#include "GpgFrontendBuildInfo.h"
#include "core/GpgFunctionObject.h"
-#include "core/thread/CtxCheckThread.h"
#include "ui/GpgFrontendUIInit.h"
#include "ui/main_window/MainWindow.h"
diff --git a/src/ui/GpgFrontendUIInit.cpp b/src/ui/GpgFrontendUIInit.cpp
index 2a8ac8b4..a5302c7b 100644
--- a/src/ui/GpgFrontendUIInit.cpp
+++ b/src/ui/GpgFrontendUIInit.cpp
@@ -29,7 +29,8 @@
#include "GpgFrontendUIInit.h"
#include "core/function/GlobalSettingStation.h"
-#include "core/thread/CtxCheckThread.h"
+#include "core/thread/CtxCheckTask.h"
+#include "core/thread/TaskRunnerGetter.h"
#include "ui/SignalStation.h"
#include "ui/UserInterfaceUtils.h"
#include "ui/main_window/MainWindow.h"
@@ -49,9 +50,7 @@ void InitGpgFrontendUI() {
CommonUtils::GetInstance();
// create the thread to load the gpg context
- auto* init_ctx_thread = new GpgFrontend::CtxCheckThread();
- QApplication::connect(init_ctx_thread, &QThread::finished, init_ctx_thread,
- &QThread::deleteLater);
+ auto* init_ctx_task = new Thread::CtxCheckTask();
// create and show loading window before starting the main window
auto* waiting_dialog = new QProgressDialog();
@@ -66,27 +65,27 @@ void InitGpgFrontendUI() {
waiting_dialog_label->setWordWrap(true);
waiting_dialog->setLabel(waiting_dialog_label);
waiting_dialog->resize(420, 120);
- QApplication::connect(init_ctx_thread, &QThread::finished, [=]() {
- waiting_dialog->finished(0);
- waiting_dialog->deleteLater();
- });
+ QApplication::connect(init_ctx_task,
+ &Thread::CtxCheckTask::SignalTaskFinished,
+ waiting_dialog, [=]() {
+ LOG(INFO) << "Gpg context loaded";
+ waiting_dialog->finished(0);
+ waiting_dialog->deleteLater();
+ });
QApplication::connect(waiting_dialog, &QProgressDialog::canceled, [=]() {
LOG(INFO) << "cancel clicked";
- if (init_ctx_thread->isRunning()) init_ctx_thread->terminate();
QCoreApplication::quit();
exit(0);
});
// show the loading window
+ waiting_dialog->setModal(true);
waiting_dialog->show();
waiting_dialog->setFocus();
// start the thread to load the gpg context
- init_ctx_thread->start();
- QEventLoop loop;
- QApplication::connect(init_ctx_thread, &QThread::finished, &loop,
- &QEventLoop::quit);
- loop.exec();
+ Thread::TaskRunnerGetter::GetInstance().GetTaskRunner()->PostTask(
+ init_ctx_task);
}
int RunGpgFrontendUI() {
diff --git a/src/ui/UserInterfaceUtils.cpp b/src/ui/UserInterfaceUtils.cpp
index 724a467e..65c55c8f 100644
--- a/src/ui/UserInterfaceUtils.cpp
+++ b/src/ui/UserInterfaceUtils.cpp
@@ -35,9 +35,13 @@
#include "core/function/FileOperator.h"
#include "core/function/GlobalSettingStation.h"
#include "core/function/gpg/GpgKeyGetter.h"
+#include "core/thread/Task.h"
+#include "core/thread/TaskRunner.h"
+#include "core/thread/TaskRunnerGetter.h"
#include "easylogging++.h"
#include "ui/SignalStation.h"
#include "ui/dialog/WaitingDialog.h"
+#include "ui/struct/SettingsObject.h"
#include "ui/widgets/TextEdit.h"
namespace GpgFrontend::UI {
@@ -111,17 +115,21 @@ void process_result_analyse(TextEdit *edit, InfoBoardWidget *info_board,
void process_operation(QWidget *parent, const std::string &waiting_title,
const std::function<void()> &func) {
+ auto *dialog =
+ new WaitingDialog(QString::fromStdString(waiting_title), parent);
+
auto thread = QThread::create(func);
QApplication::connect(thread, &QThread::finished, thread,
&QThread::deleteLater);
- thread->start();
+ QApplication::connect(thread, &QThread::finished, dialog, &QDialog::close);
+ QApplication::connect(thread, &QThread::finished, dialog,
+ &QDialog::deleteLater);
- auto *dialog =
- new WaitingDialog(QString::fromStdString(waiting_title), parent);
- while (thread->isRunning()) {
- QApplication::processEvents();
- }
- dialog->close();
+ QEventLoop looper;
+ QApplication::connect(dialog, &QDialog::finished, &looper, &QEventLoop::quit);
+
+ thread->start();
+ looper.exec();
}
CommonUtils *CommonUtils::GetInstance() {
@@ -245,11 +253,23 @@ void CommonUtils::SlotExecuteGpgCommand(
void CommonUtils::SlotImportKeyFromKeyServer(
const KeyIdArgsList &key_ids, const ImportCallbackFunctiopn &callback) {
std::string target_keyserver;
+
if (target_keyserver.empty()) {
try {
auto &settings = GlobalSettingStation::GetInstance().GetUISettings();
+ SettingsObject key_server_json("key_server");
+
+ // get key servers from settings
+ const auto key_server_list =
+ key_server_json.Check("server_list", nlohmann::json::array());
+ if (key_server_list.empty()) {
+ throw std::runtime_error("No key server configured");
+ }
- target_keyserver = settings.lookup("keyserver.default_server").c_str();
+ const int target_key_server_index =
+ key_server_json.Check("default_server", 0);
+ target_keyserver =
+ key_server_list[target_key_server_index].get<std::string>();
LOG(INFO) << _("Set target Key Server to default Key Server")
<< target_keyserver;
@@ -323,39 +343,26 @@ void CommonUtils::SlotImportKeyFromKeyServer(
current_index++;
}
});
-
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
thread->start();
}
void CommonUtils::slot_update_key_status() {
LOG(INFO) << "called";
- auto *thread = QThread::create([this]() {
- std::vector<QThread *> threads;
+ auto refresh_task = new Thread::Task([]() -> int {
// flush key cache for all GpgKeyGetter Intances.
for (const auto &channel_id : GpgKeyGetter::GetAllChannelId()) {
- // multi threading
- auto *refresh_thread = QThread::create([channel_id]() {
- LOG(INFO) << "FlushKeyCache thread start"
- << "channel:" << channel_id;
- GpgKeyGetter::GetInstance(channel_id).FlushKeyCache();
- });
- refresh_thread->start();
- threads.push_back(refresh_thread);
+ GpgKeyGetter::GetInstance(channel_id).FlushKeyCache();
}
-
- for (auto *thread : threads) {
- thread->wait();
- thread->deleteLater();
- }
-
- emit SignalKeyDatabaseRefreshDone();
- LOG(INFO) << "finished";
+ return 0;
});
- connect(thread, &QThread::finished, thread, &QThread::deleteLater);
- LOG(INFO) << "start thread";
- thread->start();
+ connect(refresh_task, &Thread::Task::SignalTaskFinished, this,
+ &CommonUtils::SignalKeyDatabaseRefreshDone);
+
+ // post the task to the default task runner
+ Thread::TaskRunnerGetter::GetInstance().GetTaskRunner()->PostTask(
+ refresh_task);
}
} // namespace GpgFrontend::UI \ No newline at end of file
diff --git a/src/ui/thread/FileReadThread.cpp b/src/ui/thread/FileReadThread.cpp
deleted file mode 100644
index 83731c8a..00000000
--- a/src/ui/thread/FileReadThread.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * Copyright (C) 2021 Saturneric
- *
- * This file is part of GpgFrontend.
- *
- * GpgFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * GpgFrontend is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from
- * the gpg4usb project, which is under GPL-3.0-or-later.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
- *
- */
-
-#include "FileReadThread.h"
-
-
-#include <utility>
-
-namespace GpgFrontend::UI {
-
-FileReadThread::FileReadThread(std::string path) : path_(std::move(path)) {
- qRegisterMetaType<std::string>("std::string");
-}
-
-void FileReadThread::run() {
- LOG(INFO) << "started reading" << path_;
-
-#ifdef WINDOWS
- std::filesystem::path read_file_path(QString::fromStdString(path_).toStdU16String());
-#else
- std::filesystem::path read_file_path(QString::fromStdString(path_).toStdString());
-#endif
-
- if (is_regular_file(read_file_path)) {
- LOG(INFO) << "read open" << read_file_path;
-
- QFile target_file;
- target_file.setFileName(QString::fromStdString(read_file_path.u8string()));
- target_file.open(QIODevice::ReadOnly);
- QByteArray read_buffer;
- LOG(INFO) << "thread start reading";
-
- const size_t buffer_size = 4096;
- if(!(target_file.isOpen() && target_file.isReadable())) {
- LOG(ERROR) << "file not open or not readable";
- if(target_file.isOpen())
- target_file.close();
- return;
- }
-
- while (!target_file.atEnd() && (read_buffer = target_file.read(buffer_size)).size() > 0) {
- // Check isInterruptionRequested
- if (QThread::currentThread()->isInterruptionRequested()) {
- LOG(INFO) << "thread is interruption requested ";
- target_file.close();
- return;
- }
- LOG(INFO) << "block size " << read_buffer.size();
- std::string buffer_str(read_buffer.toStdString());
-
- emit SignalSendReadBlock(buffer_str);
-#ifdef RELEASE
- QThread::msleep(32);
-#else
- QThread::msleep(128);
-#endif
- }
- target_file.close();
- emit SignalReadDone();
- LOG(INFO) << "thread end reading";
- }
-}
-
-} // namespace GpgFrontend::UI
diff --git a/src/ui/widgets/KeyList.cpp b/src/ui/widgets/KeyList.cpp
index bbddc84b..0bd65f25 100644
--- a/src/ui/widgets/KeyList.cpp
+++ b/src/ui/widgets/KeyList.cpp
@@ -164,7 +164,6 @@ void KeyList::SlotRefresh() {
ui_->syncButton->setDisabled(true);
emit SignalRefreshStatusBar(_("Refreshing Key List..."), 3000);
-
this->buffered_keys_list_ = GpgKeyGetter::GetInstance().FetchKey();
this->slot_refresh_ui();
}
@@ -463,7 +462,7 @@ void KeyList::slot_sync_with_key_server() {
ui_->syncButton->setDisabled(false);
ui_->refreshKeyListButton->setDisabled(false);
emit SignalRefreshStatusBar(_("Key List Sync Done."), 3000);
- emit SignalRefreshDatabase();
+ emit this->SignalRefreshDatabase();
}
});
}
@@ -501,8 +500,9 @@ KeyIdArgsListPtr& KeyTable::GetChecked() {
if (checked_key_ids_ == nullptr)
checked_key_ids_ = std::make_unique<KeyIdArgsList>();
auto& ret = checked_key_ids_;
- for (int i = 0; i < key_list_->rowCount(); i++) {
+ for (int i = 0; i < buffered_keys_.size(); i++) {
auto key_id = buffered_keys_[i].GetId();
+ LOG(INFO) << "i: " << i << " key_id: " << key_id;
if (key_list_->item(i, 0)->checkState() == Qt::Checked &&
std::find(ret->begin(), ret->end(), key_id) == ret->end()) {
ret->push_back(key_id);
@@ -517,7 +517,7 @@ void KeyTable::SetChecked(KeyIdArgsListPtr key_ids) {
}
void KeyTable::Refresh(KeyLinkListPtr m_keys) {
- LOG(INFO) << "Called";
+ LOG(INFO) << "called";
auto& checked_key_list = GetChecked();
// while filling the table, sort enabled causes errors
@@ -532,16 +532,19 @@ void KeyTable::Refresh(KeyLinkListPtr m_keys) {
else
keys = std::move(m_keys);
+ LOG(INFO) << "keys size: " << keys->size();
auto it = keys->begin();
int row_count = 0;
while (it != keys->end()) {
+ LOG(INFO) << "filtering key id: " << it->GetId();
if (filter_ != nullptr) {
if (!filter_(*it)) {
it = keys->erase(it);
continue;
}
}
+ LOG(INFO) << "adding key id: " << it->GetId();
if (select_type_ == KeyListRow::ONLY_SECRET_KEY && !it->IsPrivateKey()) {
it = keys->erase(it);
continue;
@@ -550,18 +553,15 @@ void KeyTable::Refresh(KeyLinkListPtr m_keys) {
it++;
}
+ LOG(INFO) << "row_count: " << row_count;
key_list_->setRowCount(row_count);
int row_index = 0;
it = keys->begin();
- auto& table_buffered_keys = buffered_keys_;
-
- table_buffered_keys.clear();
+ buffered_keys_.clear();
while (it != keys->end()) {
- table_buffered_keys.push_back(it->Copy());
-
auto* tmp0 = new QTableWidgetItem(QString::number(row_index));
tmp0->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled |
Qt::ItemIsSelectable);
@@ -627,6 +627,12 @@ void KeyTable::Refresh(KeyLinkListPtr m_keys) {
tmp2->setFont(strike);
tmp3->setFont(strike);
}
+
+ LOG(INFO) << "key id: " << it->GetId() << "added into key_list_:" << this;
+
+ // move to buffered keys
+ buffered_keys_.emplace_back(std::move(*it));
+
it++;
++row_index;
}
diff --git a/src/ui/widgets/PlainTextEditorPage.cpp b/src/ui/widgets/PlainTextEditorPage.cpp
index c1787c36..6f1727e8 100644
--- a/src/ui/widgets/PlainTextEditorPage.cpp
+++ b/src/ui/widgets/PlainTextEditorPage.cpp
@@ -31,7 +31,9 @@
#include <utility>
#include "core/function/CharsetOperator.h"
-#include "ui/thread/FileReadThread.h"
+#include "core/thread/FileReadTask.h"
+#include "core/thread/Task.h"
+#include "core/thread/TaskRunnerGetter.h"
#include "ui_PlainTextEditor.h"
namespace GpgFrontend::UI {
@@ -54,7 +56,7 @@ PlainTextEditorPage::PlainTextEditorPage(QString file_path, QWidget *parent)
this->ui_->encodingLabel->setText(_("utf-8"));
connect(ui_->textPage, &QPlainTextEdit::textChanged, this, [=]() {
- // if file is loaded
+ // if file is loading
if (!read_done_) return;
auto text = ui_->textPage->document()->toPlainText();
@@ -163,36 +165,34 @@ void PlainTextEditorPage::ReadFile() {
auto text_page = this->GetTextPage();
text_page->setReadOnly(true);
- auto thread = new FileReadThread(this->full_file_path_.toStdString());
- connect(thread, &FileReadThread::SignalSendReadBlock, this,
- &PlainTextEditorPage::slot_insert_text);
+ const auto target_path = this->full_file_path_.toStdString();
- connect(thread, &FileReadThread::SignalReadDone, this, [=]() {
- LOG(INFO) << "thread read done";
- if (!binary_mode_) {
- text_page->setReadOnly(false);
- }
+ auto *task_runner =
+ GpgFrontend::Thread::TaskRunnerGetter::GetInstance().GetTaskRunner();
+
+ auto *read_task = new FileReadTask(target_path);
+ connect(read_task, &FileReadTask::SignalFileBytesRead, this,
+ &PlainTextEditorPage::slot_insert_text, Qt::QueuedConnection);
+ connect(this, &PlainTextEditorPage::SignalUIBytesDisplayed, read_task,
+ &FileReadTask::SignalFileBytesReadNext, Qt::QueuedConnection);
+
+ connect(read_task, &FileReadTask::SignalTaskFinished, this,
+ []() { LOG(INFO) << "read thread closed"; });
+ connect(this, &PlainTextEditorPage::close, read_task,
+ &FileReadTask::SignalTaskFinished);
+ connect(read_task, &FileReadTask::SignalFileBytesReadEnd, this, [=]() {
+ // set the UI
+ if (!binary_mode_) text_page->setReadOnly(false);
this->read_done_ = true;
this->ui_->textPage->setEnabled(true);
text_page->document()->setModified(false);
this->ui_->textPage->blockSignals(false);
this->ui_->textPage->document()->blockSignals(false);
this->ui_->loadingLabel->setHidden(true);
-
- // delete thread
- read_thread_->deleteLater();
});
- connect(this, &PlainTextEditorPage::destroyed, [=]() {
- LOG(INFO) << "request interruption for read thread";
- if (read_thread_ != nullptr && read_thread_->isRunning())
- read_thread_->requestInterruption();
- read_thread_ = nullptr;
- });
-
- this->read_thread_ = thread;
- thread->start();
+ task_runner->PostTask(read_task);
}
std::string binary_to_string(const std::string &source) {
@@ -203,11 +203,12 @@ std::string binary_to_string(const std::string &source) {
return ss.str();
}
-void PlainTextEditorPage::slot_insert_text(const std::string &data) {
+void PlainTextEditorPage::slot_insert_text(QByteArray bytes_data) {
+ std::string data = bytes_data.toStdString();
LOG(INFO) << "data size" << data.size();
read_bytes_ += data.size();
- // If binary format is detected, the entire file is converted to binary format
- // for display.
+ // If binary format is detected, the entire file is converted to binary
+ // format for display.
bool if_last_binary_mode = binary_mode_;
if (!binary_mode_ && !read_done_) {
detect_encoding(data);
@@ -251,13 +252,8 @@ void PlainTextEditorPage::slot_insert_text(const std::string &data) {
auto str = boost::format(_("%1% character(s)")) % text.size();
this->ui_->characterLabel->setText(str.str().c_str());
}
-}
-
-void PlainTextEditorPage::PrepareToDestroy() {
- if (read_thread_) {
- read_thread_->requestInterruption();
- read_thread_ = nullptr;
- }
+ QTimer::singleShot(25, this, &PlainTextEditorPage::SignalUIBytesDisplayed);
+ LOG(INFO) << "end";
}
void PlainTextEditorPage::detect_encoding(const std::string &data) {
diff --git a/src/ui/widgets/PlainTextEditorPage.h b/src/ui/widgets/PlainTextEditorPage.h
index 0009b7d6..e5c1c89d 100644
--- a/src/ui/widgets/PlainTextEditorPage.h
+++ b/src/ui/widgets/PlainTextEditorPage.h
@@ -101,12 +101,6 @@ class PlainTextEditorPage : public QWidget {
[[nodiscard]] bool ReadDone() const { return this->read_done_; }
/**
- * @brief
- *
- */
- void PrepareToDestroy();
-
- /**
* @brief detect if the charset of the file will change
*
*/
@@ -118,18 +112,25 @@ class PlainTextEditorPage : public QWidget {
*/
void NotifyFileSaved();
+ signals:
+
+ /**
+ * @brief this signal is emitted when the bytes has been append in texteditor.
+ *
+ */
+ void SignalUIBytesDisplayed();
+
private:
std::shared_ptr<Ui_PlainTextEditor> ui_; ///<
QString full_file_path_; ///< The path to the file handled in the tab
bool sign_marked_{}; ///< true, if the signed header is marked, false if not
- bool read_done_ = false; ///<
- QThread* read_thread_ = nullptr; ///<
- bool binary_mode_ = false; ///<
- size_t read_bytes_ = 0; ///<
- std::string charset_name_; ///<
- std::string language_name_; ///<
- int32_t charset_confidence_; ///<
- bool is_crlf_ = false; ///<
+ bool read_done_ = false; ///<
+ bool binary_mode_ = false; ///<
+ size_t read_bytes_ = 0; ///<
+ std::string charset_name_; ///<
+ std::string language_name_; ///<
+ int32_t charset_confidence_; ///<
+ bool is_crlf_ = false; ///<
/**
* @brief
@@ -157,7 +158,7 @@ class PlainTextEditorPage : public QWidget {
*
* @param data
*/
- void slot_insert_text(const std::string& data);
+ void slot_insert_text(QByteArray bytes_data);
};
} // namespace GpgFrontend::UI
diff --git a/src/ui/widgets/TextEdit.cpp b/src/ui/widgets/TextEdit.cpp
index 689f877b..713dbb80 100644
--- a/src/ui/widgets/TextEdit.cpp
+++ b/src/ui/widgets/TextEdit.cpp
@@ -315,9 +315,7 @@ bool TextEdit::maybe_save_current_tab(bool askToSave) {
return false;
}
}
-
- // destroy
- page->PrepareToDestroy();
+ page->deleteLater();
return true;
}