Добрый вечер. Возник затык и без посторонней помощи, к сожалению, видимо, не обойдусь.
Есть модель дерева ListsRegisterModel, реализующая QAbstractItemModel. Есть QSortFilterProxyModel, к которой подключаю источником модель ListsRegisterModel. Вывожу ListsRegisterModel и прокси-модель в различные QTreeView.
И тут начинается странное. У меня пропали ветки второго уровня во втором отображении, хотя судя по виду, rowCount() отрабатывает правильно.
Код:
ListsRegisterModel *model = new ListsRegisterModel(this);
QSortFilterProxyModel *proxyModel = new QSortFilterProxyModel(this);
proxyModel->setSourceModel(model);
QTreeView *view = new QTreeView(this);
view->setModel(model);
QTreeView *view2 = new QTreeView(this);
view2->setModel(proxyModel);
class ListsRegisterModel : public QAbstractItemModel
{
Q_OBJECT
public:
explicit ListsRegisterModel(QObject *parent = 0);
~ListsRegisterModel();
QVariant data(const QModelIndex &index, int role) const;
Qt::ItemFlags flags(const QModelIndex &index) const;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const;
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex &index) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
bool setData(const QModelIndex &index, const QVariant &value,
int role = Qt::CheckStateRole);
private:
enum Columns
{
RamificationColumn,
ListNameColumn = RamificationColumn,
ListSubscriberColumn
};
TreeItem *rootItem;
/**
* @brief parseListsFile разбираем структуру файла с описаниями списков
* @param path путь к файлу с регистром списков
* @return QMultiMap<имя_списка, адрес получателя>
*/
QMultiMap<QString, QString> parseListsFile(QString path);
/**
* @brief setupModelData первоначальная настройка модели
* @param lists multiMap с регистром списков
* @param parent корневой элемент дерева
*/
void setupModelData(QMultiMap<QString, QString> lists, TreeItem *parent);
TreeItem *getItem(const QModelIndex &index) const;
};
#include "listsregistermodel.h"
#include <QtCore>
#include "../treeItem/treeitem.h"
ListsRegisterModel::ListsRegisterModel(QObject *parent) :
QAbstractItemModel(parent)
{
QList<QVariant> rootData;
rootData << tr("Имя") << tr("Абоненты");
rootItem = new TreeItem(rootData);
QMultiMap<QString, QString> listsReg = parseListsFile("etc/lists.reg");
setupModelData(listsReg, rootItem);
}
void ListsRegisterModel::setupModelData(
QMultiMap<QString, QString> lists, TreeItem *parent)
{
TreeItem *root = parent;
QList<TreeItem*> parents;
parents << root;
foreach (QString listName, lists.uniqueKeys()) {
root->appendChild(new TreeItem(listName, root));
if (root->childCount() > 0) {
parents << root->child(root->childCount() - 1);
}
foreach (QString subscriber, lists.values(listName)) {
parents.last()->appendChild(
new TreeItem(subscriber, parents.last()));
}
}
}
QMultiMap<QString, QString> ListsRegisterModel::parseListsFile(QString path)
{
QMultiMap<QString, QString> listsRegister;
QRegExp rx("^(\\d{4})\\s+\\{(.+)\\}$");
QFile file(path);
if (!file.exists()) {
qWarning() << "Warning: file " << file.fileName() << " is not exist";
}
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qWarning() << "Warning: file " << file.fileName() << " didn't' open";
}
while (!file.atEnd()) {
// поиск регулярного выражения в следующей строке
rx.indexIn(file.readLine().trimmed());
// выбор абонентов выбранного списка
QStringList subscribers =
rx.cap(2).simplified().split(",", QString::KeepEmptyParts);
// заполнение MultiMap контейнера значениями <имя списка, абонент>
foreach (QString addr, subscribers) {
listsRegister.insertMulti(rx.cap(1), addr);
}
}
file.close();
return listsRegister;
}
ListsRegisterModel::~ListsRegisterModel()
{
delete rootItem;
}
QVariant ListsRegisterModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
TreeItem *item = getItem(index);
switch (role) {
case Qt::DisplayRole:
if (item->parent() == rootItem) {
return item->data(index.column());
}
else {
qDebug() << item->data(index.column() - 1);
return item->data(index.column() - 1);
}
break;
case Qt::CheckStateRole:
if (index.column() == RamificationColumn
&& item->parent() == rootItem) {
return QVariant(item->checkState());
}
break;
default:
return QVariant();
break;
}
return QVariant();
}
TreeItem *ListsRegisterModel::getItem(const QModelIndex &index) const
{
if (index.isValid()) {
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
if (item) return item;
}
return rootItem;
}
Qt::ItemFlags ListsRegisterModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return 0;
const Qt::ItemFlags f = QAbstractItemModel::flags(index);
TreeItem * item = getItem(index);
if (index.column() == RamificationColumn && item->parent() == rootItem) {
return f | Qt::ItemIsUserCheckable;
}
return f;
}
QVariant ListsRegisterModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
return rootItem->data(section);
return QVariant();
}
QModelIndex ListsRegisterModel::index(int row, int column, const QModelIndex &parent) const
{
TreeItem * parentItem;
if (row < 0 || column < 0)
return QModelIndex();
if (!parent.isValid())
parentItem = rootItem;
else
parentItem = getItem(parent);
TreeItem *childItem = parentItem->child(row);
if (childItem)
return createIndex(row, column, childItem);
return QModelIndex();
}
QModelIndex ListsRegisterModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();
TreeItem *childItem = getItem(index);
TreeItem *parentItem = childItem->parent();
if (parentItem == rootItem)
return QModelIndex();
return createIndex(parentItem->row(), 0, parentItem);
}
int ListsRegisterModel::rowCount(const QModelIndex &parent) const
{
TreeItem *parentItem;
if (parent.column() > 0)
return 0;
if (!parent.isValid())
parentItem = rootItem;
else
parentItem = static_cast<TreeItem*>(parent.internalPointer());
return parentItem->childCount();
}
int ListsRegisterModel::columnCount(const QModelIndex &parent) const
{
if (parent.isValid())
return static_cast<TreeItem*>(parent.internalPointer())->columnCount();
else
return rootItem->columnCount();
}
bool ListsRegisterModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (role != Qt::CheckStateRole)
return false;
TreeItem *item = getItem(index);
Qt::CheckState state
= (value.toInt() == Qt::Checked) ? Qt::Checked : Qt::Unchecked;
item->setCheckState(state);
emit dataChanged(index, index);
return true;
}