PDA

View Full Version : QTreeView selection artifacts with custom tree model



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