Imported existing sources
This commit is contained in:
23
DbDatabaseTree.pro
Normal file
23
DbDatabaseTree.pro
Normal file
@@ -0,0 +1,23 @@
|
||||
QT += core sql gui widgets
|
||||
|
||||
DBLIBS +=
|
||||
|
||||
TARGET = databasetree
|
||||
|
||||
PROJECT_ROOT = ..
|
||||
|
||||
SOURCES += main.cpp \
|
||||
mymodel.cpp
|
||||
|
||||
HEADERS += \
|
||||
mymodel.h
|
||||
|
||||
FORMS +=
|
||||
|
||||
RESOURCES +=
|
||||
|
||||
TRANSLATIONS +=
|
||||
|
||||
DISTFILES += install.sql
|
||||
|
||||
include($${PROJECT_ROOT}/app.pri)
|
96
install.sql
Normal file
96
install.sql
Normal file
@@ -0,0 +1,96 @@
|
||||
DROP TABLE IF EXISTS `Tree`;
|
||||
|
||||
CREATE TABLE `Tree` (
|
||||
`ID` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
`ParentID` INT UNSIGNED CHECK (`ID` <> `ParentID`),
|
||||
`Name` VARCHAR(255) NOT NULL,
|
||||
`Description` TEXT NOT NULL,
|
||||
UNIQUE(`ParentID`, `Name`),
|
||||
FOREIGN KEY (`ParentID`) REFERENCES `Tree`(`ID`)
|
||||
);
|
||||
|
||||
INSERT INTO `test`.`tree` (`ParentID`, `Name`, `Description`) VALUES
|
||||
(NULL, "root0", "Eine Testbeschreibung"),
|
||||
(NULL, "root1", "Eine Testbeschreibung"),
|
||||
(NULL, "root2", "Eine Testbeschreibung"),
|
||||
(NULL, "root3", "Eine Testbeschreibung"),
|
||||
(1, "root0sub0", "Eine Testbeschreibung"),
|
||||
(1, "root0sub1", "Eine Testbeschreibung"),
|
||||
(1, "root0sub2", "Eine Testbeschreibung"),
|
||||
(1, "root0sub3", "Eine Testbeschreibung"),
|
||||
(2, "root1sub0", "Eine Testbeschreibung"),
|
||||
(2, "root1sub1", "Eine Testbeschreibung"),
|
||||
(2, "root1sub2", "Eine Testbeschreibung"),
|
||||
(2, "root1sub3", "Eine Testbeschreibung"),
|
||||
(3, "root2sub0", "Eine Testbeschreibung"),
|
||||
(3, "root2sub1", "Eine Testbeschreibung"),
|
||||
(3, "root2sub2", "Eine Testbeschreibung"),
|
||||
(3, "root2sub3", "Eine Testbeschreibung"),
|
||||
(4, "root3sub0", "Eine Testbeschreibung"),
|
||||
(4, "root3sub1", "Eine Testbeschreibung"),
|
||||
(4, "root3sub2", "Eine Testbeschreibung"),
|
||||
(4, "root3sub3", "Eine Testbeschreibung"),
|
||||
(5, "root0sub0sub0", "Eine Testbeschreibung"),
|
||||
(5, "root0sub0sub1", "Eine Testbeschreibung"),
|
||||
(5, "root0sub0sub2", "Eine Testbeschreibung"),
|
||||
(5, "root0sub0sub3", "Eine Testbeschreibung"),
|
||||
(6, "root0sub1sub0", "Eine Testbeschreibung"),
|
||||
(6, "root0sub1sub1", "Eine Testbeschreibung"),
|
||||
(6, "root0sub1sub2", "Eine Testbeschreibung"),
|
||||
(6, "root0sub1sub3", "Eine Testbeschreibung"),
|
||||
(6, "root0sub2sub0", "Eine Testbeschreibung"),
|
||||
(7, "root0sub2sub1", "Eine Testbeschreibung"),
|
||||
(7, "root0sub2sub2", "Eine Testbeschreibung"),
|
||||
(7, "root0sub2sub3", "Eine Testbeschreibung"),
|
||||
(8, "root0sub3sub0", "Eine Testbeschreibung"),
|
||||
(8, "root0sub3sub1", "Eine Testbeschreibung"),
|
||||
(8, "root0sub3sub2", "Eine Testbeschreibung"),
|
||||
(8, "root0sub3sub3", "Eine Testbeschreibung"),
|
||||
(9, "root1sub0sub0", "Eine Testbeschreibung"),
|
||||
(9, "root1sub0sub1", "Eine Testbeschreibung"),
|
||||
(9, "root1sub0sub2", "Eine Testbeschreibung"),
|
||||
(9, "root1sub0sub3", "Eine Testbeschreibung"),
|
||||
(10, "root1sub1sub0", "Eine Testbeschreibung"),
|
||||
(10, "root1sub1sub1", "Eine Testbeschreibung"),
|
||||
(10, "root1sub1sub2", "Eine Testbeschreibung"),
|
||||
(10, "root1sub1sub3", "Eine Testbeschreibung"),
|
||||
(11, "root1sub2sub0", "Eine Testbeschreibung"),
|
||||
(11, "root1sub2sub1", "Eine Testbeschreibung"),
|
||||
(11, "root1sub2sub2", "Eine Testbeschreibung"),
|
||||
(11, "root1sub2sub3", "Eine Testbeschreibung"),
|
||||
(12, "root1sub3sub0", "Eine Testbeschreibung"),
|
||||
(12, "root1sub3sub1", "Eine Testbeschreibung"),
|
||||
(12, "root1sub3sub2", "Eine Testbeschreibung"),
|
||||
(12, "root1sub3sub3", "Eine Testbeschreibung"),
|
||||
(13, "root2sub0sub0", "Eine Testbeschreibung"),
|
||||
(13, "root2sub0sub1", "Eine Testbeschreibung"),
|
||||
(13, "root2sub0sub2", "Eine Testbeschreibung"),
|
||||
(13, "root2sub0sub3", "Eine Testbeschreibung"),
|
||||
(14, "root2sub1sub0", "Eine Testbeschreibung"),
|
||||
(14, "root2sub1sub1", "Eine Testbeschreibung"),
|
||||
(14, "root2sub1sub2", "Eine Testbeschreibung"),
|
||||
(14, "root2sub1sub3", "Eine Testbeschreibung"),
|
||||
(15, "root2sub2sub0", "Eine Testbeschreibung"),
|
||||
(15, "root2sub2sub1", "Eine Testbeschreibung"),
|
||||
(15, "root2sub2sub2", "Eine Testbeschreibung"),
|
||||
(15, "root2sub2sub3", "Eine Testbeschreibung"),
|
||||
(16, "root2sub3sub0", "Eine Testbeschreibung"),
|
||||
(16, "root2sub3sub1", "Eine Testbeschreibung"),
|
||||
(16, "root2sub3sub2", "Eine Testbeschreibung"),
|
||||
(16, "root2sub3sub3", "Eine Testbeschreibung"),
|
||||
(17, "root3sub0sub0", "Eine Testbeschreibung"),
|
||||
(17, "root3sub0sub1", "Eine Testbeschreibung"),
|
||||
(17, "root3sub0sub2", "Eine Testbeschreibung"),
|
||||
(17, "root3sub0sub3", "Eine Testbeschreibung"),
|
||||
(18, "root3sub1sub0", "Eine Testbeschreibung"),
|
||||
(18, "root3sub1sub1", "Eine Testbeschreibung"),
|
||||
(18, "root3sub1sub2", "Eine Testbeschreibung"),
|
||||
(18, "root3sub1sub3", "Eine Testbeschreibung"),
|
||||
(19, "root3sub2sub0", "Eine Testbeschreibung"),
|
||||
(19, "root3sub2sub1", "Eine Testbeschreibung"),
|
||||
(19, "root3sub2sub2", "Eine Testbeschreibung"),
|
||||
(19, "root3sub2sub3", "Eine Testbeschreibung"),
|
||||
(20, "root3sub3sub0", "Eine Testbeschreibung"),
|
||||
(20, "root3sub3sub1", "Eine Testbeschreibung"),
|
||||
(20, "root3sub3sub2", "Eine Testbeschreibung"),
|
||||
(20, "root3sub3sub3", "Eine Testbeschreibung");
|
29
main.cpp
Normal file
29
main.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <QApplication>
|
||||
#include <QSqlDatabase>
|
||||
#include <QDebug>
|
||||
#include <QSqlError>
|
||||
#include <QTreeView>
|
||||
|
||||
#include "mymodel.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL", "myConnection");
|
||||
db.setHostName("localhost");
|
||||
db.setUserName("test");
|
||||
db.setPassword("test");
|
||||
db.setDatabaseName("test");
|
||||
if(!db.open())
|
||||
{
|
||||
qWarning() << db.lastError().text();
|
||||
return -1;
|
||||
}
|
||||
|
||||
QTreeView view;
|
||||
view.setModel(new MyModel(db, &app));
|
||||
view.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
171
mymodel.cpp
Normal file
171
mymodel.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
#include "mymodel.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QSqlError>
|
||||
|
||||
void ItemData::fetch(QSqlQuery &query)
|
||||
{
|
||||
if(m_fetched)
|
||||
{
|
||||
qWarning() << m_id << "already fetched";
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "loadChildrens" << m_id;
|
||||
|
||||
query.bindValue(":ParentID", m_id);
|
||||
if(!query.exec())
|
||||
{
|
||||
qWarning() << query.lastError().text();
|
||||
qFatal("could not execute query");
|
||||
return;
|
||||
}
|
||||
|
||||
while(query.next())
|
||||
m_childrens.append(new ItemData(this, query.value("ID").toUInt(), query.value("Name").toString(), query.value("Description").toString()));
|
||||
|
||||
m_fetched = true;
|
||||
}
|
||||
|
||||
MyModel::MyModel(QSqlDatabase &db, QObject *parent) :
|
||||
QAbstractItemModel(parent),
|
||||
m_db(db),
|
||||
m_query(m_db)
|
||||
{
|
||||
if(!m_query.prepare("SELECT `ID`, `Name`, `Description` FROM `Tree` WHERE (:ParentID = 0 AND `ParentID` IS NULL) OR (`ParentID` = :ParentID);"))
|
||||
{
|
||||
qWarning() << m_query.lastError().text();
|
||||
qFatal("could not prepare query");
|
||||
return;
|
||||
}
|
||||
|
||||
m_root = new ItemData(Q_NULLPTR, 0);
|
||||
//m_root->fetch(m_query);
|
||||
}
|
||||
|
||||
QModelIndex MyModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
if(!hasIndex(row, column, parent))
|
||||
return QModelIndex();
|
||||
|
||||
auto parentData = parent.isValid() ? static_cast<ItemData*>(parent.internalPointer()) : m_root;
|
||||
|
||||
auto childData = parentData->child(row);
|
||||
if (childData)
|
||||
return createIndex(row, column, childData);
|
||||
else
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
QModelIndex MyModel::parent(const QModelIndex &child) const
|
||||
{
|
||||
if(!child.isValid())
|
||||
return QModelIndex();
|
||||
|
||||
auto childData = static_cast<ItemData*>(child.internalPointer());
|
||||
auto parentData = childData->parent();
|
||||
|
||||
if(parentData == m_root)
|
||||
return QModelIndex();
|
||||
|
||||
return createIndex(parentData->row(), 0, parentData);
|
||||
}
|
||||
|
||||
int MyModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
if(parent.column() > 0)
|
||||
return 0;
|
||||
|
||||
auto parentData = parent.isValid() ? static_cast<ItemData*>(parent.internalPointer()) : m_root;
|
||||
|
||||
return parentData->childCount();
|
||||
}
|
||||
|
||||
int MyModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
return 2;
|
||||
}
|
||||
|
||||
QVariant MyModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if(!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
switch(role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
case Qt::EditRole:
|
||||
auto itemData = static_cast<ItemData*>(index.internalPointer());
|
||||
switch(index.column())
|
||||
{
|
||||
case 0: return itemData->name();
|
||||
case 1: return itemData->description();
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant MyModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
switch(orientation)
|
||||
{
|
||||
case Qt::Horizontal:
|
||||
switch(section)
|
||||
{
|
||||
case 0:
|
||||
switch(role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
case Qt::EditRole:
|
||||
return tr("Name");
|
||||
}
|
||||
case 1:
|
||||
switch(role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
case Qt::EditRole:
|
||||
return tr("Beschreibung");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Qt::Vertical:
|
||||
break;
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool MyModel::hasChildren(const QModelIndex &parent) const
|
||||
{
|
||||
if(parent.column() > 0)
|
||||
return false;
|
||||
|
||||
auto parentData = parent.isValid() ? static_cast<ItemData*>(parent.internalPointer()) : m_root;
|
||||
|
||||
if(!parentData->fetched())
|
||||
return true;
|
||||
|
||||
return parentData->childCount() > 0;
|
||||
}
|
||||
|
||||
void MyModel::fetchMore(const QModelIndex &parent)
|
||||
{
|
||||
if(parent.column() > 0)
|
||||
return;
|
||||
|
||||
auto parentData = parent.isValid() ? static_cast<ItemData*>(parent.internalPointer()) : m_root;
|
||||
|
||||
parentData->fetch(m_query);
|
||||
}
|
||||
|
||||
bool MyModel::canFetchMore(const QModelIndex &parent) const
|
||||
{
|
||||
if(parent.column() > 0)
|
||||
return false;
|
||||
|
||||
auto parentData = parent.isValid() ? static_cast<ItemData*>(parent.internalPointer()) : m_root;
|
||||
|
||||
return !parentData->fetched();
|
||||
}
|
70
mymodel.h
Normal file
70
mymodel.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#ifndef MYMODEL_H
|
||||
#define MYMODEL_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QSqlDatabase>
|
||||
#include <QSqlQuery>
|
||||
#include <QList>
|
||||
|
||||
class ItemData
|
||||
{
|
||||
public:
|
||||
inline explicit ItemData(ItemData *parent, quint32 id, const QString &name = QString(), const QString &description = QString()) :
|
||||
m_parent(parent),
|
||||
m_id(id),
|
||||
m_name(name),
|
||||
m_description(description),
|
||||
m_fetched(false)
|
||||
{}
|
||||
|
||||
inline ~ItemData() { qDeleteAll(m_childrens); }
|
||||
|
||||
inline ItemData *parent() const { return m_parent; }
|
||||
inline const QList<ItemData *> &childrens() const { return m_childrens; }
|
||||
inline quint32 id() const { return m_id; }
|
||||
inline const QString &name() const { return m_name; }
|
||||
inline const QString &description() const { return m_description; }
|
||||
inline bool fetched() const { return m_fetched; }
|
||||
|
||||
inline int row() { if(m_parent) return m_parent->childrens().indexOf(this); return 0; }
|
||||
inline ItemData *child(int row) const { return m_childrens.at(row); }
|
||||
inline int childCount() const { return m_childrens.count(); }
|
||||
|
||||
void fetch(QSqlQuery &query);
|
||||
|
||||
private:
|
||||
ItemData *m_parent;
|
||||
QList<ItemData *> m_childrens;
|
||||
quint32 m_id;
|
||||
QString m_name;
|
||||
QString m_description;
|
||||
bool m_fetched;
|
||||
};
|
||||
|
||||
class MyModel : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MyModel(QSqlDatabase &db, QObject *parent = 0);
|
||||
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent) const Q_DECL_OVERRIDE;
|
||||
QModelIndex parent(const QModelIndex &child) const Q_DECL_OVERRIDE;
|
||||
int rowCount(const QModelIndex &parent) const Q_DECL_OVERRIDE;
|
||||
int columnCount(const QModelIndex &parent) const Q_DECL_OVERRIDE;
|
||||
QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE;
|
||||
bool hasChildren(const QModelIndex &parent) const Q_DECL_OVERRIDE;
|
||||
void fetchMore(const QModelIndex &parent) Q_DECL_OVERRIDE;
|
||||
bool canFetchMore(const QModelIndex &parent) const Q_DECL_OVERRIDE;
|
||||
|
||||
private:
|
||||
void loadChildrens(ItemData *itemData);
|
||||
|
||||
QSqlDatabase &m_db;
|
||||
QSqlQuery m_query;
|
||||
ItemData *m_root;
|
||||
};
|
||||
|
||||
#endif // MYMODEL_H
|
Reference in New Issue
Block a user