Basic version of ConnectionTreeModel is working.

This commit is contained in:
eelke 2019-08-25 15:33:51 +02:00
parent 3721808df4
commit 8840d3bcbb
8 changed files with 348 additions and 3 deletions

View file

@ -4,12 +4,89 @@
#include <botan/cryptobox.h>
#include <QDir>
#include <QStandardPaths>
#include <QSettings>
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
#include <QStandardPaths>
namespace {
const char * const q_create_table_conngroup =
R"__(
CREATE TABLE IF NOT EXISTS conngroup (
conngroup_id INTEGER PRIMARY KEY,
gname TEXT NOT NULL
);)__";
const char * const q_create_table_connection =
R"__(
CREATE TABLE IF NOT EXISTS connection (
uuid TEXT PRIMARY KEY,
cname TEXT NOT NULL,
conngroup_id INTEGER NOT NULL,
host TEXT NOT NULL,
hostaddr TEXT NOT NULL,
port INTEGER NOT NULL,
user TEXT NOT NULL,
dbname TEXT NOT NULL,
sslmode INTEGER NOT NULL,
sslcert TEXT NOT NULL,
sslkey TEXT NOT NULL,
sslrootcert TEXT NOT NULL,
sslcrl TEXT NOT NULL,
passwordstate INTEGER NOT NULL
);)__";
const char * const q_insert_or_replace_into_connection =
R"__(INSERT OR REPLACE INTO connection
VALUES (:uuid, :name, :conngroup_id, :host, :hostaddr, :port, :user, :dbname,
:sslmode, :sslcert, :sslkey, :sslrootcert, :sslcrl, :passwordstate);
)__" ;
std::tuple<bool, QSqlError> InitConnectionTables(QSqlDatabase &db)
{
QSqlQuery q_create_table(db);
q_create_table.prepare(q_create_table_conngroup);
if (!q_create_table.exec()) {
auto err = q_create_table.lastError();
return { false, err };
}
q_create_table.prepare(q_create_table_connection);
if (!q_create_table.exec()) {
auto err = q_create_table.lastError();
return { false, err };
}
return {true, {}};
}
std::tuple<bool, QSqlError> SaveConnectionConfig(QSqlDatabase &db, const ConnectionConfig &cc, int conngroup_id)
{
QSqlQuery q(db);
q.prepare(q_insert_or_replace_into_connection);
q.bindValue(":uuid", cc.uuid().toString());
q.bindValue(":name", stdStrToQ(cc.name()));
q.bindValue(":conngroup_id", conngroup_id);
q.bindValue(":host", stdStrToQ(cc.host()));
q.bindValue(":hostaddr", stdStrToQ(cc.hostAddr()));
q.bindValue(":port", cc.port());
q.bindValue(":user", stdStrToQ(cc.user()));
q.bindValue(":dbname", stdStrToQ(cc.dbname()));
q.bindValue(":sslmode", static_cast<int>(cc.sslMode()));
q.bindValue(":sslcert", stdStrToQ(cc.sslCert()));
q.bindValue(":sslkey", stdStrToQ(cc.sslKey()));
q.bindValue(":sslrootcert", stdStrToQ(cc.sslRootCert()));
q.bindValue(":sslcrl", stdStrToQ(cc.sslCrl()));
q.bindValue(":passwordstate", static_cast<int>(cc.passwordState()));
if (!q.exec()) {
auto err = q.lastError();
return { false, err };
}
return {true, {}};
}
/** Saves a connection configuration.
Before calling this you may want to call beginGroup.
@ -31,6 +108,8 @@ namespace {
settings.setValue("passwordState", static_cast<int>(cc.passwordState()));
}
template <typename S, typename T>
bool in_range(T value)
{
@ -67,10 +146,10 @@ namespace {
}
} // end of unnamed namespace
ConnectionListModel::ConnectionListModel(QObject *parent)
: QAbstractListModel(parent)
{
@ -311,3 +390,164 @@ QString ConnectionListModel::iniFileName()
path += "/connections.ini";
return path;
}
ConnectionTreeModel::ConnectionTreeModel(QObject *parent, QSqlDatabase &db)
: QAbstractItemModel(parent)
, m_db(db)
{
}
void ConnectionTreeModel::load()
{
InitConnectionTables(m_db);
auto g1 = std::make_shared<ConnectionGroup>();
g1->name = "Testing";
for (int i = 1; i < 3; ++i) {
auto cc = std::make_shared<ConnectionConfig>();
cc->setUuid(QUuid::createUuid());
cc->setName("testconn " + std::to_string(i));
g1->add(cc);
}
auto g2 = std::make_shared<ConnectionGroup>();
g2->name = "Production";
for (int i = 1; i < 4; ++i) {
auto cc = std::make_shared<ConnectionConfig>();
cc->setUuid(QUuid::createUuid());
cc->setName("prodconn " + std::to_string(i));
g2->add(cc);
}
m_groups = { g1, g2 };
}
QVariant ConnectionTreeModel::data(const QModelIndex &index, int role) const
{
// Code below assumes two level tree groups/connections
// it will fail for nested groups
QVariant v;
auto privdata = static_cast<ConnectionNode*>(index.internalPointer());
if (auto group = dynamic_cast<ConnectionGroup*>(privdata); group != nullptr) {
// This is a group
if (role == Qt::DisplayRole) {
if (index.column() == Name) {
v = group->name;
}
}
}
else if (auto conn = dynamic_cast<ConnectionConfig*>(privdata); conn != nullptr) {
// This is a connection
if (role == Qt::DisplayRole) {
switch (index.column()) {
case Name: v = stdStrToQ(conn->name()); break;
case Host: v = stdStrToQ(conn->host()); break;
case Port: v = conn->port(); break;
case User: v = stdStrToQ(conn->user()); break;
case DbName: v= stdStrToQ(conn->dbname()); break;
}
}
}
return v;
}
QVariant ConnectionTreeModel::headerData(int section, Qt::Orientation orientation, int role) const
{
QVariant v;
if (orientation == Qt::Horizontal) {
if (role == Qt::DisplayRole) {
switch (section) {
case Name: v = tr("Name"); break;
case Host: v = tr("Host"); break;
case Port: v = tr("Port"); break;
case User: v = tr("User"); break;
case DbName: v= tr("Database"); break;
}
}
}
return v;
}
QModelIndex ConnectionTreeModel::index(int row, int column, const QModelIndex &parent) const
{
if (!hasIndex(row, column, parent))
return {};
const ConnectionNode *node = nullptr;
if (parent.isValid()) {
auto privdata = static_cast<ConnectionNode*>(parent.internalPointer());
if (auto group = dynamic_cast<ConnectionGroup*>(privdata); group != nullptr) {
node = group->connections().at(row).get();
}
else {
throw std::logic_error("Should never ask for a child index of a connectionconfig");
}
}
else {
node = m_groups[row].get();
}
return createIndex(row, column, const_cast<ConnectionNode*>(node));
// void *p = nullptr;
// if (parent.isValid()) {
// auto cg = static_cast<ConnectionGroup *>(parent.internalPointer());
// auto cc = &cg->connections().at(row);
// p = const_cast<ConnectionConfig*>(cc);
// }
// else {
// p = const_cast<ConnectionGroup*>(&m_groups.at(row));
// }
// return createIndex(row, column, p);
}
QModelIndex ConnectionTreeModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return {};
auto privdata = static_cast<ConnectionNode*>(index.internalPointer());
if (auto group = dynamic_cast<ConnectionGroup*>(privdata); group != nullptr) {
return {};
}
else if (auto config = dynamic_cast<ConnectionConfig*>(privdata); config != nullptr) {
auto p = config->parent();
auto find_res = std::find_if(m_groups.begin(), m_groups.end(), [p] (auto item) -> bool { return *p == *item; });
if (find_res != m_groups.end()) {
return createIndex(find_res - m_groups.begin(), 0, config->parent());
}
}
throw std::logic_error("Should never get here");
}
int ConnectionTreeModel::rowCount(const QModelIndex &parent) const
{
int result = 0;
if (parent.isValid()) {
// if (parent.column() <= 0) {
// result = m_groups[parent.row()].connections().size();
// }
// else {
// result = 1;
// }
auto privdata = static_cast<ConnectionNode*>(parent.internalPointer());
if (auto group = dynamic_cast<ConnectionGroup*>(privdata); group != nullptr) {
result = group->connections().size();
}
else if (auto config = dynamic_cast<ConnectionConfig*>(privdata); config != nullptr) {
result = 0;
}
}
else {
result = m_groups.size();
}
return result;
}
int ConnectionTreeModel::columnCount(const QModelIndex &parent) const
{
return ColCount;
}