diff --git a/src/backgroundmanager/CMakeLists.txt b/src/backgroundmanager/CMakeLists.txt index cd519dc..6dab96f 100644 --- a/src/backgroundmanager/CMakeLists.txt +++ b/src/backgroundmanager/CMakeLists.txt @@ -1,6 +1,14 @@ set(MR_TIMETABLE_PLANNER_SOURCES ${MR_TIMETABLE_PLANNER_SOURCES} + backgroundmanager/backgroundmanager.h backgroundmanager/backgroundmanager.cpp + + backgroundmanager/backgroundresultwidget.cpp + backgroundmanager/backgroundresultwidget.h + + backgroundmanager/ibackgroundchecker.cpp + backgroundmanager/ibackgroundchecker.h + PARENT_SCOPE ) diff --git a/src/backgroundmanager/backgroundresultwidget.cpp b/src/backgroundmanager/backgroundresultwidget.cpp new file mode 100644 index 0000000..bf27b24 --- /dev/null +++ b/src/backgroundmanager/backgroundresultwidget.cpp @@ -0,0 +1,113 @@ +#ifdef ENABLE_BACKGROUND_MANAGER + +#include "ibackgroundchecker.h" +#include "backgroundresultwidget.h" + +#include +#include +#include +#include + +#include + +#include +#include + +#include + + +BackgroundResultWidget::BackgroundResultWidget(IBackgroundChecker *mgr_, QWidget *parent) : + QWidget(parent), + mgr(mgr_), + timerId(0) +{ + view = new QTreeView; + view->setUniformRowHeights(true); + view->setSelectionBehavior(QTreeView::SelectRows); + + progressBar = new QProgressBar; + startBut = new QPushButton(tr("Start")); + stopBut = new QPushButton(tr("Stop")); + + startBut->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); + stopBut->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); + + view->setModel(mgr_->getModel()); + view->header()->setStretchLastSection(true); + view->setSelectionBehavior(QTreeView::SelectRows); + + QGridLayout *grid = new QGridLayout(this); + grid->addWidget(view, 0, 0, 1, 3); + grid->addWidget(startBut, 1, 0, 1, 1); + grid->addWidget(stopBut, 1, 1, 1, 1); + grid->addWidget(progressBar, 1, 2, 1, 1); + + connect(mgr, &IBackgroundChecker::progress, this, &BackgroundResultWidget::onTaskProgress); + connect(mgr, &IBackgroundChecker::taskFinished, this, &BackgroundResultWidget::taskFinished); + + connect(startBut, &QPushButton::clicked, this, &BackgroundResultWidget::startTask); + connect(stopBut, &QPushButton::clicked, this, &BackgroundResultWidget::stopTask); + + view->setContextMenuPolicy(Qt::CustomContextMenu); + connect(view, &QTreeView::customContextMenuRequested, this, &BackgroundResultWidget::showContextMenu); + + setWindowTitle(tr("Rollingstock Errors")); + + progressBar->hide(); +} + +void BackgroundResultWidget::startTask() +{ + progressBar->setValue(0); + + if(mgr->startWorker()) + { + if(timerId) + { + killTimer(timerId); //Stop progressBar from hiding in 1 second + timerId = 0; + } + } +} + +void BackgroundResultWidget::stopTask() +{ + mgr->abortTasks(); +} + +void BackgroundResultWidget::onTaskProgress(int val, int max) +{ + progressBar->setMaximum(max); + progressBar->setValue(val); + progressBar->show(); +} + +void BackgroundResultWidget::taskFinished() +{ + progressBar->setValue(progressBar->maximum()); + + if(timerId) + killTimer(timerId); + timerId = startTimer(1000); //Hide progressBar after 1 second +} + +void BackgroundResultWidget::timerEvent(QTimerEvent *e) +{ + if(e->timerId() == timerId) + { + killTimer(timerId); + timerId = 0; + progressBar->hide(); + } +} + +void BackgroundResultWidget::showContextMenu(const QPoint& pos) +{ + QModelIndex idx = view->indexAt(pos); + if(!idx.isValid()) + return; + + mgr->showContextMenu(this, view->viewport()->mapToGlobal(pos), idx); +} + +#endif // ENABLE_BACKGROUND_MANAGER diff --git a/src/backgroundmanager/backgroundresultwidget.h b/src/backgroundmanager/backgroundresultwidget.h new file mode 100644 index 0000000..2d2e00a --- /dev/null +++ b/src/backgroundmanager/backgroundresultwidget.h @@ -0,0 +1,43 @@ +#ifndef BACKGROUNDRESULTWIDGET_H +#define BACKGROUNDRESULTWIDGET_H + +#ifdef ENABLE_BACKGROUND_MANAGER + +#include + +class QTreeView; +class QProgressBar; +class QPushButton; + +class IBackgroundChecker; + +class BackgroundResultWidget : public QWidget +{ + Q_OBJECT +public: + explicit BackgroundResultWidget(IBackgroundChecker *mgr_, QWidget *parent = nullptr); + +protected: + void timerEvent(QTimerEvent *e) override; + +private slots: + void startTask(); + void stopTask(); + void onTaskProgress(int val, int max); + void taskFinished(); + void showContextMenu(const QPoint &pos); + +private: + friend class BackgroundResultPanel; + + IBackgroundChecker *mgr; + QTreeView *view; + QProgressBar *progressBar; + QPushButton *startBut; + QPushButton *stopBut; + int timerId; +}; + +#endif // ENABLE_BACKGROUND_MANAGER + +#endif // BACKGROUNDRESULTWIDGET_H diff --git a/src/backgroundmanager/ibackgroundchecker.cpp b/src/backgroundmanager/ibackgroundchecker.cpp new file mode 100644 index 0000000..0b5a45b --- /dev/null +++ b/src/backgroundmanager/ibackgroundchecker.cpp @@ -0,0 +1,114 @@ +#ifdef ENABLE_BACKGROUND_MANAGER + +#include "ibackgroundchecker.h" + +#include +#include "utils/thread/iquittabletask.h" +#include "utils/thread/taskprogressevent.h" + +#include "sqlite3pp/sqlite3pp.h" + + +IBackgroundChecker::IBackgroundChecker(sqlite3pp::database &db, QObject *parent) : + QObject(parent), + mDb(db) +{ + +} + +bool IBackgroundChecker::event(QEvent *e) +{ + if(e->type() == TaskProgressEvent::_Type) + { + e->setAccepted(true); + + TaskProgressEvent *ev = static_cast(e); + emit progress(ev->progress, ev->progressMax); + + return true; + } + else if(e->type() == eventType) + { + e->setAccepted(true); + + GenericTaskEvent *ev = static_cast(e); + if(m_mainWorker && ev->task == m_mainWorker) + { + if(!m_mainWorker->wasStopped()) + { + setErrors(ev, false); + } + + delete m_mainWorker; + m_mainWorker = nullptr; + + emit taskFinished(); + } + else + { + int idx = m_workers.indexOf(ev->task); + if(idx != -1) + { + m_workers.removeAt(idx); + if(!ev->task->wasStopped()) + setErrors(ev, true); + + delete ev->task; + } + } + + return true; + } + + return QObject::event(e); +} + +bool IBackgroundChecker::startWorker() +{ + if(m_mainWorker) + return false; + + if(!mDb.db()) + return false; + + m_mainWorker = createMainWorker(); + + QThreadPool::globalInstance()->start(m_mainWorker); + + for(auto task = m_workers.begin(); task != m_workers.end(); task++) + { + if(QThreadPool::globalInstance()->tryTake(*task)) + { + IQuittableTask *ptr = *task; + m_workers.erase(task); + delete ptr; + } + else + { + (*task)->stop(); + } + } + + return true; +} + +void IBackgroundChecker::abortTasks() +{ + if(m_mainWorker) + { + m_mainWorker->stop(); + } + + for(IQuittableTask *task : qAsConst(m_workers)) + { + task->stop(); + } +} + +void IBackgroundChecker::addSubTask(IQuittableTask *task) +{ + m_workers.append(task); + QThreadPool::globalInstance()->start(task); +} + +#endif // ENABLE_BACKGROUND_MANAGER diff --git a/src/backgroundmanager/ibackgroundchecker.h b/src/backgroundmanager/ibackgroundchecker.h new file mode 100644 index 0000000..59d2a44 --- /dev/null +++ b/src/backgroundmanager/ibackgroundchecker.h @@ -0,0 +1,61 @@ +#ifndef IBACKGROUNDCHECKER_H +#define IBACKGROUNDCHECKER_H + +#ifdef ENABLE_BACKGROUND_MANAGER + +#include +#include + +class QAbstractItemModel; +class QModelIndex; +class QWidget; +class QPoint; + +class IQuittableTask; + +namespace sqlite3pp { +class database; +} + +class IBackgroundChecker : public QObject +{ + Q_OBJECT +public: + IBackgroundChecker(sqlite3pp::database &db, QObject *parent = nullptr); + + bool event(QEvent *e) override; + + bool startWorker(); + void abortTasks(); + + inline bool isRunning() const { return m_mainWorker || m_workers.size() > 0; } + + inline QAbstractItemModel *getModel() const { return errorsModel; }; + + virtual QString getName() const = 0; + virtual void clearModel() = 0; + virtual void showContextMenu(QWidget *panel, const QPoint& globalPos, const QModelIndex& idx) const = 0; + +signals: + void progress(int val, int max); + void taskFinished(); + +protected: + void addSubTask(IQuittableTask *task); + + virtual IQuittableTask *createMainWorker() = 0; + virtual void setErrors(QEvent *e, bool merge) = 0; + +protected: + sqlite3pp::database &mDb; + QAbstractItemModel *errorsModel = nullptr; + int eventType = 0; + +private: + IQuittableTask *m_mainWorker = nullptr; + QVector m_workers; +}; + +#endif // ENABLE_BACKGROUND_MANAGER + +#endif // IBACKGROUNDCHECKER_H