diff --git a/src/blackgui/models/listmodelbase.cpp b/src/blackgui/models/listmodelbase.cpp index 79cdb9fff..958025360 100644 --- a/src/blackgui/models/listmodelbase.cpp +++ b/src/blackgui/models/listmodelbase.cpp @@ -163,16 +163,18 @@ namespace BlackGui * Async update */ template - BlackGui::IUpdateWorker *CListModelBase::updateAsync(const ContainerType &container, bool sort) + BlackMisc::CWorker *CListModelBase::updateAsync(const ContainerType &container, bool sort) { - // TODO: mutex - CModelUpdateWorker *worker = new CModelUpdateWorker(this, container, sort); - if (worker->start()) { return worker; } - - // start failed, we have responsibility to clean up the worker - Q_ASSERT_X(false, "CModelBase", "cannot start worker"); - worker->terminate(); - return nullptr; + auto sortColumn = this->getSortColumn(); + auto sortOrder = this->getSortOrder(); + BlackMisc::CWorker *worker = BlackMisc::CWorker::fromTask(this, "ModelSort", [this, container, sort, sortColumn, sortOrder]() + { + ContainerType sortedContainer = this->sortContainerByColumn(container, sortColumn, sortOrder); + QMetaObject::invokeMethod(this, "updateContainer", + Q_ARG(QVariant, sortedContainer.toQVariant()), Q_ARG(bool, false)); + }); + worker->then(this, &CListModelBase::asyncUpdateFinished); + return worker; } /* diff --git a/src/blackgui/models/listmodelbase.h b/src/blackgui/models/listmodelbase.h index 077b1edbb..718c29441 100644 --- a/src/blackgui/models/listmodelbase.h +++ b/src/blackgui/models/listmodelbase.h @@ -13,7 +13,7 @@ #define BLACKGUI_LISTMODELBASE_H #include "blackgui/models/columns.h" -#include "blackgui/updateworker.h" +#include "blackmisc/worker.h" #include "blackmisc/propertyindex.h" #include #include @@ -144,8 +144,7 @@ namespace BlackGui virtual int update(const ContainerType &container, bool sort = true); //! Asynchronous update - //! \return worker or nullptr if worker could not be started - virtual BlackGui::IUpdateWorker *updateAsync(const ContainerType &container, bool sort = true); + virtual BlackMisc::CWorker *updateAsync(const ContainerType &container, bool sort = true); //! Update by new container virtual void updateContainerMaybeAsync(const ContainerType &container, bool sort = true); @@ -210,55 +209,6 @@ namespace BlackGui //! \copydoc CModelBaseNonTemplate::performUpdateContainer virtual int performUpdateContainer(const QVariant &variant, bool sort) override; - - // ---- worker ----------------------------------------------------------------------------------- - - //! Worker class performing update and sorting in background - class CModelUpdateWorker : public BlackGui::IUpdateWorker - { - - public: - //! Constructor - CModelUpdateWorker(CListModelBase *model, const ContainerType &container, bool sort) : - BlackGui::IUpdateWorker(sort), m_model(model), m_container(container) - { - - Q_ASSERT(model); - this->m_sortColumn = model->getSortColumn(); - this->m_sortOrder = model->getSortOrder(); - connect(this, &CModelUpdateWorker::updateFinished, model, &CListModelBase::asyncUpdateFinished, Qt::QueuedConnection); - this->setObjectName(model->objectName().append(":CModelUpdateWorker")); - } - - //! Destructor - virtual ~CModelUpdateWorker() {} - - protected: - //! \copydoc CUpdateWorkerPrivate::update - virtual void update() override - { - // KWB remove later - qDebug() << this->objectName() << "thread:" << QThread::currentThreadId(); - if (m_model) - { - if (m_sort) - { - // almost thread safe sorting in background - m_container = m_model->sortContainerByColumn(m_container, m_sortColumn, m_sortOrder); - } - // now update model itself thread safe, but time for sort was saved - // the invoked method itself will run in the main thread's event loop again - QMetaObject::invokeMethod(m_model, "updateContainer", Qt::QueuedConnection, - Q_ARG(QVariant, m_container.toQVariant()), Q_ARG(bool, false)); - } - } - - CListModelBase *m_model = nullptr; //!< model to be updated, actually const but invokeMethod does not allow const - ContainerType m_container; //!< container with data - }; - - // ---- worker ----------------------------------------------------------------------------------- - }; } // namespace diff --git a/src/blackgui/updateworker.h b/src/blackgui/updateworker.h deleted file mode 100644 index 76b6ed11a..000000000 --- a/src/blackgui/updateworker.h +++ /dev/null @@ -1,108 +0,0 @@ -/* Copyright (C) 2013 - * swift project Community / Contributors - * - * This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level - * directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project, - * including this file, may be copied, modified, propagated, or distributed except according to the terms - * contained in the LICENSE file. - */ - -//! \file - -#ifndef BLACKGUI_UPDATEWORKER_H -#define BLACKGUI_UPDATEWORKER_H - -#include -#include -#include - -namespace BlackGui -{ - //! Base class for workers. Runs itself in newly created thread when started. - //! Provides access to related thread and cleans up itself when done. - class IUpdateWorker : public QObject - { - Q_OBJECT - - public: - //! Constructor - //! \remarks no parent, as objects with parents can not be moved to thread - IUpdateWorker(bool sort) : QObject(), m_sort(sort) {} - - //! Destructor - virtual ~IUpdateWorker() { terminateThread();} - - signals: - //! Update is completed - void updateFinished(); - - public slots: - - //! Terminate myself when thread is done - void terminate() - { - terminateThread(); - deleteLater(); - } - - //! Start thread, return nullptr if cannot be started - //! \remarks If start fails (false), object needs to be terminated manually - bool start() - { - qDebug() << "before init thread" << QThread::currentThreadId(); - if (!m_thread) { initializeThread(); } - m_thread->start(); // starting, not yet doing anything - - // m_thread will start with invocation by event loop - // invokeMethod "schedules" an update running in the newly created thread - bool ok = QMetaObject::invokeMethod(this, "ps_runUpdate", Qt::QueuedConnection); - if (ok) { return true; } - - // invocation failed, so I can clean up thread straight away - this->terminateThread(); - return false; - } - - protected: - //! Do the update (perform work here in another thread) - virtual void update() = 0; - - bool m_sort = true; //!< perform sort? - int m_sortColumn = -1; //!< which column to sort - QThread *m_thread = nullptr; //!< corresponding thread - Qt::SortOrder m_sortOrder = Qt::AscendingOrder; //!< sort order - - private slots: - //! Update, call virtual method so inheriting class needs no slots - void ps_runUpdate() - { - this->update(); // call overridden method doing work - emit this->updateFinished(); - this->terminate(); // clean up thread, delete worker (myself) - } - - private: - //! Terminate and clean up thread - void terminateThread() - { - if (!m_thread) - { - QThread *t = m_thread; - m_thread = nullptr; - t->quit(); - t->deleteLater(); - } - } - - //! Initialize thread - void initializeThread() - { - if (m_thread) { return; } - m_thread = new QThread(); - this->moveToThread(m_thread); - } - - }; -} // namespace - -#endif // guard diff --git a/src/blackgui/views/viewbase.cpp b/src/blackgui/views/viewbase.cpp index 3db1d2d07..33d1e7023 100644 --- a/src/blackgui/views/viewbase.cpp +++ b/src/blackgui/views/viewbase.cpp @@ -149,16 +149,19 @@ namespace BlackGui return c; } - template IUpdateWorker *CViewBase::updateContainerAsync(const ContainerType &container, bool sort, bool resize) + template BlackMisc::CWorker *CViewBase::updateContainerAsync(const ContainerType &container, bool sort, bool resize) { - // TODO: mutex - CViewUpdateWorker *worker = new CViewUpdateWorker(this, container, sort, resize); - if (worker->start()) { return worker; } - - // start failed, we have responsibility to clean up the worker - Q_ASSERT_X(false, "CViewBase", "cannot start worker"); - worker->terminate(); - return nullptr; + ModelClass *model = this->derivedModel(); + auto sortColumn = model->getSortColumn(); + auto sortOrder = model->getSortOrder(); + BlackMisc::CWorker *worker = BlackMisc::CWorker::fromTask(this, "ViewSort", [this, model, container, sort, resize, sortColumn, sortOrder]() + { + ContainerType sortedContainer = model->sortContainerByColumn(container, sortColumn, sortOrder); + QMetaObject::invokeMethod(this, "updateContainer", + Q_ARG(QVariant, sortedContainer.toQVariant()), Q_ARG(bool, false), Q_ARG(bool, resize)); + }); + worker->then(this, &CViewBase::asyncUpdateFinished); + return worker; } template void CViewBase::updateContainerMaybeAsync(const ContainerType &container, bool sort, bool resize) diff --git a/src/blackgui/views/viewbase.h b/src/blackgui/views/viewbase.h index b1916b221..f4cdc3fa0 100644 --- a/src/blackgui/views/viewbase.h +++ b/src/blackgui/views/viewbase.h @@ -13,7 +13,7 @@ #define BLACKGUI_VIEWBASE_H #include "blackmisc/icons.h" -#include "blackgui/updateworker.h" +#include "blackmisc/worker.h" #include #include #include @@ -156,8 +156,7 @@ namespace BlackGui int updateContainer(const ContainerType &container, bool sort = true, bool resize = true); //! Update whole container in background - //! \returns Worker or nullptr if worker cannot be started - IUpdateWorker *updateContainerAsync(const ContainerType &container, bool sort = true, bool resize = true); + BlackMisc::CWorker *updateContainerAsync(const ContainerType &container, bool sort = true, bool resize = true); //! Based on size call sync / async update void updateContainerMaybeAsync(const ContainerType &container, bool sort = true, bool resize = true); @@ -214,61 +213,6 @@ namespace BlackGui //! \copydoc CViewBaseNonTemplate::performUpdateContainer virtual int performUpdateContainer(const QVariant &variant, bool sort, bool resize) override; - // ---- worker ----------------------------------------------------------------------------------- - - //! Worker class performing update and sorting in background - class CViewUpdateWorker : public BlackGui::IUpdateWorker - { - - public: - //! Constructor - CViewUpdateWorker(CViewBase *view, const ContainerType &container, bool sort, bool resize) : - BlackGui::IUpdateWorker(sort), m_view(view), m_container(container), m_resize(resize) - { - Q_ASSERT(view); - this->m_sortColumn = view->derivedModel()->getSortColumn(); - this->m_sortOrder = view->derivedModel()->getSortOrder(); - this->setObjectName(view->objectName().append(":CViewUpdateWorker")); - connect(this, &CViewUpdateWorker::updateFinished, view, &CViewBase::asyncUpdateFinished, Qt::QueuedConnection); - } - - //! Destructor - virtual ~CViewUpdateWorker() {} - - protected: - //! \copydoc CUpdateWorkerPrivate::update - virtual void update() override - { - Q_ASSERT(m_view); - Q_ASSERT(m_view->derivedModel()); - if (m_view) - { - // KWB remove later - qDebug() << this->objectName() << "worker thread:" << QThread::currentThreadId(); - - // resize has to be in main thread - ModelClass *model = m_view->derivedModel(); - if (m_sort) - { - // thread safe sort: - // 1) the container itself is copied when worker is created and hence thread safe - // 2) the sort order itself is not really thread safe, - // but always represents the latest value from CListModelBase/QAbstractListModel::sort() - m_container = model->sortContainerByColumn(m_container, m_sortColumn, m_sortOrder); - } - // now update view itself thread safe, but time for sort was saved - QMetaObject::invokeMethod(m_view, "updateContainer", Qt::QueuedConnection, - Q_ARG(QVariant, m_container.toQVariant()), Q_ARG(bool, false), Q_ARG(bool, m_resize)); - } - } - - CViewBase *m_view = nullptr; //!< view to be updated, actually const but invokeMethod does not allow const - ContainerType m_container; //!< container with data - bool m_resize; //!< with resizing - }; - - // ---- worker ----------------------------------------------------------------------------------- - }; } // namespace } // namespace