From 4f465f223e9539257e008a596b209f96fb87e1d2 2017-10-31 13:33:36 From: Thibaud Rabillard Date: 2017-10-31 13:33:36 Subject: [PATCH] Merge branch 'feature/DragDropProduct' into develop --- diff --git a/core/include/Common/MimeTypesDef.h b/core/include/Common/MimeTypesDef.h index 2212853..3766fac 100644 --- a/core/include/Common/MimeTypesDef.h +++ b/core/include/Common/MimeTypesDef.h @@ -12,6 +12,7 @@ extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_GRAPH; extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_ZONE; extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_VARIABLE_LIST; +extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_PRODUCT_LIST; extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_TIME_RANGE; diff --git a/core/include/DataSource/DataSourceController.h b/core/include/DataSource/DataSourceController.h index 568f5a9..13e89a2 100644 --- a/core/include/DataSource/DataSourceController.h +++ b/core/include/DataSource/DataSourceController.h @@ -64,11 +64,16 @@ public: */ void loadProductItem(const QUuid &dataSourceUid, const DataSourceItem &productItem) noexcept; + QByteArray mimeDataForProductsData(const QVariantList &productsData) const; + QVariantList productsDataForMimeData(const QByteArray &mimeData) const; + public slots: /// Manage init/end of the controller void initialize(); void finalize(); + void requestVariable(const QVariantHash &productData); + signals: /// Signal emitted when a structure has been set for a data source void dataSourceItemSet(DataSourceItem *dataSourceItem); diff --git a/core/include/DataSource/DataSourceItem.h b/core/include/DataSource/DataSourceItem.h index cecbf82..3b03955 100644 --- a/core/include/DataSource/DataSourceItem.h +++ b/core/include/DataSource/DataSourceItem.h @@ -91,6 +91,14 @@ public: DataSourceItemType type() const noexcept; + /** + * @brief Searches the first child matching the specified data. + * @param data The data to search. + * @param recursive So the search recursively. + * @return the item matching the data or nullptr if it was not found. + */ + DataSourceItem *findItem(const QVariantHash &data, bool recursive); + bool operator==(const DataSourceItem &other); bool operator!=(const DataSourceItem &other); diff --git a/core/include/Variable/VariableModel.h b/core/include/Variable/VariableModel.h index 95da42c..f3928f8 100644 --- a/core/include/Variable/VariableModel.h +++ b/core/include/Variable/VariableModel.h @@ -93,6 +93,7 @@ public: signals: void abortProgessRequested(std::shared_ptr variable); + void requestVariable(const QVariantHash &productData); private: class VariableModelPrivate; diff --git a/core/meson.build b/core/meson.build index 2256757..a275a3b 100644 --- a/core/meson.build +++ b/core/meson.build @@ -3,6 +3,7 @@ core_moc_headers = [ 'include/Data/IDataProvider.h', 'include/DataSource/DataSourceController.h', 'include/DataSource/DataSourceItemAction.h', + 'include/DataSource/DataSourceWidget.h', 'include/Network/NetworkController.h', 'include/Time/TimeController.h', 'include/Variable/Variable.h', @@ -31,6 +32,7 @@ core_sources = [ 'src/DataSource/DataSourceController.cpp', 'src/DataSource/DataSourceItem.cpp', 'src/DataSource/DataSourceItemAction.cpp', + 'src/DataSource/DataSourceWidget.cpp', 'src/Network/NetworkController.cpp', 'src/Plugin/PluginManager.cpp', 'src/Settings/SqpSettingsDefs.cpp', diff --git a/core/src/Common/MimeTypesDef.cpp b/core/src/Common/MimeTypesDef.cpp index 24ef739..0393e1f 100644 --- a/core/src/Common/MimeTypesDef.cpp +++ b/core/src/Common/MimeTypesDef.cpp @@ -1,6 +1,7 @@ #include "Common/MimeTypesDef.h" -const QString MIME_TYPE_GRAPH = QStringLiteral("scqlop/graph"); -const QString MIME_TYPE_ZONE = QStringLiteral("scqlop/zone"); -const QString MIME_TYPE_VARIABLE_LIST = QStringLiteral("scqlop/var-list"); -const QString MIME_TYPE_TIME_RANGE = QStringLiteral("scqlop/time-range"); +const QString MIME_TYPE_GRAPH = QStringLiteral("sciqlop/graph"); +const QString MIME_TYPE_ZONE = QStringLiteral("sciqlop/zone"); +const QString MIME_TYPE_VARIABLE_LIST = QStringLiteral("sciqlop/var-list"); +const QString MIME_TYPE_PRODUCT_LIST = QStringLiteral("sciqlop/product-list"); +const QString MIME_TYPE_TIME_RANGE = QStringLiteral("sciqlop/time-range"); diff --git a/core/src/DataSource/DataSourceController.cpp b/core/src/DataSource/DataSourceController.cpp index 220945e..6d42abf 100644 --- a/core/src/DataSource/DataSourceController.cpp +++ b/core/src/DataSource/DataSourceController.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -44,6 +45,20 @@ public: /// @remarks Data providers are stored as shared_ptr as they can be sent to a variable and /// continue to live without necessarily the data source controller std::map > m_DataProviders; + + // Search for the first datasource item matching the specified data + DataSourceItem *findDataSourceItem(const QVariantHash &data) + { + DataSourceItem *sourceItem = nullptr; + for (const auto &item : m_DataSourceItems) { + sourceItem = item.second->findItem(data, true); + if (sourceItem) { + break; + } + } + + return sourceItem; + } }; DataSourceController::DataSourceController(QObject *parent) @@ -124,6 +139,26 @@ void DataSourceController::loadProductItem(const QUuid &dataSourceUid, } } +QByteArray DataSourceController::mimeDataForProductsData(const QVariantList &productsData) const +{ + QByteArray encodedData; + QDataStream stream{&encodedData, QIODevice::WriteOnly}; + + stream << productsData; + + return encodedData; +} + +QVariantList DataSourceController::productsDataForMimeData(const QByteArray &mimeData) const +{ + QDataStream stream{mimeData}; + + QVariantList productList; + stream >> productList; + + return productList; +} + void DataSourceController::initialize() { qCDebug(LOG_DataSourceController()) << tr("DataSourceController init") @@ -137,6 +172,20 @@ void DataSourceController::finalize() impl->m_WorkingMutex.unlock(); } +void DataSourceController::requestVariable(const QVariantHash &productData) +{ + DataSourceItem *sourceItem = impl->findDataSourceItem(productData); + + if (sourceItem) { + auto sourceName = sourceItem->rootItem().name(); + auto sourceId = impl->m_DataSources.key(sourceName); + loadProductItem(sourceId, *sourceItem); + } + else { + qCWarning(LOG_DataSourceController()) << tr("requestVariable, product data not found"); + } +} + void DataSourceController::waitForFinish() { QMutexLocker locker{&impl->m_WorkingMutex}; diff --git a/core/src/DataSource/DataSourceItem.cpp b/core/src/DataSource/DataSourceItem.cpp index cf316d8..a1fe8e7 100644 --- a/core/src/DataSource/DataSourceItem.cpp +++ b/core/src/DataSource/DataSourceItem.cpp @@ -123,6 +123,24 @@ DataSourceItemType DataSourceItem::type() const noexcept return impl->m_Type; } +DataSourceItem *DataSourceItem::findItem(const QVariantHash &data, bool recursive) +{ + for (const auto &child : impl->m_Children) { + if (child->impl->m_Data == data) { + return child.get(); + } + + if (recursive) { + auto foundItem = child->findItem(data, true); + if (foundItem) { + return foundItem; + } + } + } + + return nullptr; +} + bool DataSourceItem::operator==(const DataSourceItem &other) { // Compares items' attributes diff --git a/core/src/Variable/VariableController.cpp b/core/src/Variable/VariableController.cpp index 5377542..0a6fbb1 100644 --- a/core/src/Variable/VariableController.cpp +++ b/core/src/Variable/VariableController.cpp @@ -310,7 +310,7 @@ VariableController::variablesForMimeData(const QByteArray &mimeData) const stream >> ids; for (auto id : ids) { - auto uuid = QUuid(id.toByteArray()); + auto uuid = QUuid{id.toByteArray()}; auto var = impl->findVariable(uuid); variables << var; } diff --git a/core/src/Variable/VariableModel.cpp b/core/src/Variable/VariableModel.cpp index ccc9933..9ef8378 100644 --- a/core/src/Variable/VariableModel.cpp +++ b/core/src/Variable/VariableModel.cpp @@ -8,6 +8,7 @@ #include +#include #include #include #include @@ -267,7 +268,7 @@ Qt::ItemFlags VariableModel::flags(const QModelIndex &index) const Qt::DropActions VariableModel::supportedDropActions() const { - return Qt::MoveAction; + return Qt::CopyAction | Qt::MoveAction; } Qt::DropActions VariableModel::supportedDragActions() const @@ -304,13 +305,29 @@ QMimeData *VariableModel::mimeData(const QModelIndexList &indexes) const bool VariableModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const { - return false; + // drop of a product + return data->hasFormat(MIME_TYPE_PRODUCT_LIST); } bool VariableModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { - return false; + bool dropDone = false; + + if (data->hasFormat(MIME_TYPE_PRODUCT_LIST)) { + QDataStream stream(data->data(MIME_TYPE_PRODUCT_LIST)); + + QVariantList productList; + stream >> productList; + + for (auto metaData : productList) { + emit requestVariable(metaData.toHash()); + } + + dropDone = true; + } + + return dropDone; } void VariableModel::abortProgress(const QModelIndex &index) diff --git a/gui/include/DataSource/DataSourceTreeWidget.h b/gui/include/DataSource/DataSourceTreeWidget.h new file mode 100644 index 0000000..08043ba --- /dev/null +++ b/gui/include/DataSource/DataSourceTreeWidget.h @@ -0,0 +1,14 @@ +#ifndef SCIQLOP_DATASOURCETREEWIDGET_H +#define SCIQLOP_DATASOURCETREEWIDGET_H + +#include + +class DataSourceTreeWidget : public QTreeWidget { +public: + DataSourceTreeWidget(QWidget *parent); + +protected: + QMimeData *mimeData(const QList items) const override; +}; + +#endif // SCIQLOP_DATASOURCETREEWIDGET_H diff --git a/gui/src/DataSource/DataSourceTreeWidget.cpp b/gui/src/DataSource/DataSourceTreeWidget.cpp new file mode 100644 index 0000000..2e39d7e --- /dev/null +++ b/gui/src/DataSource/DataSourceTreeWidget.cpp @@ -0,0 +1,37 @@ +#include "DataSource/DataSourceTreeWidget.h" +#include "Common/MimeTypesDef.h" +#include "DataSource/DataSourceController.h" +#include "DataSource/DataSourceItem.h" +#include "DataSource/DataSourceTreeWidgetItem.h" + +#include "SqpApplication.h" + +#include + +DataSourceTreeWidget::DataSourceTreeWidget(QWidget *parent) : QTreeWidget(parent) {} + +QMimeData *DataSourceTreeWidget::mimeData(const QList items) const +{ + auto mimeData = new QMimeData; + + // Basic check to ensure the item are correctly typed + Q_ASSERT(items.isEmpty() || dynamic_cast(items.first()) != nullptr); + + QVariantList productData; + + for (auto item : items) { + auto dataSourceTreeItem = static_cast(item); + auto dataSource = dataSourceTreeItem->data(); + + if (dataSource->type() == DataSourceItemType::COMPONENT + || dataSource->type() == DataSourceItemType::PRODUCT) { + auto metaData = dataSource->data(); + productData << metaData; + } + } + + auto encodedData = sqpApp->dataSourceController().mimeDataForProductsData(productData); + mimeData->setData(MIME_TYPE_PRODUCT_LIST, encodedData); + + return mimeData; +} diff --git a/gui/src/DataSource/DataSourceTreeWidgetItem.cpp b/gui/src/DataSource/DataSourceTreeWidgetItem.cpp index df831ad..67bbeb1 100644 --- a/gui/src/DataSource/DataSourceTreeWidgetItem.cpp +++ b/gui/src/DataSource/DataSourceTreeWidgetItem.cpp @@ -129,6 +129,15 @@ DataSourceTreeWidgetItem::DataSourceTreeWidgetItem(QTreeWidget *parent, const Da auto itemActions = impl->m_Data->actions(); std::transform(std::cbegin(itemActions), std::cend(itemActions), std::back_inserter(impl->m_Actions), createTreeAction); + + // Sets the flags of the items + auto flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; + if (data->type() == DataSourceItemType::COMPONENT + || data->type() == DataSourceItemType::PRODUCT) { + flags |= Qt::ItemIsDragEnabled; + } + + setFlags(flags); } const DataSourceItem *DataSourceTreeWidgetItem::data() const diff --git a/gui/src/DragDropHelper.cpp b/gui/src/DragDropHelper.cpp index 7e91e83..a98ab82 100644 --- a/gui/src/DragDropHelper.cpp +++ b/gui/src/DragDropHelper.cpp @@ -248,6 +248,12 @@ QUrl DragDropHelper::imageTemporaryUrl(const QImage &image) const bool DragDropHelper::checkMimeDataForVisualization(const QMimeData *mimeData, VisualizationDragDropContainer *dropContainer) { + if (!mimeData || !dropContainer) { + qCWarning(LOG_DragDropHelper()) << QObject::tr( + "DragDropHelper::checkMimeDataForVisualization, invalid input parameters."); + Q_ASSERT(false); + } + auto result = true; if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) { diff --git a/gui/src/SqpApplication.cpp b/gui/src/SqpApplication.cpp index 09ee43b..7b200c1 100644 --- a/gui/src/SqpApplication.cpp +++ b/gui/src/SqpApplication.cpp @@ -8,6 +8,7 @@ #include