Moved some parts to a static lib so both the executable and the tests can link to it.
Written additional tests.
This commit is contained in:
parent
0a809a7288
commit
d0ea9dfa0c
39 changed files with 1767 additions and 493 deletions
|
|
@ -57,7 +57,10 @@ ConnectionConfig::ConnectionConfig()
|
|||
|
||||
void ConnectionConfig::setName(std::string desc)
|
||||
{
|
||||
m_name = std::move(desc);
|
||||
if (m_name != desc) {
|
||||
m_dirty = true;
|
||||
m_name = std::move(desc);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::name() const
|
||||
|
|
@ -67,7 +70,10 @@ const std::string& ConnectionConfig::name() const
|
|||
|
||||
void ConnectionConfig::setHost(std::string host)
|
||||
{
|
||||
m_host = std::move(host);
|
||||
if (m_host != host) {
|
||||
m_dirty = true;
|
||||
m_host = std::move(host);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::host() const
|
||||
|
|
@ -77,7 +83,10 @@ const std::string& ConnectionConfig::host() const
|
|||
|
||||
void ConnectionConfig::setHostAddr(std::string v)
|
||||
{
|
||||
m_hostaddr = std::move(v);
|
||||
if (m_hostaddr != v) {
|
||||
m_dirty = true;
|
||||
m_hostaddr = std::move(v);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::hostAddr() const
|
||||
|
|
@ -87,7 +96,11 @@ const std::string& ConnectionConfig::hostAddr() const
|
|||
|
||||
void ConnectionConfig::setPort(unsigned short port)
|
||||
{
|
||||
m_port = std::to_string(port);
|
||||
auto p = std::to_string(port);
|
||||
if (m_port != p) {
|
||||
m_dirty = true;
|
||||
m_port = p;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned short ConnectionConfig::port() const
|
||||
|
|
@ -97,7 +110,11 @@ unsigned short ConnectionConfig::port() const
|
|||
|
||||
void ConnectionConfig::setUser(std::string v)
|
||||
{
|
||||
m_user = std::move(v);
|
||||
if (m_user != v) {
|
||||
m_dirty = true;
|
||||
m_user = std::move(v);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::user() const
|
||||
|
|
@ -107,7 +124,10 @@ const std::string& ConnectionConfig::user() const
|
|||
|
||||
void ConnectionConfig::setPassword(std::string v)
|
||||
{
|
||||
m_password = std::move(v);
|
||||
if (m_password != v) {
|
||||
m_dirty = true;
|
||||
m_password = std::move(v);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::password() const
|
||||
|
|
@ -117,7 +137,10 @@ const std::string& ConnectionConfig::password() const
|
|||
|
||||
void ConnectionConfig::setDbname(std::string v)
|
||||
{
|
||||
m_dbname = std::move(v);
|
||||
if (m_dbname != v) {
|
||||
m_dirty = true;
|
||||
m_dbname = std::move(v);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::dbname() const
|
||||
|
|
@ -127,7 +150,11 @@ const std::string& ConnectionConfig::dbname() const
|
|||
|
||||
void ConnectionConfig::setSslMode(SslMode m)
|
||||
{
|
||||
m_sslMode = SslModeToString(m);
|
||||
auto v = SslModeToString(m);
|
||||
if (m_sslMode != v) {
|
||||
m_dirty = true;
|
||||
m_sslMode = v;
|
||||
}
|
||||
}
|
||||
|
||||
SslMode ConnectionConfig::sslMode() const
|
||||
|
|
@ -137,7 +164,10 @@ SslMode ConnectionConfig::sslMode() const
|
|||
|
||||
void ConnectionConfig::setSslCert(std::string v)
|
||||
{
|
||||
m_sslCert = std::move(v);
|
||||
if (m_sslCert != v) {
|
||||
m_dirty = true;
|
||||
m_sslCert = std::move(v);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::sslCert() const
|
||||
|
|
@ -147,7 +177,10 @@ const std::string& ConnectionConfig::sslCert() const
|
|||
|
||||
void ConnectionConfig::setSslKey(std::string v)
|
||||
{
|
||||
m_sslKey = std::move(v);
|
||||
if (m_sslKey != v) {
|
||||
m_dirty = true;
|
||||
m_sslKey = std::move(v);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::sslKey() const
|
||||
|
|
@ -157,7 +190,10 @@ const std::string& ConnectionConfig::sslKey() const
|
|||
|
||||
void ConnectionConfig::setSslRootCert(std::string v)
|
||||
{
|
||||
m_sslRootCert = std::move(v);
|
||||
if (m_sslRootCert != v) {
|
||||
m_dirty = true;
|
||||
m_sslRootCert = std::move(v);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::sslRootCert() const
|
||||
|
|
@ -167,7 +203,10 @@ const std::string& ConnectionConfig::sslRootCert() const
|
|||
|
||||
void ConnectionConfig::setSslCrl(std::string v)
|
||||
{
|
||||
m_sslCrl = std::move(v);
|
||||
if (m_sslCrl != v) {
|
||||
m_dirty = true;
|
||||
m_sslCrl = std::move(v);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::sslCrl() const
|
||||
|
|
@ -210,3 +249,13 @@ bool ConnectionConfig::isSameDatabase(const ConnectionConfig &rhs) const
|
|||
&& m_password == rhs.m_password
|
||||
&& m_dbname == rhs.m_dbname;
|
||||
}
|
||||
|
||||
bool ConnectionConfig::dirty() const
|
||||
{
|
||||
return m_dirty;
|
||||
}
|
||||
|
||||
void ConnectionConfig::clean()
|
||||
{
|
||||
m_dirty = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,12 @@ enum class SslMode {
|
|||
verify_full=5
|
||||
};
|
||||
|
||||
enum class PasswordMode {
|
||||
Unsave,
|
||||
Encrypted,
|
||||
DontSave
|
||||
};
|
||||
|
||||
class ConnectionConfig {
|
||||
public:
|
||||
ConnectionConfig();
|
||||
|
|
@ -57,6 +63,9 @@ public:
|
|||
const char * const * getValues() const;
|
||||
|
||||
bool isSameDatabase(const ConnectionConfig &rhs) const;
|
||||
|
||||
bool dirty() const;
|
||||
void clean();
|
||||
private:
|
||||
std::string m_name;
|
||||
std::string m_host;
|
||||
|
|
@ -75,6 +84,8 @@ private:
|
|||
|
||||
std::string m_applicationName;
|
||||
|
||||
bool m_dirty = false;
|
||||
|
||||
static std::vector<const char*> s_keywords;
|
||||
mutable std::vector<const char*> m_values;
|
||||
};
|
||||
|
|
|
|||
148
src/ConnectionList.cpp
Normal file
148
src/ConnectionList.cpp
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
#include "ConnectionList.h"
|
||||
#include "scopeguard.h"
|
||||
#include "util.h"
|
||||
#include <QDir>
|
||||
#include <QStandardPaths>
|
||||
#include <QSettings>
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
/** Saves a connection configuration.
|
||||
|
||||
Before calling this you may want to call beginGroup.
|
||||
*/
|
||||
void SaveConnectionConfig(QSettings &settings, const ConnectionConfig &cc)
|
||||
{
|
||||
settings.setValue("name", stdStrToQ(cc.name()));
|
||||
settings.setValue("host", stdStrToQ(cc.host()));
|
||||
settings.setValue("hostaddr", stdStrToQ(cc.hostAddr()));
|
||||
settings.setValue("port", cc.port());
|
||||
settings.setValue("user", stdStrToQ(cc.user()));
|
||||
settings.setValue("password", stdStrToQ(cc.password()));
|
||||
settings.setValue("dbname", stdStrToQ(cc.dbname()));
|
||||
settings.setValue("sslmode", (int)cc.sslMode());
|
||||
settings.setValue("sslcert", stdStrToQ(cc.sslCert()));
|
||||
settings.setValue("sslkey", stdStrToQ(cc.sslKey()));
|
||||
settings.setValue("sslrootcert", stdStrToQ(cc.sslRootCert()));
|
||||
settings.setValue("sslcrl", stdStrToQ(cc.sslCrl()));
|
||||
}
|
||||
|
||||
void LoadConnectionConfig(QSettings &settings, ConnectionConfig &cc)
|
||||
{
|
||||
cc.setName(qvarToStdStr(settings.value("name")));
|
||||
cc.setHost(qvarToStdStr(settings.value("host")));
|
||||
cc.setHostAddr(qvarToStdStr(settings.value("hostaddr")));
|
||||
cc.setPort(settings.value("port", 5432).toInt());
|
||||
cc.setUser(qvarToStdStr(settings.value("user")));
|
||||
// std::string encpw = qvarToStdStr(settings.value("encryptedpw"));
|
||||
// if (encpw.empty()) {
|
||||
cc.setPassword(qvarToStdStr(settings.value("password")));
|
||||
// }
|
||||
// else {
|
||||
// cc.setEncryptedPassword(encpw);
|
||||
// }
|
||||
cc.setDbname(qvarToStdStr(settings.value("dbname")));
|
||||
cc.setSslMode((SslMode)settings.value("sslmode").toInt());
|
||||
cc.setSslCert(qvarToStdStr(settings.value("sslcert")));
|
||||
cc.setSslKey(qvarToStdStr(settings.value("sslkey")));
|
||||
cc.setSslRootCert(qvarToStdStr(settings.value("sslrootcert")));
|
||||
cc.setSslCrl(qvarToStdStr(settings.value("sslcrl")));
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // end of unnamed namespace
|
||||
|
||||
/// \todo should return an expected as creation of the folder can fail
|
||||
QString ConnectionList::iniFileName()
|
||||
{
|
||||
QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
||||
QDir dir(path);
|
||||
if (!dir.exists()) {
|
||||
dir.mkpath(".");
|
||||
}
|
||||
path += "/connections.ini";
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
ConnectionList::ConnectionList()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int ConnectionList::createNew()
|
||||
{
|
||||
m_connections.emplace_back(QUuid::createUuid(), ConnectionConfig());
|
||||
return m_connections.size()-1;
|
||||
}
|
||||
|
||||
void ConnectionList::remove(int idx, int count)
|
||||
{
|
||||
auto f = m_connections.begin() + idx;
|
||||
auto l = f + count;
|
||||
deleteFromIni(f, l);
|
||||
m_connections.erase(f, l);
|
||||
}
|
||||
|
||||
void ConnectionList::deleteFromIni(t_Connections::iterator begin, t_Connections::iterator end)
|
||||
{
|
||||
QString file_name = iniFileName();
|
||||
QSettings settings(file_name, QSettings::IniFormat);
|
||||
for (auto i = begin; i != end; ++i) {
|
||||
settings.remove(i->m_uuid.toString());
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionList::load()
|
||||
{
|
||||
QString file_name = iniFileName();
|
||||
QSettings settings(file_name, QSettings::IniFormat);
|
||||
auto groups = settings.childGroups();
|
||||
for (auto grp : groups) {
|
||||
if (grp == "c_IniGroupSecurity") {
|
||||
// Read security settings
|
||||
|
||||
} else {
|
||||
QUuid uuid(grp);
|
||||
if ( ! uuid.isNull() ) {
|
||||
settings.beginGroup(grp);
|
||||
SCOPE_EXIT { settings.endGroup(); };
|
||||
|
||||
ConnectionConfig cc;
|
||||
LoadConnectionConfig(settings, cc);
|
||||
m_connections.emplace_back(uuid, cc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionList::save()
|
||||
{
|
||||
QString file_name = iniFileName();
|
||||
QSettings settings(file_name, QSettings::IniFormat);
|
||||
for (auto& e : m_connections) {
|
||||
settings.beginGroup(e.m_uuid.toString());
|
||||
SCOPE_EXIT { settings.endGroup(); };
|
||||
|
||||
SaveConnectionConfig(settings, e.m_config);
|
||||
e.m_config.clean();
|
||||
}
|
||||
settings.sync();
|
||||
}
|
||||
|
||||
void ConnectionList::save(int index)
|
||||
{
|
||||
if (index >= 0 && index < (int)m_connections.size()) {
|
||||
auto& e = m_connections[index];
|
||||
if (e.m_config.dirty()) {
|
||||
QString file_name = iniFileName();
|
||||
QSettings settings(file_name, QSettings::IniFormat);
|
||||
settings.beginGroup(e.m_uuid.toString());
|
||||
SaveConnectionConfig(settings, e.m_config);
|
||||
e.m_config.clean();
|
||||
settings.sync();
|
||||
}
|
||||
}
|
||||
}
|
||||
54
src/ConnectionList.h
Normal file
54
src/ConnectionList.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
#ifndef CONNECTIONLIST_H
|
||||
#define CONNECTIONLIST_H
|
||||
|
||||
#include "ConnectionConfig.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QUuid>
|
||||
#include <vector>
|
||||
#include "Expected.h"
|
||||
|
||||
|
||||
class ConnectionList {
|
||||
private:
|
||||
static QString iniFileName();
|
||||
|
||||
public:
|
||||
|
||||
ConnectionList();
|
||||
int size() const { return m_connections.size(); }
|
||||
|
||||
ConnectionConfig& getConfigByIdx(int idx)
|
||||
{
|
||||
return m_connections.at(idx).m_config;
|
||||
}
|
||||
|
||||
int createNew();
|
||||
|
||||
void remove(int idx, int count);
|
||||
|
||||
void load();
|
||||
void save();
|
||||
void save(int index);
|
||||
|
||||
|
||||
private:
|
||||
class LijstElem {
|
||||
public:
|
||||
QUuid m_uuid;
|
||||
ConnectionConfig m_config;
|
||||
|
||||
LijstElem(const QUuid id, const ConnectionConfig &cfg)
|
||||
: m_uuid(id), m_config(cfg)
|
||||
{}
|
||||
};
|
||||
|
||||
using t_Connections = std::vector<LijstElem>;
|
||||
t_Connections m_connections;
|
||||
|
||||
void deleteFromIni(t_Connections::iterator begin, t_Connections::iterator end);
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // CONNECTIONLIST_H
|
||||
|
|
@ -1,74 +1,27 @@
|
|||
#include "connectionlistmodel.h"
|
||||
#include <QDir>
|
||||
#include <QStandardPaths>
|
||||
#include <QSettings>
|
||||
#include "ConnectionListModel.h"
|
||||
#include "ConnectionList.h"
|
||||
#include "scopeguard.h"
|
||||
#include "util.h"
|
||||
|
||||
inline QString stdStrToQ(const std::string &s)
|
||||
{
|
||||
return QString::fromUtf8(s.c_str());
|
||||
}
|
||||
|
||||
inline std::string qStrToStd(const QString &s)
|
||||
{
|
||||
return std::string(s.toUtf8().data());
|
||||
}
|
||||
|
||||
inline std::string qvarToStdStr(const QVariant &c)
|
||||
{
|
||||
return qStrToStd(c.toString());
|
||||
}
|
||||
#include <botan/cryptobox.h>
|
||||
|
||||
|
||||
/** Saves a connection configuration.
|
||||
|
||||
Before calling this you may want to call beginGroup.
|
||||
*/
|
||||
void SaveConnectionConfig(QSettings &settings, const ConnectionConfig &cc)
|
||||
{
|
||||
settings.setValue("name", stdStrToQ(cc.name()));
|
||||
settings.setValue("host", stdStrToQ(cc.host()));
|
||||
settings.setValue("hostaddr", stdStrToQ(cc.hostAddr()));
|
||||
settings.setValue("port", cc.port());
|
||||
settings.setValue("user", stdStrToQ(cc.user()));
|
||||
settings.setValue("password", stdStrToQ(cc.password()));
|
||||
settings.setValue("dbname", stdStrToQ(cc.dbname()));
|
||||
settings.setValue("sslmode", (int)cc.sslMode());
|
||||
settings.setValue("sslcert", stdStrToQ(cc.sslCert()));
|
||||
settings.setValue("sslkey", stdStrToQ(cc.sslKey()));
|
||||
settings.setValue("sslrootcert", stdStrToQ(cc.sslRootCert()));
|
||||
settings.setValue("sslcrl", stdStrToQ(cc.sslCrl()));
|
||||
}
|
||||
|
||||
void LoadConnectionConfig(QSettings &settings, ConnectionConfig &cc)
|
||||
{
|
||||
cc.setName(qvarToStdStr(settings.value("name")));
|
||||
cc.setHost(qvarToStdStr(settings.value("host")));
|
||||
cc.setHostAddr(qvarToStdStr(settings.value("hostaddr")));
|
||||
cc.setPort(settings.value("port", 5432).toInt());
|
||||
cc.setUser(qvarToStdStr(settings.value("user")));
|
||||
cc.setPassword(qvarToStdStr(settings.value("password")));
|
||||
cc.setDbname(qvarToStdStr(settings.value("dbname")));
|
||||
cc.setSslMode((SslMode)settings.value("sslmode").toInt());
|
||||
cc.setSslCert(qvarToStdStr(settings.value("sslcert")));
|
||||
cc.setSslKey(qvarToStdStr(settings.value("sslkey")));
|
||||
cc.setSslRootCert(qvarToStdStr(settings.value("sslrootcert")));
|
||||
cc.setSslCrl(qvarToStdStr(settings.value("sslcrl")));
|
||||
}
|
||||
|
||||
|
||||
|
||||
ConnectionListModel::ConnectionListModel(QObject *parent)
|
||||
ConnectionListModel::ConnectionListModel(ConnectionList *conns, QObject *parent)
|
||||
: QAbstractListModel(parent)
|
||||
, m_connections(conns)
|
||||
{
|
||||
load();
|
||||
}
|
||||
|
||||
ConnectionListModel::~ConnectionListModel()
|
||||
{
|
||||
delete m_connections;
|
||||
}
|
||||
|
||||
int ConnectionListModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
int result = 0;
|
||||
if (parent == QModelIndex()) {
|
||||
result = m_connections.size();
|
||||
result = m_connections->size();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -84,7 +37,7 @@ QVariant ConnectionListModel::data(const QModelIndex &index, int role) const
|
|||
if (role == Qt::DisplayRole || role == Qt::EditRole) {
|
||||
int row = index.row();
|
||||
int col = index.column();
|
||||
const ConnectionConfig& cfg = m_connections.at(row).m_config;
|
||||
const ConnectionConfig& cfg = m_connections->getConfigByIdx(row);
|
||||
switch (col) {
|
||||
case 0:
|
||||
result = makeLongDescription(cfg);
|
||||
|
|
@ -119,9 +72,10 @@ bool ConnectionListModel::setData(const QModelIndex &index, const QVariant &valu
|
|||
if (role == Qt::EditRole) {
|
||||
int row = index.row();
|
||||
int col = index.column();
|
||||
auto& elem = m_connections.at(row);
|
||||
elem.m_dirty = true;
|
||||
ConnectionConfig& cfg = elem.m_config;
|
||||
// auto& elem = m_connections.at(row);
|
||||
// elem.m_dirty = true;
|
||||
// ConnectionConfig& cfg = elem.m_config;
|
||||
ConnectionConfig& cfg = m_connections->getConfigByIdx(row);
|
||||
if (col > 0) {
|
||||
result = true;
|
||||
}
|
||||
|
|
@ -158,7 +112,7 @@ Qt::ItemFlags ConnectionListModel::flags(const QModelIndex &index) const
|
|||
{
|
||||
Qt::ItemFlags result;
|
||||
int row = index.row();
|
||||
if (row >= 0 && row < (int)m_connections.size()) {
|
||||
if (row >= 0 && row < (int)m_connections->size()) {
|
||||
result = Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
|
||||
}
|
||||
return result;
|
||||
|
|
@ -180,17 +134,17 @@ QString ConnectionListModel::makeLongDescription(const ConnectionConfig &cfg)
|
|||
return stdStrToQ(result);
|
||||
}
|
||||
|
||||
void ConnectionListModel::add(const ConnectionConfig &cfg)
|
||||
void ConnectionListModel::newItem()
|
||||
{
|
||||
m_connections.emplace_back(QUuid::createUuid(), cfg);
|
||||
auto idx = createIndex(m_connections.size()-1, 0);
|
||||
int i = m_connections->createNew();
|
||||
auto idx = createIndex(i, 0);
|
||||
emit dataChanged(idx, idx);
|
||||
}
|
||||
|
||||
Expected<ConnectionConfig> ConnectionListModel::get(int row)
|
||||
{
|
||||
if (row >= 0 && row < (int)m_connections.size()) {
|
||||
return m_connections.at(row).m_config;
|
||||
if (row >= 0 && row < (int)m_connections->size()) {
|
||||
return m_connections->getConfigByIdx(row);
|
||||
}
|
||||
else {
|
||||
return Expected<ConnectionConfig>::fromException(std::out_of_range("Invalid row"));
|
||||
|
|
@ -201,85 +155,29 @@ Expected<ConnectionConfig> ConnectionListModel::get(int row)
|
|||
bool ConnectionListModel::removeRows(int row, int count, const QModelIndex &parent)
|
||||
{
|
||||
bool result = false;
|
||||
if (row >= 0 && row < (int)m_connections.size()) {
|
||||
if (row >= 0 && row < (int)m_connections->size()) {
|
||||
|
||||
beginRemoveRows(parent, row, row + count -1);
|
||||
SCOPE_EXIT { endRemoveRows(); };
|
||||
|
||||
auto f = m_connections.begin() + row;
|
||||
auto l = f + count;
|
||||
deleteFromIni(f, l);
|
||||
m_connections.erase(f, l);
|
||||
m_connections->remove(row, count);
|
||||
result = true;
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// \todo should return an expected as creation of the folder can fail
|
||||
QString ConnectionListModel::iniFileName()
|
||||
{
|
||||
QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
||||
QDir dir(path);
|
||||
if (!dir.exists()) {
|
||||
dir.mkpath(".");
|
||||
}
|
||||
path += "/connections.ini";
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
void ConnectionListModel::load()
|
||||
{
|
||||
QString file_name = iniFileName();
|
||||
QSettings settings(file_name, QSettings::IniFormat);
|
||||
auto groups = settings.childGroups();
|
||||
for (auto grp : groups) {
|
||||
QUuid uuid(grp);
|
||||
if ( ! uuid.isNull() ) {
|
||||
settings.beginGroup(grp);
|
||||
SCOPE_EXIT { settings.endGroup(); };
|
||||
|
||||
ConnectionConfig cc;
|
||||
LoadConnectionConfig(settings, cc);
|
||||
m_connections.emplace_back(uuid, cc);
|
||||
}
|
||||
}
|
||||
}
|
||||
//void ConnectionListModel::load()
|
||||
//{
|
||||
// m_connections->load();
|
||||
//}
|
||||
|
||||
void ConnectionListModel::save()
|
||||
{
|
||||
QString file_name = iniFileName();
|
||||
QSettings settings(file_name, QSettings::IniFormat);
|
||||
for (auto& e : m_connections) {
|
||||
settings.beginGroup(e.m_uuid.toString());
|
||||
SCOPE_EXIT { settings.endGroup(); };
|
||||
|
||||
SaveConnectionConfig(settings, e.m_config);
|
||||
}
|
||||
m_connections->save();
|
||||
}
|
||||
|
||||
void ConnectionListModel::save(int index)
|
||||
{
|
||||
if (index >= 0 && index < (int)m_connections.size()) {
|
||||
auto& e = m_connections[index];
|
||||
if (e.m_dirty) {
|
||||
QString file_name = iniFileName();
|
||||
QSettings settings(file_name, QSettings::IniFormat);
|
||||
settings.beginGroup(e.m_uuid.toString());
|
||||
SaveConnectionConfig(settings, e.m_config);
|
||||
settings.sync();
|
||||
e.m_dirty = false;
|
||||
}
|
||||
}
|
||||
m_connections->save(index);
|
||||
}
|
||||
|
||||
void ConnectionListModel::deleteFromIni(t_Connections::iterator begin, t_Connections::iterator end)
|
||||
{
|
||||
QString file_name = iniFileName();
|
||||
QSettings settings(file_name, QSettings::IniFormat);
|
||||
for (auto i = begin; i != end; ++i) {
|
||||
settings.remove(i->m_uuid.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@
|
|||
#include <memory>
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QUuid>
|
||||
|
||||
#include "connectionconfig.h"
|
||||
#include "expected.h"
|
||||
|
||||
class ConnectionList;
|
||||
|
||||
/** \brief Model class for the list of connections.
|
||||
*
|
||||
|
|
@ -18,7 +18,9 @@
|
|||
class ConnectionListModel : public QAbstractListModel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ConnectionListModel(QObject *parent);
|
||||
ConnectionListModel(ConnectionList *conns, QObject *parent);
|
||||
ConnectionListModel(const ConnectionListModel&) = delete;
|
||||
~ConnectionListModel();
|
||||
|
||||
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
virtual int columnCount(const QModelIndex &/*parent*/) const override;
|
||||
|
|
@ -27,30 +29,16 @@ public:
|
|||
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
|
||||
virtual Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
|
||||
void add(const ConnectionConfig &cfg);
|
||||
void newItem();
|
||||
Expected<ConnectionConfig> get(int row);
|
||||
virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
|
||||
|
||||
void load();
|
||||
void save();
|
||||
void save(int index);
|
||||
private:
|
||||
class LijstElem {
|
||||
public:
|
||||
QUuid m_uuid;
|
||||
bool m_dirty = false;
|
||||
ConnectionConfig m_config;
|
||||
|
||||
LijstElem(const QUuid id, const ConnectionConfig &cfg)
|
||||
: m_uuid(id), m_config(cfg)
|
||||
{}
|
||||
};
|
||||
ConnectionList *m_connections;
|
||||
|
||||
using t_Connections = std::vector<LijstElem>;
|
||||
t_Connections m_connections;
|
||||
|
||||
void deleteFromIni(t_Connections::iterator begin, t_Connections::iterator end);
|
||||
static QString iniFileName();
|
||||
|
||||
static QString makeLongDescription(const ConnectionConfig &cfg);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -37,12 +37,12 @@ ConnectionManagerWindow::~ConnectionManagerWindow()
|
|||
|
||||
void ConnectionManagerWindow::on_actionAdd_Connection_triggered()
|
||||
{
|
||||
ConnectionConfig c;
|
||||
c.setName("new");
|
||||
// ConnectionConfig c;
|
||||
// c.setName("new");
|
||||
//m_listModel->add(c);
|
||||
|
||||
auto clm = m_masterController->getConnectionListModel();
|
||||
clm->add(c);
|
||||
clm->newItem();
|
||||
|
||||
// Select the new row
|
||||
auto idx = clm->index(clm->rowCount() - 1, 0);
|
||||
|
|
@ -110,3 +110,67 @@ void ConnectionManagerWindow::on_actionManage_server_triggered()
|
|||
auto ci = ui->listView->selectionModel()->currentIndex();
|
||||
m_masterController->openServerWindowForConnection(ci.row());
|
||||
}
|
||||
|
||||
#include <botan/botan.h>
|
||||
//#include <botan/base64.h>
|
||||
//#include <botan/pbkdf.h>
|
||||
//#include <botan/block_cipher.h>
|
||||
//#include <botan/hex.h>
|
||||
#include <botan/cryptobox.h>
|
||||
|
||||
void ConnectionManagerWindow::on_testButton_clicked()
|
||||
{
|
||||
std::string error = Botan::runtime_version_check(BOTAN_VERSION_MAJOR,
|
||||
BOTAN_VERSION_MINOR,
|
||||
BOTAN_VERSION_PATCH);
|
||||
if (error.empty()) {
|
||||
// Botan::AutoSeeded_RNG rng;
|
||||
// Botan::secure_vector<Botan::byte> salt =
|
||||
// //{ 0x3f, 0x0a, 0xb0, 0x11, 0x44, 0xfe, 0x9d, 0xf7, 0x85, 0xd3, 0x11, 0x38, 0xe2, 0xdf, 0x31, 0x42 };
|
||||
// rng.random_vec(16);
|
||||
// // salt should be random and saved with encrypted data so it can be used when we decrypt
|
||||
|
||||
// std::string password = "Hello kitty";
|
||||
// std::unique_ptr<Botan::PBKDF> pbkdf(Botan::get_pbkdf("PBKDF2(SHA-256)"));
|
||||
// Botan::OctetString aes256_key = pbkdf->derive_key(32, password, salt.data(), salt.size(), 10000);
|
||||
|
||||
// std::string plaintext("Your great-grandfather gave this watch to your granddad for good luck. Unfortunately, Dane's luck wasn't as good as his old man's.");
|
||||
// Botan::secure_vector<uint8_t> pt(plaintext.data(),plaintext.data()+plaintext.length());
|
||||
|
||||
// std::unique_ptr<Botan::Cipher_Mode> enc(Botan::get_cipher_mode("AES-256/CBC/PKCS7", Botan::ENCRYPTION));
|
||||
// enc->set_key(aes256_key);
|
||||
|
||||
// //generate fresh nonce (IV)
|
||||
// //std::unique_ptr<Botan::RandomNumberGenerator> rng(new Botan::AutoSeeded_RNG);
|
||||
// std::vector<uint8_t> iv(enc->default_nonce_length());
|
||||
// rng.randomize(iv.data(), iv.size());
|
||||
// enc->start(iv);
|
||||
// enc->finish(pt);
|
||||
// //std::cout << std::endl << enc->name() << " with iv " << Botan::hex_encode(iv) << std::endl << Botan::hex_encode(pt);
|
||||
|
||||
|
||||
//std::string s = aes256_key.as_string();// + "\n" + t.format_string();
|
||||
|
||||
std::string passphrase = "my passphrase";
|
||||
std::string plaintext("password1234");
|
||||
try {
|
||||
Botan::AutoSeeded_RNG rng;
|
||||
std::string encrypted = Botan::CryptoBox::encrypt((const uint8_t*)plaintext.data(), plaintext.length(), passphrase, rng);
|
||||
|
||||
std::string decrypted = Botan::CryptoBox::decrypt(encrypted, passphrase);
|
||||
|
||||
std::string s = encrypted + "\n" + decrypted;
|
||||
QMessageBox::information(this, "pglab",
|
||||
QString::fromUtf8(s.c_str()), QMessageBox::Yes);
|
||||
}
|
||||
catch (Botan::Decoding_Error &e) {
|
||||
QMessageBox::information(this, "pglab",
|
||||
tr("Failure to decrypt"), QMessageBox::Yes);
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
QMessageBox ::information(this, "pglab",
|
||||
QString::fromUtf8(error.c_str()), QMessageBox::Yes);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,10 +15,8 @@ class QStandardItemModel;
|
|||
/** \brief Class that holds glue code for the ConnectionManager UI.
|
||||
*
|
||||
*/
|
||||
class ConnectionManagerWindow : public QMainWindow
|
||||
{
|
||||
class ConnectionManagerWindow : public QMainWindow {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ConnectionManagerWindow(MasterController *master, QWidget *parent = 0);
|
||||
~ConnectionManagerWindow();
|
||||
|
|
@ -27,15 +25,13 @@ private slots:
|
|||
void on_actionAdd_Connection_triggered();
|
||||
void on_currentChanged(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
void on_actionDelete_connection_triggered();
|
||||
|
||||
void on_actionConnect_triggered();
|
||||
|
||||
void on_actionQuit_application_triggered();
|
||||
|
||||
void on_actionBackup_database_triggered();
|
||||
|
||||
void on_actionManage_server_triggered();
|
||||
|
||||
void on_testButton_clicked();
|
||||
|
||||
private:
|
||||
Ui::ConnectionManagerWindow *ui;
|
||||
QDataWidgetMapper *m_mapper = nullptr;
|
||||
|
|
|
|||
|
|
@ -182,6 +182,13 @@
|
|||
<item row="10" column="1">
|
||||
<widget class="QLineEdit" name="edtCrl"/>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<widget class="QPushButton" name="testButton">
|
||||
<property name="text">
|
||||
<string>PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
|
|
|
|||
|
|
@ -1,64 +0,0 @@
|
|||
#include "csvwriter.h"
|
||||
|
||||
CsvWriter::CsvWriter()
|
||||
{}
|
||||
|
||||
CsvWriter::CsvWriter(QTextStream *output)
|
||||
: m_output(output)
|
||||
{}
|
||||
|
||||
void CsvWriter::setDestination(QTextStream *output)
|
||||
{
|
||||
m_output = output;
|
||||
m_column = 0;
|
||||
}
|
||||
|
||||
void CsvWriter::setSeperator(QChar ch)
|
||||
{
|
||||
m_seperator = ch;
|
||||
}
|
||||
|
||||
void CsvWriter::setQuote(QChar ch)
|
||||
{
|
||||
m_quote = ch;
|
||||
}
|
||||
|
||||
void CsvWriter::writeField(QString field)
|
||||
{
|
||||
QTextStream &out = *m_output;
|
||||
if (m_column > 0) {
|
||||
out << m_seperator;
|
||||
}
|
||||
// if field contains any of seperator, quote or newline then it needs to be quoted
|
||||
// when quoted quotes need to be doubled to escape them
|
||||
bool needs_quotes = false;
|
||||
for (auto ch : field) {
|
||||
if (ch == '\n' || ch == m_seperator || ch == m_quote) {
|
||||
needs_quotes = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (needs_quotes) {
|
||||
out << m_quote;
|
||||
for (auto ch : field) {
|
||||
if (ch == m_quote)
|
||||
out << m_quote;
|
||||
out << ch;
|
||||
}
|
||||
out << m_quote;
|
||||
}
|
||||
else {
|
||||
out << field;
|
||||
}
|
||||
++m_column;
|
||||
}
|
||||
|
||||
|
||||
void CsvWriter::nextRow()
|
||||
{
|
||||
QTextStream &out = *m_output;
|
||||
out << '\n';
|
||||
m_column = 0;
|
||||
}
|
||||
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
#ifndef CSVWRITER_H
|
||||
#define CSVWRITER_H
|
||||
|
||||
#include <ostream>
|
||||
#include <QTextStream>
|
||||
|
||||
class CsvWriter {
|
||||
public:
|
||||
CsvWriter();
|
||||
explicit CsvWriter(QTextStream *output);
|
||||
void setDestination(QTextStream *output);
|
||||
void setSeperator(QChar ch);
|
||||
void setQuote(QChar ch);
|
||||
void writeField(QString field);
|
||||
void nextRow();
|
||||
private:
|
||||
QChar m_seperator = ',';
|
||||
QChar m_quote = '"';
|
||||
QTextStream *m_output = nullptr;
|
||||
int m_column = 0;
|
||||
};
|
||||
|
||||
#endif // CSVWRITER_H
|
||||
156
src/Expected.h
156
src/Expected.h
|
|
@ -1,156 +0,0 @@
|
|||
#ifndef EXPECTED_H
|
||||
#define EXPECTED_H
|
||||
|
||||
template <typename T>
|
||||
class Expected {
|
||||
union {
|
||||
T m_value;
|
||||
std::exception_ptr m_error;
|
||||
};
|
||||
bool m_valid;
|
||||
Expected() {} // internal use
|
||||
|
||||
public:
|
||||
|
||||
Expected(const T& rhs)
|
||||
: m_value(rhs), m_valid(true)
|
||||
{}
|
||||
|
||||
Expected(T&& rhs)
|
||||
: m_value(std::move(rhs))
|
||||
, m_valid(true)
|
||||
{}
|
||||
|
||||
|
||||
Expected(const Expected& rhs)
|
||||
: m_valid(rhs.valid)
|
||||
{
|
||||
if (m_valid) {
|
||||
new (&m_value) T(rhs.m_value);
|
||||
}
|
||||
else {
|
||||
new (&m_error) std::exception_ptr(rhs.m_error);
|
||||
}
|
||||
}
|
||||
|
||||
Expected(Expected &&rhs)
|
||||
: m_valid(rhs.m_valid)
|
||||
{
|
||||
if (m_valid) {
|
||||
new (&m_value) T(std::move(rhs.m_value));
|
||||
}
|
||||
else {
|
||||
new (&m_error) std::exception_ptr(std::move(rhs.m_error));
|
||||
}
|
||||
}
|
||||
|
||||
~Expected()
|
||||
{
|
||||
if (m_valid) {
|
||||
m_value.~T();
|
||||
}
|
||||
else {
|
||||
using std::exception_ptr;
|
||||
m_error.~exception_ptr();
|
||||
}
|
||||
}
|
||||
|
||||
void swap(Expected& rhs)
|
||||
{
|
||||
if (m_valid) {
|
||||
if (rhs.m_valid) {
|
||||
using std::swamp;
|
||||
swap(m_value, rhs.m_value);
|
||||
}
|
||||
else {
|
||||
auto t = std::move(rhs.m_error);
|
||||
new(&rhs.m_value) T(std::move(m_value));
|
||||
new(&m_error) std::exception_ptr(t);
|
||||
std::swap(m_valid, rhs.m_valid);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (rhs.m_valid) {
|
||||
rhs.swap(*this);
|
||||
}
|
||||
else {
|
||||
m_error.swap(rhs.m_error);
|
||||
std::swap(m_valid, rhs.m_valid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class E>
|
||||
static Expected<T> fromException(const E& exception)
|
||||
{
|
||||
if (typeid(exception) != typeid(E)) {
|
||||
throw std::invalid_argument("slicing detected");
|
||||
}
|
||||
return fromException(std::make_exception_ptr(exception));
|
||||
}
|
||||
|
||||
static Expected<T> fromException(std::exception_ptr p)
|
||||
{
|
||||
Expected<T> result;
|
||||
result.m_valid = false;
|
||||
new (&result.m_error) std::exception_ptr(std::move(p));
|
||||
return result;
|
||||
}
|
||||
|
||||
static Expected<T> fromException()
|
||||
{
|
||||
return fromException(std::current_exception());
|
||||
}
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
return m_valid;
|
||||
}
|
||||
|
||||
T& get()
|
||||
{
|
||||
if (!m_valid) {
|
||||
std::rethrow_exception(m_error);
|
||||
}
|
||||
return m_value;
|
||||
}
|
||||
|
||||
const T& get() const
|
||||
{
|
||||
if (!m_valid) {
|
||||
std::rethrow_exception(m_error);
|
||||
}
|
||||
return m_value;
|
||||
}
|
||||
|
||||
template <class E>
|
||||
bool hasException() const
|
||||
{
|
||||
try {
|
||||
if (!m_valid) {
|
||||
std::rethrow_exception(m_error);
|
||||
}
|
||||
}
|
||||
catch (const E& object) {
|
||||
return true;
|
||||
}
|
||||
catch (...) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class F>
|
||||
static Expected fromCode(F fun)
|
||||
{
|
||||
try {
|
||||
return Expected(fun());
|
||||
}
|
||||
catch (...) {
|
||||
return fromException();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // EXPECTED_H
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
#include "MasterController.h"
|
||||
#include "connectionmanagerwindow.h"
|
||||
#include "connectionlistmodel.h"
|
||||
#include "ConnectionManagerWindow.h"
|
||||
#include "ConnectionList.h"
|
||||
#include "ConnectionListModel.h"
|
||||
#include "MainWindow.h"
|
||||
#include "ServerWindow.h"
|
||||
|
||||
|
|
@ -12,11 +13,14 @@ MasterController::~MasterController()
|
|||
{
|
||||
delete m_connectionManagerWindow;
|
||||
delete m_connectionListModel;
|
||||
delete m_connectionList;
|
||||
}
|
||||
|
||||
void MasterController::init()
|
||||
{
|
||||
m_connectionListModel = new ConnectionListModel(this);
|
||||
m_connectionList = new ConnectionList;
|
||||
m_connectionList->load();
|
||||
m_connectionListModel = new ConnectionListModel(m_connectionList, this);
|
||||
|
||||
m_connectionManagerWindow = new ConnectionManagerWindow(this, nullptr);
|
||||
m_connectionManagerWindow->show();
|
||||
|
|
|
|||
|
|
@ -5,16 +5,18 @@
|
|||
#include <map>
|
||||
|
||||
class ConnectionConfig;
|
||||
class ConnectionList;
|
||||
class ConnectionListModel;
|
||||
class ConnectionManagerWindow;
|
||||
|
||||
/** \brief Controller class responsible for all things global.
|
||||
*/
|
||||
class MasterController : public QObject
|
||||
{
|
||||
class MasterController : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MasterController(QObject *parent = 0);
|
||||
MasterController(const MasterController&) = delete;
|
||||
MasterController &operator=(const MasterController&) = delete;
|
||||
~MasterController();
|
||||
|
||||
void init();
|
||||
|
|
@ -33,7 +35,7 @@ signals:
|
|||
public slots:
|
||||
|
||||
private:
|
||||
|
||||
ConnectionList *m_connectionList = nullptr;
|
||||
ConnectionListModel *m_connectionListModel = nullptr;
|
||||
ConnectionManagerWindow *m_connectionManagerWindow = nullptr;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ QWidget *ParamTypeDelegate::createEditor(QWidget *parent,
|
|||
QWidget *w = nullptr;
|
||||
|
||||
QComboBox *cmbbx = new QComboBox(parent);
|
||||
cmbbx->setMaxVisibleItems(32);
|
||||
cmbbx->setModel(m_typeSelectionModel);
|
||||
w = cmbbx;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,69 +0,0 @@
|
|||
#ifndef SCOPEGUARD_H
|
||||
#define SCOPEGUARD_H
|
||||
|
||||
/** \brief Template class for executing code at scope exit.
|
||||
*
|
||||
* By default the object will be an active mode and execute the function
|
||||
* passed to the constructor when the object is destructed. You can however
|
||||
* cancel this action by calling dismiss().
|
||||
*
|
||||
* There is a clever macro that allows you to write something like
|
||||
* SCOPE_EXIT { foo(); };
|
||||
*/
|
||||
template<class Fun>
|
||||
class ScopeGuard {
|
||||
Fun f_;
|
||||
bool active_;
|
||||
public:
|
||||
ScopeGuard(Fun f)
|
||||
: f_(std::move(f))
|
||||
, active_(true) {
|
||||
}
|
||||
|
||||
~ScopeGuard() { if(active_) f_(); }
|
||||
|
||||
void dismiss() { active_=false; }
|
||||
|
||||
ScopeGuard() = delete;
|
||||
ScopeGuard(const ScopeGuard&) = delete;
|
||||
ScopeGuard& operator=(const ScopeGuard&) = delete;
|
||||
ScopeGuard(ScopeGuard&& rhs)
|
||||
: f_(std::move(rhs.f_))
|
||||
, active_(rhs.active_)
|
||||
{
|
||||
rhs.dismiss();
|
||||
}
|
||||
};
|
||||
|
||||
template<class Fun>
|
||||
ScopeGuard<Fun> scopeGuard(Fun f)
|
||||
{
|
||||
return ScopeGuard<Fun>(std::move(f));
|
||||
}
|
||||
|
||||
namespace ScopeGuard_detail {
|
||||
|
||||
enum class ScopeGuardOnExit {};
|
||||
|
||||
template<typename Fun>
|
||||
ScopeGuard<Fun> operator+(ScopeGuardOnExit, Fun&& fn) {
|
||||
return ScopeGuard<Fun>(std::forward<Fun>(fn));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define CONCATENATE_IMPL(s1, s2) s1##s2
|
||||
#define CONCATENATE(s1, s2) CONCATENATE_IMPL(s1, s2)
|
||||
#ifdef __COUNTER__
|
||||
#define ANONYMOUS_VARIABLE(str) \
|
||||
CONCATENATE(str,__COUNTER__)
|
||||
#else
|
||||
#define ANONYMOUS_VARIABLE(str) \
|
||||
CONCATENATE(str,__LINE__)
|
||||
#endif
|
||||
|
||||
#define SCOPE_EXIT \
|
||||
auto ANONYMOUS_VARIABLE(SCOPE_EXIT_STATE) \
|
||||
= ::ScopeGuard_detail::ScopeGuardOnExit() + [&]()
|
||||
|
||||
#endif // SCOPEGUARD_H
|
||||
134
src/SqlLexer.cpp
134
src/SqlLexer.cpp
|
|
@ -1,134 +0,0 @@
|
|||
#include "SqlLexer.h"
|
||||
|
||||
SqlLexer::SqlLexer(const QString &block, LexerState currentstate)
|
||||
: m_block(block)
|
||||
, m_state(currentstate)
|
||||
{}
|
||||
|
||||
QChar SqlLexer::nextChar()
|
||||
{
|
||||
QChar result = QChar::Null;
|
||||
if (m_pos < m_block.size()) {
|
||||
result = m_block.at(m_pos++);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QChar SqlLexer::peekChar()
|
||||
{
|
||||
QChar result = QChar::Null;
|
||||
if (m_pos < m_block.size()) {
|
||||
result = m_block.at(m_pos);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief NextBasicToken
|
||||
* @param in
|
||||
* @param ofs
|
||||
* @param start
|
||||
* @param length
|
||||
* @return false when input seems invalid, it will return what it did recognize but something wasn't right, parser should try to recover
|
||||
*/
|
||||
bool SqlLexer::nextBasicToken(int &startpos, int &length, BasicTokenType &tokentype, QString &out)
|
||||
{
|
||||
// Basically chops based on white space
|
||||
// it does also recognize comments and quoted strings/identifiers
|
||||
bool result = false;
|
||||
while (true) {
|
||||
startpos = m_pos;
|
||||
QChar c = nextChar();
|
||||
if (c.isSpace()) {
|
||||
// Just skip whitespace
|
||||
}
|
||||
else if (c == '-' && peekChar() == '-') { // two dashes, start of comment
|
||||
// Loop till end of line or end of block
|
||||
c = nextChar();
|
||||
for (;;) {
|
||||
c = peekChar();
|
||||
if (c != QChar::Null && c != '\n')
|
||||
nextChar();
|
||||
else
|
||||
break;
|
||||
}
|
||||
length = m_pos - startpos;
|
||||
tokentype = BasicTokenType::Comment;
|
||||
return true;
|
||||
}
|
||||
else if (c == '\'') {
|
||||
// Single quoted string so it's an SQL text literal
|
||||
while (true) {
|
||||
c = peekChar();
|
||||
if (c == QChar::Null || c == '\n') {
|
||||
// unexpected end, pretend nothings wrong
|
||||
length = m_pos - startpos;
|
||||
tokentype = BasicTokenType::QuotedString;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
nextChar();
|
||||
if (c == '\'') {
|
||||
// maybe end of string literal
|
||||
if (peekChar() == '\'') {
|
||||
// Nope, just double quote to escape quote
|
||||
nextChar(); // eat it
|
||||
}
|
||||
else {
|
||||
length = m_pos - startpos;
|
||||
tokentype = BasicTokenType::QuotedString;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (c == '"') {
|
||||
// Double quoted identifier
|
||||
while (true) {
|
||||
c = peekChar();
|
||||
if (c == QChar::Null || c == '\n') {
|
||||
// unexpected end, pretend nothings wrong
|
||||
length = m_pos - startpos;
|
||||
tokentype = BasicTokenType::QuotedIdentifier;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
nextChar();
|
||||
if (c == '"') {
|
||||
// maybe end of string literal
|
||||
if (peekChar() == '"') {
|
||||
// Nope, just double quote to escape quote
|
||||
nextChar(); // eat it
|
||||
}
|
||||
else {
|
||||
length = m_pos - startpos;
|
||||
tokentype = BasicTokenType::QuotedIdentifier;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (c == QChar::Null) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
// Undetermined symbol
|
||||
for (;;) {
|
||||
c = peekChar();
|
||||
if (c.isLetterOrNumber() || c == '_')
|
||||
nextChar();
|
||||
else
|
||||
break;
|
||||
}
|
||||
length = m_pos - startpos;
|
||||
tokentype = BasicTokenType::Symbol;
|
||||
QStringRef sr(&m_block, startpos, length);
|
||||
out = sr.toString();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
#ifndef SQLLEXER_H
|
||||
#define SQLLEXER_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
enum class BasicTokenType {
|
||||
None,
|
||||
End, // End of input
|
||||
Symbol, // can be many things, keyword, object name, operator, ..
|
||||
Comment,
|
||||
QuotedString,
|
||||
DollarQuotedString,
|
||||
QuotedIdentifier
|
||||
};
|
||||
|
||||
enum class LexerState {
|
||||
Null,
|
||||
InDollarQuotedString
|
||||
};
|
||||
|
||||
|
||||
class SqlLexer {
|
||||
public:
|
||||
SqlLexer(const QString &block, LexerState currentstate);
|
||||
QChar nextChar();
|
||||
QChar peekChar();
|
||||
/**
|
||||
* @brief NextBasicToken
|
||||
* @param in
|
||||
* @param ofs
|
||||
* @param start
|
||||
* @param length
|
||||
* @return false when input seems invalid, it will return what it did recognize but something wasn't right, parser should try to recover
|
||||
*/
|
||||
bool nextBasicToken(int &startpos, int &length, BasicTokenType &tokentype, QString &out);
|
||||
|
||||
private:
|
||||
QString m_block;
|
||||
int m_pos = 0;
|
||||
LexerState m_state;
|
||||
|
||||
};
|
||||
|
||||
#endif // SQLLEXER_H
|
||||
|
|
@ -133,7 +133,10 @@ void SqlSyntaxHighlighter::setTypes(const PgTypeContainer *types)
|
|||
|
||||
void SqlSyntaxHighlighter::highlightBlock(const QString &text)
|
||||
{
|
||||
SqlLexer lexer(text, LexerState::Null);
|
||||
int previous_state = previousBlockState();
|
||||
if (previous_state <= 0)
|
||||
previous_state = 0;
|
||||
SqlLexer lexer(text, (LexerState)previous_state);
|
||||
int startpos, length;
|
||||
BasicTokenType tokentype;
|
||||
QString s;
|
||||
|
|
@ -151,6 +154,9 @@ void SqlSyntaxHighlighter::highlightBlock(const QString &text)
|
|||
setFormat(startpos, length, m_typeFormat);
|
||||
}
|
||||
break;
|
||||
case BasicTokenType::OpenBlockComment:
|
||||
setCurrentBlockState((int)lexer.currentState());
|
||||
case BasicTokenType::BlockComment:
|
||||
case BasicTokenType::Comment:
|
||||
setFormat(startpos, length, m_commentFormat);
|
||||
break;
|
||||
|
|
|
|||
35
src/src.pro
35
src/src.pro
|
|
@ -4,6 +4,7 @@
|
|||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
CONFIG += c++11
|
||||
QT += core gui
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets sql
|
||||
|
|
@ -11,9 +12,17 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets sql
|
|||
TARGET = pglab
|
||||
TEMPLATE = app
|
||||
|
||||
INCLUDEPATH += C:\prog\include
|
||||
INCLUDEPATH += C:\prog\include C:\VSproj\boost_1_63_0
|
||||
DEFINES += WIN32_LEAN_AND_MEAN NOMINMAX
|
||||
LIBS += c:\prog\lib\libpq.lib c:\prog\lib\fmt.lib User32.lib ws2_32.lib
|
||||
LIBS += /LIBPATH:C:\VSproj\boost_1_63_0\stage\lib /LIBPATH:c:\prog\lib\ libpq.lib fmt.lib User32.lib ws2_32.lib
|
||||
|
||||
debug {
|
||||
LIBS += c:\prog\lib\botand_imp.lib
|
||||
}
|
||||
|
||||
release {
|
||||
# LIBS += c:\prog\lib\botan.lib
|
||||
}
|
||||
|
||||
win32:RC_ICONS += pglab.ico
|
||||
|
||||
|
|
@ -29,7 +38,6 @@ SOURCES += main.cpp\
|
|||
tsqueue.cpp \
|
||||
win32event.cpp \
|
||||
waithandlelist.cpp \
|
||||
CsvWriter.cpp \
|
||||
DatabaseWindow.cpp \
|
||||
ConnectionManagerWindow.cpp \
|
||||
ConnectionListModel.cpp \
|
||||
|
|
@ -53,7 +61,6 @@ SOURCES += main.cpp\
|
|||
ParamListModel.cpp \
|
||||
MainWindow.cpp \
|
||||
SqlSyntaxHighlighter.cpp \
|
||||
SqlLexer.cpp \
|
||||
ServerWindow.cpp \
|
||||
ASyncWindow.cpp \
|
||||
DatabasesTableModel.cpp \
|
||||
|
|
@ -65,7 +72,8 @@ SOURCES += main.cpp\
|
|||
PgAuthIdContainer.cpp \
|
||||
Pgsql_Result.cpp \
|
||||
Pgsql_Row.cpp \
|
||||
Pgsql_Value.cpp
|
||||
Pgsql_Value.cpp \
|
||||
ConnectionList.cpp
|
||||
|
||||
HEADERS += \
|
||||
sqlparser.h \
|
||||
|
|
@ -78,13 +86,10 @@ HEADERS += \
|
|||
tsqueue.h \
|
||||
win32event.h \
|
||||
waithandlelist.h \
|
||||
CsvWriter.h \
|
||||
DatabaseWindow.h \
|
||||
ConnectionManagerWindow.h \
|
||||
ConnectionListModel.h \
|
||||
ConnectionConfig.h \
|
||||
ScopeGuard.h \
|
||||
Expected.h \
|
||||
QueryTab.h \
|
||||
stopwatch.h \
|
||||
util.h \
|
||||
|
|
@ -117,7 +122,8 @@ HEADERS += \
|
|||
PgAuthIdContainer.h \
|
||||
Pgsql_Result.h \
|
||||
Pgsql_Row.h \
|
||||
Pgsql_Value.h
|
||||
Pgsql_Value.h \
|
||||
ConnectionList.h
|
||||
|
||||
FORMS += mainwindow.ui \
|
||||
DatabaseWindow.ui \
|
||||
|
|
@ -132,3 +138,14 @@ RESOURCES += \
|
|||
resources.qrc
|
||||
|
||||
QMAKE_LFLAGS_WINDOWS = /SUBSYSTEM:WINDOWS,5.01
|
||||
|
||||
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../core/release/ -lcore
|
||||
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../core/debug/ -lcore
|
||||
|
||||
INCLUDEPATH += $$PWD/../core
|
||||
DEPENDPATH += $$PWD/../core
|
||||
|
||||
win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../core/release/libcore.a
|
||||
else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../core/debug/libcore.a
|
||||
else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../core/release/core.lib
|
||||
else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../core/debug/core.lib
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ public:
|
|||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
|
||||
private:
|
||||
// const PgTypeContainer* m_types;
|
||||
std::vector<QString> m_types;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include <QTextStream>
|
||||
#include <QClipboard>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
// Supported range from microseconds to seconds
|
||||
// min:sec to hours::min::sec
|
||||
|
|
@ -134,3 +135,5 @@ QString ConvertToMultiLineCString(const QString &in)
|
|||
out.append('"');
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
18
src/util.h
18
src/util.h
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
#include <string>
|
||||
#include <QString>
|
||||
#include <QTableView>
|
||||
|
||||
|
|
@ -9,6 +10,23 @@ void copySelectionToClipboard(const QTableView *view);
|
|||
QString ConvertToMultiLineCString(const QString &in);
|
||||
void exportTable(const QTableView *view, QTextStream &out);
|
||||
|
||||
inline QString stdStrToQ(const std::string &s)
|
||||
{
|
||||
return QString::fromUtf8(s.c_str());
|
||||
}
|
||||
|
||||
inline std::string qStrToStd(const QString &s)
|
||||
{
|
||||
return std::string(s.toUtf8().data());
|
||||
}
|
||||
|
||||
inline std::string qvarToStdStr(const QVariant &c)
|
||||
{
|
||||
return qStrToStd(c.toString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace std {
|
||||
|
||||
template <>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue