##// END OF EJS Templates
New DataSources model class ready for integration...
New DataSources model class ready for integration Signed-off-by: Alexis Jeandet <alexis.jeandet@member.fsf.org>

File last commit:

r98:b081849458c2
r98:b081849458c2
Show More
datasources.cpp
288 lines | 9.9 KiB | text/x-c | CppLexer
/*------------------------------------------------------------------------------
* -- This file is a part of SciQLop
* -- Copyright (C) 2019, Plasma Physics Laboratory - CNRS
* --
* -- This program 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.
* --
* -- This program 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 this program; if not, write to the Free Software
* -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* -------------------------------------------------------------------------------*/
/*-- Author : Alexis Jeandet
* -- Mail : alexis.jeandet@lpp.polytechnique.fr
* -- alexis.jeandet@member.fsf.org
* ----------------------------------------------------------------------------*/
// https://doc.qt.io/qt-5/qtwidgets-itemviews-simpletreemodel-example.html
#include "DataSource/datasources.h"
#include "Common/MimeTypesDef.h"
#include "DataSource/DataSourceItemAction.h"
#include "containers/algorithms.hpp"
#include <QDataStream>
QString QVariant2QString(const QVariant& variant) noexcept
{
if(variant.canConvert<QVariantList>())
{
auto valueString = QStringLiteral("{");
auto variantList = variant.value<QVariantList>();
QStringList items;
std::transform(std::cbegin(variantList), std::cend(variantList),
std::back_inserter(items),
[](const auto& item) { return QVariant2QString(item); });
valueString.append(cpp_utils::containers::join(items, ", "));
valueString.append("}");
return valueString;
}
else
{
return variant.toString();
}
}
inline std::unique_ptr<DataSourceItem> make_folder_item(const QString& name)
{
return std::make_unique<DataSourceItem>(DataSourceItemType::NODE, name);
}
template<typename T>
DataSourceItem* walk_tree(
const T& path_list_begin, const T& path_list_end, DataSourceItem* root,
const std::function<DataSourceItem*(DataSourceItem*, DataSourceItem*,
const decltype(*std::declval<T>())&)>&
f = [](DataSourceItem* parent, DataSourceItem* node,
const auto& name) -> DataSourceItem* {
(void)parent;
(void)name;
return node;
})
{
std::for_each(path_list_begin, path_list_end,
[&root, &f](const auto& folder_name) mutable {
auto folder_ptr = root->findItem(folder_name);
root = f(root, folder_ptr, folder_name);
});
return root;
}
DataSourceItem* walk_tree(
const QString& path, DataSourceItem* root,
const std::function<DataSourceItem*(DataSourceItem*, DataSourceItem*,
const QString&)>& f =
[](DataSourceItem* parent, DataSourceItem* node,
const auto& name) -> DataSourceItem* {
(void)parent;
(void)name;
return node;
})
{
auto path_list = path.split('/', QString::SkipEmptyParts);
return walk_tree(std::cbegin(path_list), std::cend(path_list), root, f);
}
template<typename T>
DataSourceItem* make_path_items(const T& path_list_begin,
const T& path_list_end, DataSourceItem* root)
{
auto node_ctor = [](DataSourceItem* parent, DataSourceItem* node,
const auto& name) -> DataSourceItem* {
if(node == nullptr)
{
auto folder = make_folder_item(name);
node = folder.get();
parent->appendChild(std::move(folder));
}
return node;
};
return walk_tree(path_list_begin, path_list_end, root, node_ctor);
}
inline std::unique_ptr<DataSourceItem>
make_product_item(const QString& name, QVariantHash& metaData,
const QUuid& dataSourceUid, const QString& DATA_SOURCE_NAME,
DataSources* dataSources)
{
auto result = std::make_unique<DataSourceItem>(DataSourceItemType::PRODUCT,
name, metaData, dataSourceUid);
// Adds plugin name to product metadata
// TODO re-consider adding a name attribute to DataSourceItem class
result->setData(DataSourceItem::PLUGIN_DATA_KEY, DATA_SOURCE_NAME);
// result->setData(DataSourceItem::ID_DATA_KEY,
// metaData.value(DataSourceItem::NAME_DATA_KEY));
// Add action to load product from DataSources
result->addAction(std::make_unique<DataSourceItemAction>(
QObject::tr("Load %1 product").arg(name),
[dataSources](DataSourceItem& item) {
if(dataSources) { dataSources->createVariable(item); }
}));
return result;
}
QVariant DataSources::data(const QModelIndex& index, int role) const
{
if(!index.isValid()) return QVariant();
DataSourceItem* item = static_cast<DataSourceItem*>(index.internalPointer());
if(role == Qt::DisplayRole) { return item->name(); }
if(role == Qt::DecorationRole)
{ return _icons.value(item->icon(), QVariant{}); }
if(role == Qt::ToolTipRole)
{
auto result = QString{};
const auto& data = item->data();
std::for_each(data.constKeyValueBegin(), data.constKeyValueEnd(),
[&result](const auto& item) {
result.append(QString{"<b>%1:</b> %2<br/>"}.arg(
item.first, QVariant2QString(item.second)));
});
return result;
}
return QVariant();
}
QMimeData* DataSources::mimeData(const QModelIndexList& indexes) const
{
QVariantList productData;
std::for_each(std::cbegin(indexes), std::cend(indexes),
[&productData](const auto& index) {
if(index.isValid())
{
DataSourceItem* item =
static_cast<DataSourceItem*>(index.internalPointer());
if(item->isProductOrComponent())
{ productData.append(item->data()); }
}
});
// TODO refactor this later
// maybe just an encode function
QByteArray encodedData;
QDataStream stream{&encodedData, QIODevice::WriteOnly};
stream << productData;
auto mimeData = new QMimeData;
mimeData->setData(MIME_TYPE_PRODUCT_LIST, encodedData);
return mimeData;
}
int DataSources::columnCount(const QModelIndex& parent) const
{
(void)parent;
return 1;
}
int DataSources::rowCount(const QModelIndex& parent) const
{
DataSourceItem* parentItem;
if(parent.column() > 0) return 0;
if(!parent.isValid())
parentItem = _root;
else
parentItem = static_cast<DataSourceItem*>(parent.internalPointer());
return parentItem->childCount();
}
QModelIndex DataSources::parent(const QModelIndex& index) const
{
if(!index.isValid()) return QModelIndex();
DataSourceItem* childItem =
static_cast<DataSourceItem*>(index.internalPointer());
DataSourceItem* parentItem = childItem->parentItem();
if(parentItem == _root) return QModelIndex();
return createIndex(parentItem->index(), 0, parentItem);
}
QModelIndex DataSources::index(int row, int column,
const QModelIndex& parent) const
{
if(!hasIndex(row, column, parent)) return QModelIndex();
DataSourceItem* parentItem;
if(!parent.isValid())
parentItem = _root;
else
parentItem = static_cast<DataSourceItem*>(parent.internalPointer());
DataSourceItem* childItem = parentItem->child(row);
if(childItem) return createIndex(row, column, childItem);
return QModelIndex();
}
Qt::ItemFlags DataSources::flags(const QModelIndex& index) const
{
Qt::ItemFlags flags = Qt::NoItemFlags;
if(index.isValid())
{
flags |= Qt::ItemIsSelectable | Qt::ItemIsEnabled;
DataSourceItem* item =
static_cast<DataSourceItem*>(index.internalPointer());
if(item && item->isProductOrComponent())
{ flags |= Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; }
}
return flags;
}
// TODO This can be optimized to only use insert row and column
// this should be much faster than doing a ResetModel all the time
// but this is more difficult to implement
void DataSources::addDataSourceItem(
const QUuid& providerUid, const QString& path,
const QMap<QString, QString>& metaData) noexcept
{
beginResetModel();
auto path_list = path.split('/', QString::SkipEmptyParts);
auto name = *(std::cend(path_list) - 1);
auto path_item =
make_path_items(std::cbegin(path_list), std::cend(path_list) - 1, _root);
QVariantHash meta_data{{DataSourceItem::NAME_DATA_KEY, name}};
for(auto& key : metaData.keys())
{
meta_data[key] = metaData[key];
}
path_item->appendChild(
make_product_item(name, meta_data, providerUid, "test", this));
endResetModel();
}
void DataSources::addProvider(IDataProvider* provider) noexcept
{
_DataProviders.insert(
{provider->id(), std::unique_ptr<IDataProvider>{provider}});
}
void DataSources::updateNodeMetaData(
const QString& path, const QMap<QString, QString>& metaData) noexcept
{
auto node = walk_tree(path, _root);
if(node != nullptr)
{
std::for_each(
metaData.constKeyValueBegin(), metaData.constKeyValueEnd(),
[node](const auto& it) { node->setData(it.first, it.second, true); });
}
}
void DataSources::createVariable(const DataSourceItem& item)
{
if(auto ds_uuid = item.source_uuid();
ds_uuid.has_value() && item.isProductOrComponent())
{
if(auto data_source_it = _DataProviders.find(ds_uuid.value());
data_source_it != std::cend(_DataProviders))
emit createVariable(item.name(), item.data(), data_source_it->second);
}
}
void DataSources::setIcon(const QString& path, const QString& iconName)
{
auto node = walk_tree(path, _root);
if(node != nullptr) { node->setIcon(iconName); }
}