Imported existing sources

This commit is contained in:
0xFEEDC0DE64
2018-09-15 20:37:17 +02:00
parent 5cc62d31cf
commit 13dacbeca5
5 changed files with 389 additions and 0 deletions

23
DbDatabaseTree.pro Normal file
View 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
View 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
View 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
View 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
View 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