Files
qt6-migration-pipeline/Lts/Common/LtsWidgets/lts_abstract_table_model.h
T

287 lines
6.3 KiB
C++
Executable File

#pragma once
#include "lts_base.h"
#include <LtsUtilsCore/data_modification_enum.h>
#include <QVector>
#include <QAbstractTableModel>
#include <memory>
#include <algorithm>
namespace LtsWidgets
{
template<class T>
class LtsAbstractTableModel : public QAbstractTableModel
{
public:
LtsAbstractTableModel(const QVector<QString> &header, QObject *parent)
: QAbstractTableModel(parent)
, m_vecColumns(header)
{}
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override
{
if (role == Qt::DisplayRole && orientation == Qt::Horizontal && section>= 0 && section < m_vecColumns.size())
return m_vecColumns[section];
return QAbstractTableModel::headerData(section, orientation, role);
}
bool isEmpty(const QModelIndex &parent = QModelIndex())
{
return parent.isValid() ? true : m_vecData.isEmpty();
}
int rowCount(const QModelIndex &parent = QModelIndex()) const override
{
return parent.isValid() ? 0 : m_vecData.size();
}
int columnCount(const QModelIndex &parent = QModelIndex()) const override
{
return parent.isValid() ? 0 : m_vecColumns.size();
}
void clear()
{
beginResetModel();
m_vecData.clear();
endResetModel();
}
bool indexIsValid(const QModelIndex &idx) const
{
if (!idx.isValid())
return false;
if (idx.row() < 0 || idx.row() >= m_vecData.size())
return false;
return true;
}
virtual bool removeRow(int row)
{
return removeRows(row, 1);
}
bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override
{
if (parent.isValid())
return false;
if (row < 0 || row >= m_vecData.size())
return false;
int range = std::min(row + count, m_vecData.size());
beginRemoveRows(QModelIndex(), row, range - 1);
m_vecData.erase(m_vecData.begin() + row, m_vecData.begin() + range);
endRemoveRows();
return true;
}
virtual bool insertRow(const T &item)
{
if (isFiltered(item, DataModification::eAdded) || isDeletedInternal(item))
return false;
beginInsertRows(QModelIndex(), m_vecData.size(), m_vecData.size());
m_vecData.append(item);
endInsertRows();
return true;
}
template <typename CONT>
void insertRows(const CONT &items)
{
if (items.isEmpty())
return;
const int cntBefore = m_vecData.size();
for (const auto &item : items)
{
if (isFiltered(item, DataModification::eAdded) || isDeletedInternal(item))
continue;
m_vecData += item;
}
const int cntAfter = m_vecData.size();
if (cntBefore == cntAfter)
return;
beginInsertRows(QModelIndex(), cntBefore, cntAfter - 1);
endInsertRows();
}
void setData(const QVector<T> &vecData)
{
clear();
insertRows(vecData);
}
void update()
{
if (!m_vecData.isEmpty())
emit dataChanged(index(0, 0), index(m_vecData.size() - 1, columnCount() - 1));
}
T getRowData(int row) const
{
if (row < 0 || row >= m_vecData.size())
return T();
return m_vecData.at(row);
}
bool setRowData(int row, const T &data)
{
if (row < 0 || row >= m_vecData.size())
return false;
m_vecData[row] = data;
emit dataChanged(index(row, 0), index(row, columnCount() - 1));
return true;
}
QModelIndex findIndexForId(int id, int column = 0) const
{
const int row = findRowForId(id);
if (row < 0)
return QModelIndex();
return index(row, column);
}
int getId(const QModelIndex &mi) const
{
if (!indexIsValid(mi))
return -1;
return getIdInternal(m_vecData.at(mi.row()));
}
protected:
template <class C>
class HasId
{
template <class CLS>
static std::true_type testSignature(const int &(CLS::*)() const);
template <class CLS>
static std::true_type testSignature(int (CLS::*)() const);
template <class CLS>
static decltype(testSignature(&CLS::id)) test(std::nullptr_t);
template <class CLS>
static std::false_type test(...);
public:
using type = decltype(test<C>(nullptr));
static const bool value = type::value;
};
template <typename F = T, typename std::enable_if<HasId<F>::value, int>::type = 0>
int getIdInternal(const F &data) const
{
return data.id();
}
virtual int getId(const T &data) const
{
Q_ASSERT(false);
Q_UNUSED(data);
return -1;
}
template < typename F = T, typename std::enable_if < !HasId<F>::value, int>::type = 0>
int getIdInternal(const F &data) const
{
return getId(data);
}
template <class C>
class HasIsDeleted
{
template <class CLS>
static std::true_type testSignature(const bool &(CLS::*)() const);
template <class CLS>
static std::true_type testSignature(bool (CLS::*)() const);
template <class CLS>
static decltype(testSignature(&CLS::isDeleted)) test(std::nullptr_t);
template <class CLS>
static std::false_type test(...);
public:
using type = decltype(test<C>(nullptr));
static const bool value = type::value;
};
template <typename F = T, typename std::enable_if<HasIsDeleted<F>::value, int>::type = 0>
bool isDeletedInternal(const F &data) const
{
return data.isDeleted();
}
virtual int isDeleted(const T &data) const
{
Q_UNUSED(data);
return false;
}
template < typename F = T, typename std::enable_if < !HasIsDeleted<F>::value, int>::type = 0>
bool isDeletedInternal(const F &data) const
{
return isDeleted(data);
}
virtual bool isFiltered(const T &data, DataModification modType) const
{
Q_UNUSED(data);
Q_UNUSED(modType);
return false;
}
virtual bool onDataChanged(const T &data, DataModification modType)
{
if (isFiltered(data, modType))
return false;
const int id = getIdInternal(data);
const int row = findRowForId(id);
if (modType == DataModification::eRemoved || isDeletedInternal(data))
{
if (row >= 0)
return removeRow(row);
return false;
}
if (modType == DataModification::eAdded && row < 0)
return insertRow(data);
return setRowData(row, data);
}
int findRowForId(int id) const
{
for (int i = 0; i < m_vecData.size(); ++i)
{
if (getIdInternal(m_vecData.at(i)) == id)
return i;
}
return -1;
}
QVector<T> m_vecData;
QVector<QString> m_vecColumns;
};
}