gfgit
30th April 2020, 15:11
Hi,
I'm expiriencing some problems with selection using a custom tree model and QTreeView.
Here is the code for the model:
#include "sessionstartendmodel.h"
#include <QDebug>
static constexpr quintptr STATION = quintptr(-1);
SessionStartEndModel::SessionStartEndModel(QObject *parent) :
QAbstractItemModel(parent),
m_mode(StartOfSession)
{
}
QVariant SessionStartEndModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if(orientation == Qt::Horizontal && role == Qt::DisplayRole)
{
switch (section)
{
case RsNameCol:
return tr("Rollingstock");
case JobCol:
return tr("Job");
case PlatfCol:
return tr("Platform");
case DepartureCol:
return m_mode == StartOfSession ? tr("Departure") : tr("Arrival");
default:
break;
}
}
return QAbstractItemModel::headerData(section, orientation, role);
}
QModelIndex SessionStartEndModel::index(int row, int column, const QModelIndex &p) const
{
if(p.isValid())
{
if(p.internalId() != STATION)
return QModelIndex();
//It's a rs
int parentRow = p.row();
if(parentRow < 0 || parentRow >= stations.size())
return QModelIndex();
if(row < 0 || (row + stations[parentRow].firstIdx) >= rsData.size() || column < 0 || column >= NCols)
return QModelIndex();
QModelIndex par = parent(createIndex(row, column, parentRow));
if(par != p)
{
qWarning() << "IDX ERROR" << p << par;
par = parent(createIndex(row, column, parentRow));
}
return createIndex(row, column, parentRow);
}
//Station
if(row < 0 || row >= stations.size() || column != 0)
return QModelIndex();
Q_ASSERT(parent(createIndex(row, column, STATION)) == p);
return createIndex(row, column, STATION);
}
QModelIndex SessionStartEndModel::parent(const QModelIndex &idx) const
{
if(!idx.isValid() || idx.internalId() == STATION)
return QModelIndex();
int parentRow = int(idx.internalId());
return createIndex(parentRow, 0, STATION);
}
int SessionStartEndModel::rowCount(const QModelIndex &p) const
{
if(p.isValid())
{
if(p.internalId() != STATION)
return 0; //RS
//Station
int firstIdx = stations.at(p.row()).firstIdx;
int lastIdx = rsData.size(); //Until end
if(p.row() + 1 < stations.size())
lastIdx = stations.at(p.row() + 1).firstIdx; //Until next station first index
return lastIdx - firstIdx;
}
//Root
return stations.size();
}
int SessionStartEndModel::columnCount(const QModelIndex &parent) const
{
return parent.isValid() ? 1 : NCols;
}
QVariant SessionStartEndModel::data(const QModelIndex &idx, int role) const
{
if(!idx.isValid())
return QVariant();
if(idx.internalId() == STATION)
{
//Station
switch (role)
{
case Qt::DisplayRole:
//return stations.at(idx.row()).stationId;
return Session->mStationsModel->getStName(stations.at(idx.row()).stationId); //TODO Station::name
case Qt::FontRole:
{
QFont f;
f.setBold(true);
return f;
}
}
}
else
{
//RS
int realIdx = stations.at(int(idx.internalId())).firstIdx + idx.row();
const RSItem& item = rsData.at(realIdx);
switch (role)
{
case Qt::DisplayRole:
{
switch (idx.column())
{
case RsNameCol:
//return item.rsId;
return Session->mRsModel->getRSName(item.rsId);
case JobCol:
//return item.jobId;
return Session->mJobsModel->getJobName(item.jobId);
case PlatfCol:
return utils::platformName(item.platform);
case DepartureCol:
return item.time;
}
}
}
}
return QVariant();
}
bool SessionStartEndModel::hasChildren(const QModelIndex &parent) const
{
if(parent.isValid())
{
if(parent.internalId() == STATION)
return true;
return false;
}
return stations.size();
}
QModelIndex SessionStartEndModel::sibling(int row, int column, const QModelIndex &idx) const
{
if(!idx.isValid())
return QModelIndex();
if(idx.internalId() == STATION)
{
if(row < stations.size() && column == 1)
return createIndex(row, column, STATION);
}
else
{
int stIdx = int(idx.internalId());
int firstIdx = stations.at(stIdx).firstIdx;
int lastIdx = rsData.size();
if(stIdx + 1 < stations.size())
lastIdx = stations.at(stIdx + 1).firstIdx;
int count = firstIdx - lastIdx;
if(row < count)
return createIndex(row, column, stIdx);
}
return QModelIndex();
}
Qt::ItemFlags SessionStartEndModel::flags(const QModelIndex &idx) const
{
Qt::ItemFlags f;
if(!idx.isValid())
return f;
f.setFlag(Qt::ItemIsEnabled);
f.setFlag(Qt::ItemIsSelectable);
if(idx.internalId() != STATION)
f.setFlag(Qt::ItemNeverHasChildren);
return f;
}
#ifndef SESSIONSTARTENDMODEL_H
#define SESSIONSTARTENDMODEL_H
#include <QAbstractItemModel>
#include <QVector>
#include <QTime>
#include "utils/types.h"
class SessionStartEndModel : public QAbstractItemModel
{
Q_OBJECT
public:
typedef struct Station_
{
db_id stationId;
QString name;
int firstIdx; //First RS index
} Station;
typedef struct RSItem_
{
db_id rsId;
int stationIdx;
int platform;
db_id jobId;
QTime time;
} RSItem;
enum Columns
{
RsNameCol = 0,
JobCol,
PlatfCol,
DepartureCol,
NCols
};
enum Mode
{
StartOfSession,
EndOfSession
};
explicit SessionStartEndModel(QObject *parent = nullptr);
// Header:
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
// Basic functionality:
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &idx) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
bool hasChildren(const QModelIndex &parent = QModelIndex()) const override;
QModelIndex sibling(int row, int column, const QModelIndex &idx) const override;
Qt::ItemFlags flags(const QModelIndex& idx) const override;
private:
QVector<Station> stations;
QVector<RSItem> rsData;
Mode m_mode;
};
#endif // SESSIONSTARTENDMODEL_H
The QTreeView should select the complete row:
view = new QTreeView(this);
view->setModel(model);
view->setSelectionBehavior(QAbstractItemView::SelectRows );
view->setSelectionMode(QAbstractItemView::SingleSelectio n);
Instead when I click on indexed on first column only 1 index gets selectd, when clicking on other columns nothing happens instead of selecting entire row.
When single clicking parent rows nothing happens (maybe this is intended behaviour)
Thanks in advance
I'm expiriencing some problems with selection using a custom tree model and QTreeView.
Here is the code for the model:
#include "sessionstartendmodel.h"
#include <QDebug>
static constexpr quintptr STATION = quintptr(-1);
SessionStartEndModel::SessionStartEndModel(QObject *parent) :
QAbstractItemModel(parent),
m_mode(StartOfSession)
{
}
QVariant SessionStartEndModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if(orientation == Qt::Horizontal && role == Qt::DisplayRole)
{
switch (section)
{
case RsNameCol:
return tr("Rollingstock");
case JobCol:
return tr("Job");
case PlatfCol:
return tr("Platform");
case DepartureCol:
return m_mode == StartOfSession ? tr("Departure") : tr("Arrival");
default:
break;
}
}
return QAbstractItemModel::headerData(section, orientation, role);
}
QModelIndex SessionStartEndModel::index(int row, int column, const QModelIndex &p) const
{
if(p.isValid())
{
if(p.internalId() != STATION)
return QModelIndex();
//It's a rs
int parentRow = p.row();
if(parentRow < 0 || parentRow >= stations.size())
return QModelIndex();
if(row < 0 || (row + stations[parentRow].firstIdx) >= rsData.size() || column < 0 || column >= NCols)
return QModelIndex();
QModelIndex par = parent(createIndex(row, column, parentRow));
if(par != p)
{
qWarning() << "IDX ERROR" << p << par;
par = parent(createIndex(row, column, parentRow));
}
return createIndex(row, column, parentRow);
}
//Station
if(row < 0 || row >= stations.size() || column != 0)
return QModelIndex();
Q_ASSERT(parent(createIndex(row, column, STATION)) == p);
return createIndex(row, column, STATION);
}
QModelIndex SessionStartEndModel::parent(const QModelIndex &idx) const
{
if(!idx.isValid() || idx.internalId() == STATION)
return QModelIndex();
int parentRow = int(idx.internalId());
return createIndex(parentRow, 0, STATION);
}
int SessionStartEndModel::rowCount(const QModelIndex &p) const
{
if(p.isValid())
{
if(p.internalId() != STATION)
return 0; //RS
//Station
int firstIdx = stations.at(p.row()).firstIdx;
int lastIdx = rsData.size(); //Until end
if(p.row() + 1 < stations.size())
lastIdx = stations.at(p.row() + 1).firstIdx; //Until next station first index
return lastIdx - firstIdx;
}
//Root
return stations.size();
}
int SessionStartEndModel::columnCount(const QModelIndex &parent) const
{
return parent.isValid() ? 1 : NCols;
}
QVariant SessionStartEndModel::data(const QModelIndex &idx, int role) const
{
if(!idx.isValid())
return QVariant();
if(idx.internalId() == STATION)
{
//Station
switch (role)
{
case Qt::DisplayRole:
//return stations.at(idx.row()).stationId;
return Session->mStationsModel->getStName(stations.at(idx.row()).stationId); //TODO Station::name
case Qt::FontRole:
{
QFont f;
f.setBold(true);
return f;
}
}
}
else
{
//RS
int realIdx = stations.at(int(idx.internalId())).firstIdx + idx.row();
const RSItem& item = rsData.at(realIdx);
switch (role)
{
case Qt::DisplayRole:
{
switch (idx.column())
{
case RsNameCol:
//return item.rsId;
return Session->mRsModel->getRSName(item.rsId);
case JobCol:
//return item.jobId;
return Session->mJobsModel->getJobName(item.jobId);
case PlatfCol:
return utils::platformName(item.platform);
case DepartureCol:
return item.time;
}
}
}
}
return QVariant();
}
bool SessionStartEndModel::hasChildren(const QModelIndex &parent) const
{
if(parent.isValid())
{
if(parent.internalId() == STATION)
return true;
return false;
}
return stations.size();
}
QModelIndex SessionStartEndModel::sibling(int row, int column, const QModelIndex &idx) const
{
if(!idx.isValid())
return QModelIndex();
if(idx.internalId() == STATION)
{
if(row < stations.size() && column == 1)
return createIndex(row, column, STATION);
}
else
{
int stIdx = int(idx.internalId());
int firstIdx = stations.at(stIdx).firstIdx;
int lastIdx = rsData.size();
if(stIdx + 1 < stations.size())
lastIdx = stations.at(stIdx + 1).firstIdx;
int count = firstIdx - lastIdx;
if(row < count)
return createIndex(row, column, stIdx);
}
return QModelIndex();
}
Qt::ItemFlags SessionStartEndModel::flags(const QModelIndex &idx) const
{
Qt::ItemFlags f;
if(!idx.isValid())
return f;
f.setFlag(Qt::ItemIsEnabled);
f.setFlag(Qt::ItemIsSelectable);
if(idx.internalId() != STATION)
f.setFlag(Qt::ItemNeverHasChildren);
return f;
}
#ifndef SESSIONSTARTENDMODEL_H
#define SESSIONSTARTENDMODEL_H
#include <QAbstractItemModel>
#include <QVector>
#include <QTime>
#include "utils/types.h"
class SessionStartEndModel : public QAbstractItemModel
{
Q_OBJECT
public:
typedef struct Station_
{
db_id stationId;
QString name;
int firstIdx; //First RS index
} Station;
typedef struct RSItem_
{
db_id rsId;
int stationIdx;
int platform;
db_id jobId;
QTime time;
} RSItem;
enum Columns
{
RsNameCol = 0,
JobCol,
PlatfCol,
DepartureCol,
NCols
};
enum Mode
{
StartOfSession,
EndOfSession
};
explicit SessionStartEndModel(QObject *parent = nullptr);
// Header:
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
// Basic functionality:
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &idx) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &idx, int role = Qt::DisplayRole) const override;
bool hasChildren(const QModelIndex &parent = QModelIndex()) const override;
QModelIndex sibling(int row, int column, const QModelIndex &idx) const override;
Qt::ItemFlags flags(const QModelIndex& idx) const override;
private:
QVector<Station> stations;
QVector<RSItem> rsData;
Mode m_mode;
};
#endif // SESSIONSTARTENDMODEL_H
The QTreeView should select the complete row:
view = new QTreeView(this);
view->setModel(model);
view->setSelectionBehavior(QAbstractItemView::SelectRows );
view->setSelectionMode(QAbstractItemView::SingleSelectio n);
Instead when I click on indexed on first column only 1 index gets selectd, when clicking on other columns nothing happens instead of selecting entire row.
When single clicking parent rows nothing happens (maybe this is intended behaviour)
Thanks in advance