Here is the working code I use for making tree model out of sql query:
TreeItem.hpp:
/**
@file
*/
#ifndef TEST_DATA_TREEITEM_HPP
#define TEST_DATA_TREEITEM_HPP
// Qt headers
#include <QtCore/QList>
#include <QtCore/QVariant>
namespace test{
namespace data {
class TreeItem
{
public:
TreeItem(const QList<QVariant>& data, TreeItem* parent = 0);
~TreeItem();
void AddChild(TreeItem* child);
TreeItem* GetChild(int rowIndex);
int GetNumberOfChildren() const;
int GetNumberOfColumns() const;
QVariant GetData
(int columnIndex
) const;
int GetRowIndex() const;
TreeItem* GetParent();
private:
QList<TreeItem*> _Children;
QList<QVariant> _ItemData;
TreeItem* _Parent;
};
} // namespace data
} // namespace test
#endif // TEST_DATA_TREEITEM_HP
/**
@file
*/
#ifndef TEST_DATA_TREEITEM_HPP
#define TEST_DATA_TREEITEM_HPP
// Qt headers
#include <QtCore/QList>
#include <QtCore/QVariant>
namespace test{
namespace data {
class TreeItem
{
public:
TreeItem(const QList<QVariant>& data, TreeItem* parent = 0);
~TreeItem();
void AddChild(TreeItem* child);
TreeItem* GetChild(int rowIndex);
int GetNumberOfChildren() const;
int GetNumberOfColumns() const;
QVariant GetData(int columnIndex) const;
int GetRowIndex() const;
TreeItem* GetParent();
private:
QList<TreeItem*> _Children;
QList<QVariant> _ItemData;
TreeItem* _Parent;
};
} // namespace data
} // namespace test
#endif // TEST_DATA_TREEITEM_HP
To copy to clipboard, switch view to plain text mode
TreeItem.cpp:
/**
@file
*/
// Project headers
#include "TreeItem.hpp"
namespace test {
namespace data {
TreeItem::TreeItem(const QList<QVariant>& data, TreeItem* parent)
{
_Parent = parent;
_ItemData = data;
}
TreeItem::~TreeItem()
{ qDeleteAll(_Children); }
void TreeItem::AddChild(TreeItem* child)
{ _Children.append(child); }
TreeItem* TreeItem::GetChild(int rowIndex)
{ return _Children.value(rowIndex); }
int TreeItem::GetNumberOfChildren() const
{ return _Children.count(); }
int TreeItem::GetNumberOfColumns() const
{ return _ItemData.count(); }
QVariant TreeItem
::GetData(int columnIndex
) const { return _ItemData.value(columnIndex); }
TreeItem* TreeItem::GetParent()
{ return _Parent; }
int TreeItem::GetRowIndex() const
{
if (_Parent)
return _Parent->_Children.indexOf(const_cast<TreeItem*>(this));
return 0;
}
} // namespace data
} // namespace test
/**
@file
*/
// Project headers
#include "TreeItem.hpp"
namespace test {
namespace data {
TreeItem::TreeItem(const QList<QVariant>& data, TreeItem* parent)
{
_Parent = parent;
_ItemData = data;
}
TreeItem::~TreeItem()
{ qDeleteAll(_Children); }
void TreeItem::AddChild(TreeItem* child)
{ _Children.append(child); }
TreeItem* TreeItem::GetChild(int rowIndex)
{ return _Children.value(rowIndex); }
int TreeItem::GetNumberOfChildren() const
{ return _Children.count(); }
int TreeItem::GetNumberOfColumns() const
{ return _ItemData.count(); }
QVariant TreeItem::GetData(int columnIndex) const
{ return _ItemData.value(columnIndex); }
TreeItem* TreeItem::GetParent()
{ return _Parent; }
int TreeItem::GetRowIndex() const
{
if (_Parent)
return _Parent->_Children.indexOf(const_cast<TreeItem*>(this));
return 0;
}
} // namespace data
} // namespace test
To copy to clipboard, switch view to plain text mode
SqlTreeModel.hpp:
/**
@file
*/
#ifndef TEST_DATA_SQLTREEMODEL_HPP
#define TEST_DATA_SQLTREEMODEL_HPP
// Qt headers
#include <QtCore/QAbstractItemModel>
#include <QtSql/QSqlQuery>
namespace test {
namespace data {
// Forward declarations
class TreeItem;
{
Q_OBJECT
public:
SqlTreeModel
(QObject* parent
= NULL);
~SqlTreeModel();
void SetQuery(const QSqlQuery& query);
bool Select();
void SetGroupByIndexes(const QList<int>& columnIndexes);
void SetGroupTitleFormat(const QString& format);
QVariant GetData
(const QModelIndex
& index,
int role
) const;
Qt::ItemFlags GetFlags(const QModelIndex& index) const;
QVariant GetHeaderData
(int section, Qt
::Orientation orientation,
int role
= Qt
::DisplayRole) const;
int rowCount
(const QModelIndex
& parent
= QModelIndex()) const;
int columnCount
(const QModelIndex
& parent
= QModelIndex()) const;
private:
QVariant data
(const QModelIndex
& index,
int role
) const;
QVariant headerData
(int section, Qt
::Orientation orientation,
int role
= Qt
::DisplayRole) const;
TreeItem* _Root;
QList<int> _GroupColumns;
void Create(TreeItem* parent);
};
} // namespace data
} // namespace test
#endif // TEST_DATA_SQLTREEMODEL_HPP
/**
@file
*/
#ifndef TEST_DATA_SQLTREEMODEL_HPP
#define TEST_DATA_SQLTREEMODEL_HPP
// Qt headers
#include <QtCore/QAbstractItemModel>
#include <QtSql/QSqlQuery>
namespace test {
namespace data {
// Forward declarations
class TreeItem;
class SqlTreeModel : public QAbstractItemModel
{
Q_OBJECT
public:
SqlTreeModel(QObject* parent = NULL);
~SqlTreeModel();
void SetQuery(const QSqlQuery& query);
bool Select();
void SetGroupByIndexes(const QList<int>& columnIndexes);
void SetGroupTitleFormat(const QString& format);
QVariant GetData(const QModelIndex& index, int role) const;
Qt::ItemFlags GetFlags(const QModelIndex& index) const;
QVariant GetHeaderData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
QModelIndex GetIndex(int rowIndex, int columnIndex, const QModelIndex& parent = QModelIndex()) const;
QModelIndex GetParent(const QModelIndex& index) const;
int rowCount(const QModelIndex& parent = QModelIndex()) const;
int columnCount(const QModelIndex& parent = QModelIndex()) const;
private:
QVariant data(const QModelIndex& index, int role) const;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
QModelIndex index(int rowIndex, int columnIndex, const QModelIndex& parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex& index) const;
TreeItem* _Root;
QSqlQuery _Query;
QList<int> _GroupColumns;
QString _GroupTitleFormat;
void Create(TreeItem* parent);
};
} // namespace data
} // namespace test
#endif // TEST_DATA_SQLTREEMODEL_HPP
To copy to clipboard, switch view to plain text mode
SqlTreeModel.cpp:
/**
@file
*/
// Project headers
#include "TreeItem.hpp"
#include "SqlTreeModel.hpp"
// Qt headers
#include <QtCore/QTextStream>
#include <QtSql/QSqlRecord>
namespace test {
namespace data {
SqlTreeModel
::SqlTreeModel(QObject* parent
/* = NULL */) : _Root(NULL),
{
_GroupColumns << 0;
_GroupTitleFormat = "{0}";
}
SqlTreeModel::~SqlTreeModel()
{
if (_Root != NULL)
delete _Root;
}
void SqlTreeModel::SetQuery(const QSqlQuery& query)
{ _Query = query; }
bool SqlTreeModel::Select()
{
if (!_Query.isActive())
return false;
const int record_count = record.count();
QList<QVariant> root_data;
for (int i = 0; i < record_count; ++i)
{
if (_GroupColumns.indexOf(i) == -1)
root_data << record.fieldName(i);
}
_Root = new TreeItem(root_data);
Create(_Root);
return true;
}
void SqlTreeModel::SetGroupByIndexes(const QList<int>& columnIndexes)
{ _GroupColumns = columnIndexes; }
void SqlTreeModel::SetGroupTitleFormat(const QString& format)
{ _GroupTitleFormat = format; }
QVariant SqlTreeModel
::GetData( const QModelIndex
& index,
int role
) const {
return data(index, role);
}
QVariant SqlTreeModel
::data(const QModelIndex
& index,
int role
) const {
if (!index.isValid())
if (role != Qt::DisplayRole)
TreeItem* item = static_cast<TreeItem*>(index.internalPointer());
return item->GetData(index.column());
}
Qt::ItemFlags SqlTreeModel::GetFlags(const QModelIndex& index) const
{
if (!index.isValid())
return 0;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
QVariant SqlTreeModel
::GetHeaderData( int section, Qt
::Orientation orientation,
int role
/*= Qt::DisplayRole*/ ) const {
return headerData(section, orientation, role);
}
QVariant SqlTreeModel
::headerData(int section, Qt
::Orientation orientation,
int role
) const {
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
return _Root->GetData(section);
}
QModelIndex SqlTreeModel
::GetIndex( int rowIndex,
int columnIndex,
const QModelIndex
& parent
/*= QModelIndex()*/ ) const {
return index(rowIndex, columnIndex, parent);
}
QModelIndex SqlTreeModel
::index(int rowIndex,
int columnIndex,
const QModelIndex
& parent
) const {
if (!hasIndex(rowIndex, columnIndex, parent))
TreeItem *parent_item;
if (!parent.isValid())
parent_item = _Root;
else
parent_item = static_cast<TreeItem*>(parent.internalPointer());
TreeItem *child_item = parent_item->GetChild(rowIndex);
if (child_item)
return createIndex(rowIndex, columnIndex, child_item);
else
}
QModelIndex SqlTreeModel
::GetParent( const QModelIndex
& index
) const {
return parent(index);
}
QModelIndex SqlTreeModel
::parent(const QModelIndex
& index
) const {
if (!index.isValid())
TreeItem* child_item = static_cast<TreeItem*>(index.internalPointer());
TreeItem* parent_item = child_item->GetParent();
if (parent_item == _Root)
return createIndex(parent_item->GetRowIndex(), 0, parent_item);
}
int SqlTreeModel::rowCount(const QModelIndex& parent) const
{
TreeItem* parent_item;
if (parent.column() > 0)
return 0;
if (!parent.isValid())
parent_item = _Root;
else
parent_item = static_cast<TreeItem*>(parent.internalPointer());
return parent_item->GetNumberOfChildren();
}
int SqlTreeModel::columnCount(const QModelIndex& parent) const
{
if (parent.isValid())
return static_cast<TreeItem*>(parent.internalPointer())->GetNumberOfColumns();
else
return _Root->GetNumberOfColumns();
}
void SqlTreeModel::Create(TreeItem* parent)
{
TreeItem* current_parent = parent;
while (_Query.next())
{
QString group_title
= _GroupTitleFormat;
const int group_columns_count = _GroupColumns.count();
const int number_of_columns = _Query.record().count();
for (int i = 0; i < group_columns_count; ++i)
{
const int column_index = _GroupColumns.at(i);
arg_stream << "{" << column_index << "}";
group_title.replace(column_arg, _Query.value(column_index).toString());
}
if (current_parent->GetData(0).toString() != group_title)
{
QList<QVariant> parent_data;
parent_data << group_title;
for (int i = 1; i < number_of_columns; ++i)
parent_data << "";
TreeItem* parent_item = new TreeItem(parent_data, parent);
parent->AddChild(parent_item);
current_parent = parent_item;
QList<QVariant> child_data;
for (int j = 0; j < number_of_columns; ++j)
{
if (_GroupColumns.indexOf(j) == -1)
child_data << _Query.record().value(j);
}
TreeItem* child_item = new TreeItem(child_data, current_parent);
current_parent->AddChild(child_item);
}
else
{
QList<QVariant> child_data;
for (int i = 0; i < number_of_columns; ++i)
{
if (_GroupColumns.indexOf(i) == -1)
child_data << _Query.record().value(i);
}
TreeItem* child_item = new TreeItem(child_data, current_parent);
current_parent->AddChild(child_item);
}
}
}
} // namespace data
} // namespace test
/**
@file
*/
// Project headers
#include "TreeItem.hpp"
#include "SqlTreeModel.hpp"
// Qt headers
#include <QtCore/QTextStream>
#include <QtSql/QSqlRecord>
namespace test {
namespace data {
SqlTreeModel::SqlTreeModel(QObject* parent /* = NULL */)
: _Root(NULL),
QAbstractItemModel(parent)
{
_GroupColumns << 0;
_GroupTitleFormat = "{0}";
}
SqlTreeModel::~SqlTreeModel()
{
if (_Root != NULL)
delete _Root;
}
void SqlTreeModel::SetQuery(const QSqlQuery& query)
{ _Query = query; }
bool SqlTreeModel::Select()
{
if (!_Query.isActive())
return false;
QSqlRecord record = _Query.record();
const int record_count = record.count();
QList<QVariant> root_data;
for (int i = 0; i < record_count; ++i)
{
if (_GroupColumns.indexOf(i) == -1)
root_data << record.fieldName(i);
}
_Root = new TreeItem(root_data);
Create(_Root);
return true;
}
void SqlTreeModel::SetGroupByIndexes(const QList<int>& columnIndexes)
{ _GroupColumns = columnIndexes; }
void SqlTreeModel::SetGroupTitleFormat(const QString& format)
{ _GroupTitleFormat = format; }
QVariant SqlTreeModel::GetData( const QModelIndex& index, int role ) const
{
return data(index, role);
}
QVariant SqlTreeModel::data(const QModelIndex& index, int role) const
{
if (!index.isValid())
return QVariant();
if (role != Qt::DisplayRole)
return QVariant();
TreeItem* item = static_cast<TreeItem*>(index.internalPointer());
return item->GetData(index.column());
}
Qt::ItemFlags SqlTreeModel::GetFlags(const QModelIndex& index) const
{
if (!index.isValid())
return 0;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}
QVariant SqlTreeModel::GetHeaderData( int section, Qt::Orientation orientation, int role /*= Qt::DisplayRole*/ ) const
{
return headerData(section, orientation, role);
}
QVariant SqlTreeModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
return _Root->GetData(section);
return QVariant();
}
QModelIndex SqlTreeModel::GetIndex( int rowIndex, int columnIndex, const QModelIndex& parent /*= QModelIndex()*/ ) const
{
return index(rowIndex, columnIndex, parent);
}
QModelIndex SqlTreeModel::index(int rowIndex, int columnIndex, const QModelIndex& parent) const
{
if (!hasIndex(rowIndex, columnIndex, parent))
return QModelIndex();
TreeItem *parent_item;
if (!parent.isValid())
parent_item = _Root;
else
parent_item = static_cast<TreeItem*>(parent.internalPointer());
TreeItem *child_item = parent_item->GetChild(rowIndex);
if (child_item)
return createIndex(rowIndex, columnIndex, child_item);
else
return QModelIndex();
}
QModelIndex SqlTreeModel::GetParent( const QModelIndex& index ) const
{
return parent(index);
}
QModelIndex SqlTreeModel::parent(const QModelIndex& index) const
{
if (!index.isValid())
return QModelIndex();
TreeItem* child_item = static_cast<TreeItem*>(index.internalPointer());
TreeItem* parent_item = child_item->GetParent();
if (parent_item == _Root)
return QModelIndex();
return createIndex(parent_item->GetRowIndex(), 0, parent_item);
}
int SqlTreeModel::rowCount(const QModelIndex& parent) const
{
TreeItem* parent_item;
if (parent.column() > 0)
return 0;
if (!parent.isValid())
parent_item = _Root;
else
parent_item = static_cast<TreeItem*>(parent.internalPointer());
return parent_item->GetNumberOfChildren();
}
int SqlTreeModel::columnCount(const QModelIndex& parent) const
{
if (parent.isValid())
return static_cast<TreeItem*>(parent.internalPointer())->GetNumberOfColumns();
else
return _Root->GetNumberOfColumns();
}
void SqlTreeModel::Create(TreeItem* parent)
{
TreeItem* current_parent = parent;
while (_Query.next())
{
QString group_title = _GroupTitleFormat;
const int group_columns_count = _GroupColumns.count();
const int number_of_columns = _Query.record().count();
for (int i = 0; i < group_columns_count; ++i)
{
const int column_index = _GroupColumns.at(i);
QString column_arg;
QTextStream arg_stream(&column_arg);
arg_stream << "{" << column_index << "}";
group_title.replace(column_arg, _Query.value(column_index).toString());
}
if (current_parent->GetData(0).toString() != group_title)
{
QList<QVariant> parent_data;
parent_data << group_title;
for (int i = 1; i < number_of_columns; ++i)
parent_data << "";
TreeItem* parent_item = new TreeItem(parent_data, parent);
parent->AddChild(parent_item);
current_parent = parent_item;
QList<QVariant> child_data;
for (int j = 0; j < number_of_columns; ++j)
{
if (_GroupColumns.indexOf(j) == -1)
child_data << _Query.record().value(j);
}
TreeItem* child_item = new TreeItem(child_data, current_parent);
current_parent->AddChild(child_item);
}
else
{
QList<QVariant> child_data;
for (int i = 0; i < number_of_columns; ++i)
{
if (_GroupColumns.indexOf(i) == -1)
child_data << _Query.record().value(i);
}
TreeItem* child_item = new TreeItem(child_data, current_parent);
current_parent->AddChild(child_item);
}
}
}
} // namespace data
} // namespace test
To copy to clipboard, switch view to plain text mode
Use case:
QList<int> group_column_indexes;
group_column_indexes << 0; // group by column 0... can be any combination of column indexes
test::data::SqlTreeModel* model = new test::data::SqlTreeModel();
model->SetQuery(query); // SELECT ... statement, for example
model->SetGroupByIndexes(group_column_indexes);
// Note, that you must format this using same indexes for grouping...
// if we choose to hide columns 0, 3 & 4, then the code/format would be something like:
//
// group_column_indexes << 0 << 3 << 4
// ...
// model->SetGroupTitleFormat("Group {0} is grouped with {3} and {4}");
model->SetGroupTitleFormat("Group {0}");
model->Select();
_TrvPackages->setAllColumnsShowFocus(false);
_TrvPackages->setModel(model);
for (int i = 0; i < _TrvPackages->model()->rowCount(); ++i)
_TrvPackages
->setFirstColumnSpanned
(i,
QModelIndex(),
true);
_TrvPackages->expandAll();
QList<int> group_column_indexes;
group_column_indexes << 0; // group by column 0... can be any combination of column indexes
test::data::SqlTreeModel* model = new test::data::SqlTreeModel();
model->SetQuery(query); // SELECT ... statement, for example
model->SetGroupByIndexes(group_column_indexes);
// Note, that you must format this using same indexes for grouping...
// if we choose to hide columns 0, 3 & 4, then the code/format would be something like:
//
// group_column_indexes << 0 << 3 << 4
// ...
// model->SetGroupTitleFormat("Group {0} is grouped with {3} and {4}");
model->SetGroupTitleFormat("Group {0}");
model->Select();
_TrvPackages->setAllColumnsShowFocus(false);
_TrvPackages->setModel(model);
for (int i = 0; i < _TrvPackages->model()->rowCount(); ++i)
_TrvPackages->setFirstColumnSpanned(i, QModelIndex(), true);
_TrvPackages->expandAll();
To copy to clipboard, switch view to plain text mode
Bookmarks