VariableModel2.cpp
279 lines
| 7.8 KiB
| text/x-c
|
CppLexer
r21 | #include <Common/DateUtils.h> | |||
#include <Common/MimeTypesDef.h> | ||||
#include <Common/StringUtils.h> | ||||
r27 | #include <Common/containers.h> | |||
r21 | #include <Data/IDataSeries.h> | |||
#include <DataSource/DataSourceController.h> | ||||
r67 | #include <QMimeData> | |||
#include <QSize> | ||||
#include <QTimer> | ||||
r21 | #include <Time/TimeController.h> | |||
r67 | #include <Variable/Variable2.h> | |||
#include <Variable/VariableController2.h> | ||||
#include <Variable/VariableModel2.h> | ||||
#include <unordered_map> | ||||
r21 | ||||
r67 | namespace | |||
{ | ||||
// Column indexes | ||||
const auto NAME_COLUMN = 0; | ||||
const auto TSTART_COLUMN = 1; | ||||
const auto TEND_COLUMN = 2; | ||||
const auto NBPOINTS_COLUMN = 3; | ||||
const auto UNIT_COLUMN = 4; | ||||
const auto MISSION_COLUMN = 5; | ||||
const auto PLUGIN_COLUMN = 6; | ||||
const auto NB_COLUMNS = 7; | ||||
// Column properties | ||||
const auto DEFAULT_HEIGHT = 25; | ||||
const auto DEFAULT_WIDTH = 100; | ||||
struct ColumnProperties | ||||
{ | ||||
ColumnProperties(const QString& name = {}, int width = DEFAULT_WIDTH, | ||||
r21 | int height = DEFAULT_HEIGHT) | |||
r67 | : m_Name{name}, m_Width{width}, m_Height{height} | |||
{} | ||||
r21 | ||||
QString m_Name; | ||||
int m_Width; | ||||
int m_Height; | ||||
r67 | }; | |||
const auto COLUMN_PROPERTIES = QHash<int, ColumnProperties>{ | ||||
{NAME_COLUMN, {QObject::tr("Name")}}, | ||||
{TSTART_COLUMN, {QObject::tr("tStart"), 180}}, | ||||
{TEND_COLUMN, {QObject::tr("tEnd"), 180}}, | ||||
{NBPOINTS_COLUMN, {QObject::tr("Nb points")}}, | ||||
{UNIT_COLUMN, {QObject::tr("Unit")}}, | ||||
{MISSION_COLUMN, {QObject::tr("Mission")}}, | ||||
{PLUGIN_COLUMN, {QObject::tr("Plugin")}}}; | ||||
QString uniqueName(const QString& defaultName, | ||||
const std::vector<std::shared_ptr<Variable2>>& variables) | ||||
{ | ||||
r21 | auto forbiddenNames = std::vector<QString>(variables.size()); | |||
std::transform(variables.cbegin(), variables.cend(), forbiddenNames.begin(), | ||||
r67 | [](const auto& variable) { return variable->name(); }); | |||
r21 | auto uniqueName = StringUtils::uniqueName(defaultName, forbiddenNames); | |||
Q_ASSERT(!uniqueName.isEmpty()); | ||||
return uniqueName; | ||||
r67 | } | |||
r21 | ||||
} // namespace | ||||
r67 | VariableModel2::VariableModel2(QObject* parent) : QAbstractTableModel{parent} {} | |||
r21 | ||||
r67 | int VariableModel2::columnCount(const QModelIndex& parent) const | |||
r21 | { | |||
r67 | Q_UNUSED(parent); | |||
r21 | ||||
r67 | return NB_COLUMNS; | |||
r21 | } | |||
r67 | int VariableModel2::rowCount(const QModelIndex& parent) const | |||
r21 | { | |||
r67 | Q_UNUSED(parent); | |||
return _variables.size(); | ||||
r21 | } | |||
r67 | QVariant VariableModel2::data(const QModelIndex& index, int role) const | |||
r21 | { | |||
r67 | if(!index.isValid()) { return QVariant{}; } | |||
r21 | ||||
r67 | if(index.row() < 0 || index.row() >= rowCount()) { return QVariant{}; } | |||
r21 | ||||
r67 | if(role == Qt::DisplayRole) | |||
{ | ||||
if(auto variable = _variables[index.row()]) | ||||
{ | ||||
switch(index.column()) | ||||
{ | ||||
case NAME_COLUMN: return variable->name(); | ||||
case TSTART_COLUMN: | ||||
{ | ||||
if(auto range = variable->realRange(); range.has_value()) | ||||
return DateUtils::dateTime(range.value().m_TStart) | ||||
.toString(DATETIME_FORMAT); | ||||
return QVariant{}; | ||||
r21 | } | |||
r67 | case TEND_COLUMN: | |||
{ | ||||
if(auto range = variable->realRange(); range.has_value()) | ||||
return DateUtils::dateTime(range.value().m_TEnd) | ||||
.toString(DATETIME_FORMAT); | ||||
return QVariant{}; | ||||
} | ||||
case NBPOINTS_COLUMN: return int(variable->nbPoints()); | ||||
case UNIT_COLUMN: | ||||
return variable->metadata().value(QStringLiteral("units")); | ||||
case MISSION_COLUMN: | ||||
return variable->metadata().value(QStringLiteral("mission")); | ||||
case PLUGIN_COLUMN: | ||||
return variable->metadata().value(QStringLiteral("plugin")); | ||||
default: | ||||
// No action | ||||
break; | ||||
} | ||||
r21 | } | |||
r67 | } | |||
else if(role == VariableRoles::ProgressRole) | ||||
{ | ||||
r21 | return QVariant{}; | |||
r67 | } | |||
return QVariant{}; | ||||
r21 | } | |||
r67 | QVariant VariableModel2::headerData(int section, Qt::Orientation orientation, | |||
int role) const | ||||
r21 | { | |||
r67 | if(role != Qt::DisplayRole && role != Qt::SizeHintRole) { return QVariant{}; } | |||
r21 | ||||
r67 | if(orientation == Qt::Horizontal) | |||
{ | ||||
auto propertiesIt = COLUMN_PROPERTIES.find(section); | ||||
if(propertiesIt != COLUMN_PROPERTIES.cend()) | ||||
{ | ||||
// Role is either DisplayRole or SizeHintRole | ||||
return (role == Qt::DisplayRole) | ||||
? QVariant{propertiesIt->m_Name} | ||||
: QVariant{ | ||||
QSize{propertiesIt->m_Width, propertiesIt->m_Height}}; | ||||
r21 | } | |||
r67 | } | |||
r21 | ||||
r67 | return QVariant{}; | |||
r21 | } | |||
r67 | Qt::ItemFlags VariableModel2::flags(const QModelIndex& index) const | |||
r21 | { | |||
r67 | return QAbstractTableModel::flags(index) | Qt::ItemIsDragEnabled | | |||
Qt::ItemIsDropEnabled; | ||||
r21 | } | |||
Qt::DropActions VariableModel2::supportedDropActions() const | ||||
{ | ||||
r67 | return Qt::CopyAction | Qt::MoveAction; | |||
r21 | } | |||
Qt::DropActions VariableModel2::supportedDragActions() const | ||||
{ | ||||
r67 | return Qt::CopyAction | Qt::MoveAction; | |||
r21 | } | |||
QStringList VariableModel2::mimeTypes() const | ||||
{ | ||||
r67 | return {MIME_TYPE_VARIABLE_LIST, MIME_TYPE_TIME_RANGE}; | |||
r21 | } | |||
r67 | QMimeData* VariableModel2::mimeData(const QModelIndexList& indexes) const | |||
r21 | { | |||
r67 | auto mimeData = new QMimeData; | |||
std::vector<std::shared_ptr<Variable2>> variables; | ||||
DateTimeRange firstTimeRange; | ||||
for(const auto& index : indexes) | ||||
{ | ||||
if(index.column() == 0) | ||||
{ // only the first column | ||||
auto variable = _variables[index.row()]; | ||||
if(variable.get() && index.isValid()) | ||||
{ | ||||
if(variables.size() == 0) | ||||
{ | ||||
// Gets the range of the first variable | ||||
firstTimeRange = variable->range(); | ||||
r21 | } | |||
r67 | variables.push_back(variable); | |||
} | ||||
r21 | } | |||
r67 | } | |||
r21 | ||||
r67 | auto variablesEncodedData = Variable2::mimeData(variables); | |||
mimeData->setData(MIME_TYPE_VARIABLE_LIST, variablesEncodedData); | ||||
r21 | ||||
r67 | if(variables.size() == 1) | |||
{ | ||||
// No time range MIME data if multiple variables are dragged | ||||
auto timeEncodedData = TimeController::mimeDataForTimeRange(firstTimeRange); | ||||
mimeData->setData(MIME_TYPE_TIME_RANGE, timeEncodedData); | ||||
} | ||||
r21 | ||||
r67 | return mimeData; | |||
r21 | } | |||
r67 | bool VariableModel2::canDropMimeData(const QMimeData* data, | |||
Qt::DropAction action, int row, int column, | ||||
const QModelIndex& parent) const | ||||
r21 | { | |||
r67 | Q_UNUSED(column); | |||
// drop of a product | ||||
return data->hasFormat(MIME_TYPE_PRODUCT_LIST) || | ||||
(data->hasFormat(MIME_TYPE_TIME_RANGE) && parent.isValid() && | ||||
!data->hasFormat(MIME_TYPE_VARIABLE_LIST)); | ||||
r21 | } | |||
r67 | bool VariableModel2::dropMimeData(const QMimeData* data, Qt::DropAction action, | |||
int row, int column, | ||||
const QModelIndex& parent) | ||||
r21 | { | |||
r67 | auto dropDone = false; | |||
r21 | ||||
r67 | if(data->hasFormat(MIME_TYPE_PRODUCT_LIST)) | |||
{ | ||||
auto productList = DataSourceController::productsDataForMimeData( | ||||
data->data(MIME_TYPE_PRODUCT_LIST)); | ||||
r21 | ||||
r67 | for(auto metaData : productList) | |||
{ | ||||
emit createVariable(metaData.toHash()); | ||||
r21 | } | |||
r67 | dropDone = true; | |||
} | ||||
else if(data->hasFormat(MIME_TYPE_TIME_RANGE) && parent.isValid()) | ||||
{ | ||||
auto variable = _variables[parent.row()]; | ||||
auto range = | ||||
TimeController::timeRangeForMimeData(data->data(MIME_TYPE_TIME_RANGE)); | ||||
r21 | ||||
r67 | emit asyncChangeRange(variable, range); | |||
r21 | ||||
r67 | dropDone = true; | |||
} | ||||
return dropDone; | ||||
r21 | } | |||
r32 | void VariableModel2::variableUpdated(QUuid id) noexcept | |||
r21 | { | |||
r67 | emit dataChanged(QModelIndex(), QModelIndex()); | |||
r27 | } | |||
r21 | ||||
r67 | void VariableModel2::variableAdded(const std::shared_ptr<Variable2>& variable) | |||
r27 | { | |||
r67 | if(!SciQLop::containers::contains(_variables, variable)) | |||
{ | ||||
beginInsertRows(QModelIndex(), this->_variables.size(), | ||||
this->_variables.size()); | ||||
this->_variables.push_back(variable); | ||||
endInsertRows(); | ||||
connect(variable.get(), &Variable2::updated, this, | ||||
&VariableModel2::variableUpdated); | ||||
} | ||||
r27 | } | |||
r67 | void VariableModel2::variableDeleted(const std::shared_ptr<Variable2>& variable) | |||
r27 | { | |||
r67 | auto it = std::find(_variables.begin(), _variables.end(), variable); | |||
if(it != _variables.end()) | ||||
{ | ||||
auto index = std::distance(_variables.begin(), it); | ||||
beginRemoveRows(QModelIndex(), index, index); | ||||
_variables.erase(it); | ||||
endRemoveRows(); | ||||
} | ||||
r21 | } | |||