From 0d257d28af1c73121ff019ef28cb665ab177d448 2017-07-17 15:20:26 From: mperrinel Date: 2017-07-17 15:20:26 Subject: [PATCH] Merge branch 'feature/AbortDownload' into develop --- diff --git a/core/include/Data/IDataProvider.h b/core/include/Data/IDataProvider.h index 0f16848..b5cfce0 100644 --- a/core/include/Data/IDataProvider.h +++ b/core/include/Data/IDataProvider.h @@ -34,6 +34,11 @@ public: */ virtual void requestDataLoading(QUuid identifier, const DataProviderParameters ¶meters) = 0; + /** + * @brief requestDataAborting stop data loading of the data identified by identifier + */ + virtual void requestDataAborting(QUuid identifier) = 0; + signals: /** * @brief dataProvided send dataSeries under dateTime and that corresponds of the data diff --git a/core/include/Variable/VariableController.h b/core/include/Variable/VariableController.h index 2776c18..2ba9d00 100644 --- a/core/include/Variable/VariableController.h +++ b/core/include/Variable/VariableController.h @@ -50,6 +50,11 @@ public: */ void deleteVariables(const QVector > &variables) noexcept; + /** + * @brief abort the variable retrieve data progression + */ + void abortProgress(std::shared_ptr variable); + signals: /// Signal emitted when a variable is about to be deleted from the controller void variableAboutToBeDeleted(std::shared_ptr variable); @@ -72,6 +77,8 @@ public slots: void onVariableRetrieveDataInProgress(QUuid identifier, double progress); + void onAbortProgressRequested(std::shared_ptr variable); + void initialize(); void finalize(); diff --git a/core/include/Variable/VariableModel.h b/core/include/Variable/VariableModel.h index 8e8f317..21e4edc 100644 --- a/core/include/Variable/VariableModel.h +++ b/core/include/Variable/VariableModel.h @@ -22,6 +22,7 @@ class Variable; * @brief The VariableModel class aims to hold the variables that have been created in SciQlop */ class VariableModel : public QAbstractTableModel { + Q_OBJECT public: explicit VariableModel(QObject *parent = nullptr); @@ -46,6 +47,7 @@ public: void setDataProgress(std::shared_ptr variable, double progress); + // /////////////////////////// // // QAbstractTableModel methods // // /////////////////////////// // @@ -56,6 +58,12 @@ public: virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + + void abortProgress(const QModelIndex &index); + +signals: + void abortProgessRequested(std::shared_ptr variable); + private: class VariableModelPrivate; spimpl::unique_impl_ptr impl; diff --git a/core/src/Network/NetworkController.cpp b/core/src/Network/NetworkController.cpp index 64c0bb8..64f3d82 100644 --- a/core/src/Network/NetworkController.cpp +++ b/core/src/Network/NetworkController.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -14,8 +15,13 @@ struct NetworkController::NetworkControllerPrivate { explicit NetworkControllerPrivate(NetworkController *parent) : m_WorkingMutex{} {} QMutex m_WorkingMutex; + QReadWriteLock m_Lock; std::unordered_map m_NetworkReplyToVariableId; std::unique_ptr m_AccessManager{nullptr}; + + void lockRead() { m_Lock.lockForRead(); } + void lockWrite() { m_Lock.lockForWrite(); } + void unlock() { m_Lock.unlock(); } }; NetworkController::NetworkController(QObject *parent) @@ -26,30 +32,50 @@ NetworkController::NetworkController(QObject *parent) void NetworkController::onProcessRequested(const QNetworkRequest &request, QUuid identifier, std::function callback) { - qCInfo(LOG_NetworkController()) << tr("NetworkController registered") - << QThread::currentThread(); auto reply = impl->m_AccessManager->get(request); + qCDebug(LOG_NetworkController()) << tr("NetworkController registered") + << QThread::currentThread() << reply; // Store the couple reply id + impl->lockWrite(); impl->m_NetworkReplyToVariableId[reply] = identifier; + impl->unlock(); auto onReplyFinished = [reply, this, identifier, callback]() { - qCInfo(LOG_NetworkController()) << tr("NetworkController onReplyFinished") - << QThread::currentThread(); + qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyFinished") + << QThread::currentThread() << reply; + impl->lockRead(); auto it = impl->m_NetworkReplyToVariableId.find(reply); + impl->unlock(); if (it != impl->m_NetworkReplyToVariableId.cend()) { + impl->lockWrite(); + impl->m_NetworkReplyToVariableId.erase(reply); + impl->unlock(); + // Deletes reply callback(reply, identifier); + reply->deleteLater(); + + emit this->replyDownloadProgress(identifier, 0); } + + qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyFinished END") + << QThread::currentThread() << reply; }; auto onReplyProgress = [reply, this](qint64 bytesRead, qint64 totalBytes) { double progress = (bytesRead * 100.0) / totalBytes; + qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyProgress") << progress + << QThread::currentThread() << reply; + impl->lockRead(); auto it = impl->m_NetworkReplyToVariableId.find(reply); + impl->unlock(); if (it != impl->m_NetworkReplyToVariableId.cend()) { emit this->replyDownloadProgress(it->second, progress); } + qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyProgress END") + << QThread::currentThread() << reply; }; @@ -73,12 +99,19 @@ void NetworkController::finalize() void NetworkController::onReplyCanceled(QUuid identifier) { auto findReply = [identifier](const auto &entry) { return identifier == entry.second; }; + qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyCanceled") + << QThread::currentThread(); + + impl->lockRead(); auto end = impl->m_NetworkReplyToVariableId.cend(); auto it = std::find_if(impl->m_NetworkReplyToVariableId.cbegin(), end, findReply); + impl->unlock(); if (it != end) { it->first->abort(); } + qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyCanceled END") + << QThread::currentThread(); } void NetworkController::waitForFinish() diff --git a/core/src/Variable/VariableController.cpp b/core/src/Variable/VariableController.cpp index afeaab9..0f96d50 100644 --- a/core/src/Variable/VariableController.cpp +++ b/core/src/Variable/VariableController.cpp @@ -46,6 +46,9 @@ VariableController::VariableController(QObject *parent) { qCDebug(LOG_VariableController()) << tr("VariableController construction") << QThread::currentThread(); + + connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this, + &VariableController::onAbortProgressRequested); } VariableController::~VariableController() @@ -105,6 +108,10 @@ void VariableController::deleteVariables( } } +void VariableController::abortProgress(std::shared_ptr variable) +{ +} + void VariableController::createVariable(const QString &name, const QVariantHash &metadata, std::shared_ptr provider) noexcept { @@ -166,6 +173,22 @@ void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, doub } } +void VariableController::onAbortProgressRequested(std::shared_ptr variable) +{ + qCDebug(LOG_VariableController()) << "TORM: VariableController::onAbortProgressRequested" + << QThread::currentThread()->objectName(); + + auto it = impl->m_VariableToIdentifierMap.find(variable); + if (it != impl->m_VariableToIdentifierMap.cend()) { + impl->m_VariableToProviderMap.at(variable)->requestDataAborting(it->second); + } + else { + qCWarning(LOG_VariableController()) + << tr("Aborting progression of inexistant variable detected !!!") + << QThread::currentThread()->objectName(); + } +} + void VariableController::onRequestDataLoading(std::shared_ptr variable, const SqpDateTime &dateTime) diff --git a/core/src/Variable/VariableModel.cpp b/core/src/Variable/VariableModel.cpp index 7553415..43cca2f 100644 --- a/core/src/Variable/VariableModel.cpp +++ b/core/src/Variable/VariableModel.cpp @@ -205,6 +205,13 @@ QVariant VariableModel::headerData(int section, Qt::Orientation orientation, int return QVariant{}; } +void VariableModel::abortProgress(const QModelIndex &index) +{ + if (auto variable = impl->m_Variables.at(index.row())) { + emit abortProgessRequested(variable); + } +} + void VariableModel::onVariableUpdated() noexcept { // Finds variable that has been updated in the model diff --git a/gui/src/Variable/VariableInspectorWidget.cpp b/gui/src/Variable/VariableInspectorWidget.cpp index 3b2e9ae..d9a1cab 100644 --- a/gui/src/Variable/VariableInspectorWidget.cpp +++ b/gui/src/Variable/VariableInspectorWidget.cpp @@ -5,6 +5,7 @@ #include +#include #include #include #include @@ -27,9 +28,12 @@ public: if (data.isValid() && progressData.isValid()) { auto name = data.value(); auto progress = progressData.value(); - if (progress >= 0) { + if (progress > 0) { + auto cancelButtonWidth = 20; auto progressBarOption = QStyleOptionProgressBar{}; - progressBarOption.rect = option.rect; + auto progressRect = option.rect; + progressRect.setWidth(progressRect.width() - cancelButtonWidth); + progressBarOption.rect = progressRect; progressBarOption.minimum = 0; progressBarOption.maximum = 100; progressBarOption.progress = progress; @@ -38,14 +42,70 @@ public: progressBarOption.textVisible = true; progressBarOption.textAlignment = Qt::AlignCenter; + QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption, painter); + + // Cancel button + auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth, + option.rect.height()); + auto buttonOption = QStyleOptionButton{}; + buttonOption.rect = buttonRect; + buttonOption.text = "X"; + + QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter); + } + else { + QStyledItemDelegate::paint(painter, option, index); } } else { QStyledItemDelegate::paint(painter, option, index); } } + + bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, + const QModelIndex &index) + { + if (event->type() == QEvent::MouseButtonRelease) { + auto data = index.data(Qt::DisplayRole); + auto progressData = index.data(VariableRoles::ProgressRole); + if (data.isValid() && progressData.isValid()) { + auto cancelButtonWidth = 20; + auto progressRect = option.rect; + progressRect.setWidth(progressRect.width() - cancelButtonWidth); + // Cancel button + auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth, + option.rect.height()); + + QMouseEvent *e = (QMouseEvent *)event; + int clickX = e->x(); + int clickY = e->y(); + + auto x = buttonRect.left(); // the X coordinate + auto y = buttonRect.top(); // the Y coordinate + auto w = buttonRect.width(); // button width + auto h = buttonRect.height(); // button height + + if (clickX > x && clickX < x + w) { + if (clickY > y && clickY < y + h) { + qCritical(LOG_VariableInspectorWidget()) << tr("editorEvent CLIC"); + auto variableModel = sqpApp->variableController().variableModel(); + variableModel->abortProgress(index); + } + } + else { + QStyledItemDelegate::editorEvent(event, model, option, index); + } + } + else { + QStyledItemDelegate::editorEvent(event, model, option, index); + } + } + else { + QStyledItemDelegate::editorEvent(event, model, option, index); + } + } }; VariableInspectorWidget::VariableInspectorWidget(QWidget *parent) diff --git a/plugins/amda/include/AmdaProvider.h b/plugins/amda/include/AmdaProvider.h index d65573b..6188efe 100644 --- a/plugins/amda/include/AmdaProvider.h +++ b/plugins/amda/include/AmdaProvider.h @@ -21,6 +21,8 @@ public: void requestDataLoading(QUuid token, const DataProviderParameters ¶meters) override; + void requestDataAborting(QUuid identifier) override; + private: void retrieveData(QUuid token, const SqpDateTime &dateTime, const QVariantHash &data); }; diff --git a/plugins/amda/src/AmdaProvider.cpp b/plugins/amda/src/AmdaProvider.cpp index 20be39b..ea7a004 100644 --- a/plugins/amda/src/AmdaProvider.cpp +++ b/plugins/amda/src/AmdaProvider.cpp @@ -61,6 +61,14 @@ void AmdaProvider::requestDataLoading(QUuid token, const DataProviderParameters } } +void AmdaProvider::requestDataAborting(QUuid identifier) +{ + if (auto app = sqpApp) { + auto &networkController = app->networkController(); + networkController.onReplyCanceled(identifier); + } +} + void AmdaProvider::retrieveData(QUuid token, const SqpDateTime &dateTime, const QVariantHash &data) { // Retrieves product ID from data: if the value is invalid, no request is made @@ -102,16 +110,13 @@ void AmdaProvider::retrieveData(QUuid token, const SqpDateTime &dateTime, const } } - // Deletes reply - reply->deleteLater(); - reply = nullptr; + }; auto httpFinishedLambda = [this, httpDownloadFinished, tempFile](QNetworkReply *reply, QUuid dataId) noexcept { auto downloadFileUrl = QUrl{QString{reply->readAll()}}; - // Deletes old reply - reply->deleteLater(); + // Executes request for downloading file // diff --git a/plugins/mockplugin/include/CosinusProvider.h b/plugins/mockplugin/include/CosinusProvider.h index 1f04e38..d28952f 100644 --- a/plugins/mockplugin/include/CosinusProvider.h +++ b/plugins/mockplugin/include/CosinusProvider.h @@ -17,6 +17,9 @@ public: void requestDataLoading(QUuid token, const DataProviderParameters ¶meters) override; + void requestDataAborting(QUuid identifier) override; + + private: /// @sa IDataProvider::retrieveData() std::shared_ptr retrieveData(const SqpDateTime &dateTime) const; diff --git a/plugins/mockplugin/src/CosinusProvider.cpp b/plugins/mockplugin/src/CosinusProvider.cpp index 0fd5537..b1dedae 100644 --- a/plugins/mockplugin/src/CosinusProvider.cpp +++ b/plugins/mockplugin/src/CosinusProvider.cpp @@ -46,3 +46,8 @@ void CosinusProvider::requestDataLoading(QUuid token, const DataProviderParamete emit dataProvided(token, scalarSeries, dateTime); } } + +void CosinusProvider::requestDataAborting(QUuid identifier) +{ + // TODO +}