Connection manager can now open a query window for selected connection.
Query window has now buttons with icons made in the designer for better looks. Depending on received responses from the database the tabcontrol with the message, data and explain tab now switches to the appropriate tab.
This commit is contained in:
parent
88fcc0338d
commit
d19741f111
26 changed files with 408 additions and 116 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -3,4 +3,5 @@ release/
|
|||
DIST/
|
||||
Makefile
|
||||
Makefile.Debug
|
||||
Makefile.Release
|
||||
Makefile.Release
|
||||
desktop.ini
|
||||
|
|
|
|||
|
|
@ -236,6 +236,13 @@ bool Connection::connectStart(const char* params)
|
|||
return conn != nullptr;
|
||||
}
|
||||
|
||||
bool Connection::connectStart(const char * const *keywords,
|
||||
const char * const *values)
|
||||
{
|
||||
conn = PQconnectStartParams(keywords, values, 0);
|
||||
return conn != nullptr;
|
||||
}
|
||||
|
||||
PostgresPollingStatusType Connection::connectPoll()
|
||||
{
|
||||
return PQconnectPoll(conn);
|
||||
|
|
|
|||
24
PgsqlConn.h
24
PgsqlConn.h
|
|
@ -19,18 +19,18 @@ namespace Pgsql {
|
|||
|
||||
*/
|
||||
|
||||
class ConnectionParams {
|
||||
public:
|
||||
std::string host;
|
||||
std::string hostaddr;
|
||||
unsigned short port = 5432;
|
||||
std::string dbname;
|
||||
std::string user;
|
||||
std::string password;
|
||||
int connect_timeout = -1; ///< -1 omit (ie uses default)
|
||||
std::string application_name;
|
||||
// class ConnectionParams {
|
||||
// public:
|
||||
// std::string host;
|
||||
// std::string hostaddr;
|
||||
// unsigned short port = 5432;
|
||||
// std::string dbname;
|
||||
// std::string user;
|
||||
// std::string password;
|
||||
// int connect_timeout = -1; ///< -1 omit (ie uses default)
|
||||
// std::string application_name;
|
||||
|
||||
};
|
||||
// };
|
||||
|
||||
class ErrorDetails {
|
||||
public:
|
||||
|
|
@ -172,6 +172,8 @@ namespace Pgsql {
|
|||
{
|
||||
return connectStart(params.toUtf8().data());
|
||||
}
|
||||
bool connectStart(const char * const *keywords,
|
||||
const char * const *values);
|
||||
|
||||
PostgresPollingStatusType connectPoll();
|
||||
ConnStatusType status();
|
||||
|
|
|
|||
|
|
@ -7,13 +7,23 @@ ASyncDBConnection::ASyncDBConnection()
|
|||
|
||||
}
|
||||
|
||||
void ASyncDBConnection::setupConnection(const std::string &connstring)
|
||||
//void ASyncDBConnection::setupConnection(const std::string &connstring)
|
||||
//{
|
||||
// if (m_thread.joinable()) {
|
||||
// m_threadData.stop();
|
||||
// m_thread.join();
|
||||
// }
|
||||
// m_threadData.m_initString = connstring;
|
||||
// m_thread = std::thread([this] () { m_threadData.run(); });
|
||||
//}
|
||||
|
||||
void ASyncDBConnection::setupConnection(const ConnectionConfig &config)
|
||||
{
|
||||
if (m_thread.joinable()) {
|
||||
m_threadData.stop();
|
||||
m_thread.join();
|
||||
}
|
||||
m_threadData.m_initString = connstring;
|
||||
m_threadData.m_config = config;
|
||||
m_thread = std::thread([this] () { m_threadData.run(); });
|
||||
}
|
||||
|
||||
|
|
@ -100,7 +110,10 @@ bool ASyncDBConnection::Thread::makeConnection()
|
|||
while (!terminateRequested) {
|
||||
|
||||
// start connecting
|
||||
bool ok = m_connection.connectStart(m_initString + " client_encoding=utf8");
|
||||
//bool ok = m_connection.connectStart(m_initString + " client_encoding=utf8");
|
||||
auto keywords = m_config.getKeywords();
|
||||
auto values = m_config.getValues();
|
||||
bool ok = m_connection.connectStart(keywords, values);
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
if (ok && m_connection.status() != CONNECTION_BAD) {
|
||||
int sock = m_connection.socket();
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "PgsqlConn.h"
|
||||
#include "win32event.h"
|
||||
#include "connectionconfig.h"
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
|
@ -26,7 +27,8 @@ public:
|
|||
|
||||
ASyncDBConnection();
|
||||
|
||||
void setupConnection(const std::string &connstring);
|
||||
// void setupConnection(const std::string &connstring);
|
||||
void setupConnection(const ConnectionConfig &config);
|
||||
void closeConnection();
|
||||
|
||||
void setStateCallback(on_state_callback state_callback);
|
||||
|
|
@ -77,7 +79,8 @@ private:
|
|||
{}
|
||||
} m_commandQueue;
|
||||
|
||||
std::string m_initString;
|
||||
// std::string m_initString;
|
||||
ConnectionConfig m_config;
|
||||
|
||||
Thread();
|
||||
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@ std::vector<const char*> ConnectionConfig::s_keywords = {
|
|||
|
||||
ConnectionConfig::ConnectionConfig()
|
||||
: m_applicationName(QCoreApplication::applicationName().toUtf8().data())
|
||||
, m_values(s_keywords.size(), nullptr)
|
||||
{}
|
||||
|
||||
void ConnectionConfig::setName(std::string desc)
|
||||
|
|
@ -69,7 +68,6 @@ const std::string& ConnectionConfig::name() const
|
|||
void ConnectionConfig::setHost(std::string host)
|
||||
{
|
||||
m_host = std::move(host);
|
||||
m_values[0] = valuePtr(m_host);
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::host() const
|
||||
|
|
@ -80,7 +78,6 @@ const std::string& ConnectionConfig::host() const
|
|||
void ConnectionConfig::setHostAddr(std::string v)
|
||||
{
|
||||
m_hostaddr = std::move(v);
|
||||
m_values[1] = valuePtr(m_hostaddr);
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::hostAddr() const
|
||||
|
|
@ -91,7 +88,6 @@ const std::string& ConnectionConfig::hostAddr() const
|
|||
void ConnectionConfig::setPort(unsigned short port)
|
||||
{
|
||||
m_port = std::to_string(port);
|
||||
m_values[2] = valuePtr(m_port);
|
||||
}
|
||||
|
||||
unsigned short ConnectionConfig::port() const
|
||||
|
|
@ -102,7 +98,6 @@ unsigned short ConnectionConfig::port() const
|
|||
void ConnectionConfig::setUser(std::string v)
|
||||
{
|
||||
m_user = std::move(v);
|
||||
m_values[3] = valuePtr(m_user);
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::user() const
|
||||
|
|
@ -113,7 +108,6 @@ const std::string& ConnectionConfig::user() const
|
|||
void ConnectionConfig::setPassword(std::string v)
|
||||
{
|
||||
m_password = std::move(v);
|
||||
m_values[4] = valuePtr(m_password);
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::password() const
|
||||
|
|
@ -124,7 +118,6 @@ const std::string& ConnectionConfig::password() const
|
|||
void ConnectionConfig::setDbname(std::string v)
|
||||
{
|
||||
m_dbname = std::move(v);
|
||||
m_values[5] = valuePtr(m_dbname);
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::dbname() const
|
||||
|
|
@ -135,7 +128,6 @@ const std::string& ConnectionConfig::dbname() const
|
|||
void ConnectionConfig::setSslMode(SslMode m)
|
||||
{
|
||||
m_sslMode = SslModeToString(m);
|
||||
m_values[6] = valuePtr(m_sslMode);
|
||||
}
|
||||
|
||||
SslMode ConnectionConfig::sslMode() const
|
||||
|
|
@ -146,7 +138,6 @@ SslMode ConnectionConfig::sslMode() const
|
|||
void ConnectionConfig::setSslCert(std::string v)
|
||||
{
|
||||
m_sslCert = std::move(v);
|
||||
m_values[7] = valuePtr(m_sslCert);
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::sslCert() const
|
||||
|
|
@ -157,7 +148,6 @@ const std::string& ConnectionConfig::sslCert() const
|
|||
void ConnectionConfig::setSslKey(std::string v)
|
||||
{
|
||||
m_sslKey = std::move(v);
|
||||
m_values[8] = valuePtr(m_sslKey);
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::sslKey() const
|
||||
|
|
@ -168,7 +158,6 @@ const std::string& ConnectionConfig::sslKey() const
|
|||
void ConnectionConfig::setSslRootCert(std::string v)
|
||||
{
|
||||
m_sslRootCert = std::move(v);
|
||||
m_values[9] = valuePtr(m_sslRootCert);
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::sslRootCert() const
|
||||
|
|
@ -179,7 +168,6 @@ const std::string& ConnectionConfig::sslRootCert() const
|
|||
void ConnectionConfig::setSslCrl(std::string v)
|
||||
{
|
||||
m_sslCrl = std::move(v);
|
||||
m_values[10] = valuePtr(m_sslCrl);
|
||||
}
|
||||
|
||||
const std::string& ConnectionConfig::sslCrl() const
|
||||
|
|
@ -195,6 +183,18 @@ const char * const * ConnectionConfig::getKeywords() const
|
|||
|
||||
const char * const * ConnectionConfig::getValues() const
|
||||
{
|
||||
m_values.resize(s_keywords.size(), nullptr);
|
||||
m_values[0] = valuePtr(m_host);
|
||||
m_values[1] = valuePtr(m_hostaddr);
|
||||
m_values[2] = valuePtr(m_port);
|
||||
m_values[3] = valuePtr(m_user);
|
||||
m_values[4] = valuePtr(m_password);
|
||||
m_values[5] = valuePtr(m_dbname);
|
||||
m_values[6] = valuePtr(m_sslMode);
|
||||
m_values[7] = valuePtr(m_sslCert);
|
||||
m_values[8] = valuePtr(m_sslKey);
|
||||
m_values[9] = valuePtr(m_sslRootCert);
|
||||
m_values[10] = valuePtr(m_sslCrl);
|
||||
m_values[11] = "utf8";
|
||||
m_values[12] = valuePtr(m_applicationName);
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,11 @@ ConnectionListModel::ConnectionListModel(QObject *parent)
|
|||
|
||||
int ConnectionListModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
return m_connections.size();
|
||||
int result = 0;
|
||||
if (parent == QModelIndex()) {
|
||||
result = m_connections.size();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int ConnectionListModel::columnCount(const QModelIndex &/*parent*/) const
|
||||
|
|
@ -150,7 +154,12 @@ bool ConnectionListModel::setData(const QModelIndex &index, const QVariant &valu
|
|||
|
||||
Qt::ItemFlags ConnectionListModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
|
||||
Qt::ItemFlags result;
|
||||
int row = index.row();
|
||||
if (row >= 0 && row < m_connections.size()) {
|
||||
result = Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -176,6 +185,28 @@ void ConnectionListModel::add(const ConnectionConfig &cfg)
|
|||
emit dataChanged(idx, idx);
|
||||
}
|
||||
|
||||
Expected<ConnectionConfig> ConnectionListModel::get(int row)
|
||||
{
|
||||
if (row >= 0 && row < m_connections.size()) {
|
||||
return m_connections.at(row).m_config;
|
||||
}
|
||||
else {
|
||||
return Expected<ConnectionConfig>::fromException(std::out_of_range("Invalid row"));
|
||||
}
|
||||
}
|
||||
|
||||
//void ConnectionListModel::del(const int idx)
|
||||
bool ConnectionListModel::removeRows(int row, int count, const QModelIndex &parent)
|
||||
{
|
||||
bool result = false;
|
||||
if (row >= 0 && row < m_connections.size()) {
|
||||
auto f = m_connections.begin() + row;
|
||||
m_connections.erase(f, f + count);
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// \todo should return an expected as creation of the folder can fail
|
||||
QString ConnectionListModel::iniFileName()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <QUuid>
|
||||
|
||||
#include "connectionconfig.h"
|
||||
#include "expected.h"
|
||||
|
||||
|
||||
class ConnectionListModel : public QAbstractListModel {
|
||||
|
|
@ -23,9 +24,12 @@ public:
|
|||
virtual Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
|
||||
void add(const ConnectionConfig &cfg);
|
||||
Expected<ConnectionConfig> get(int row);
|
||||
virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
|
||||
|
||||
void load();
|
||||
void save();
|
||||
|
||||
private:
|
||||
class LijstElem {
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#include "connectionmanagerwindow.h"
|
||||
#include "ui_connectionmanagerwindow.h"
|
||||
#include "mainwindow.h"
|
||||
#include <QDataWidgetMapper>
|
||||
#include <QMessageBox>
|
||||
#include <QStandardItemModel>
|
||||
|
||||
#include "connectionlistmodel.h"
|
||||
|
|
@ -42,24 +44,15 @@ void ConnectionManagerWindow::on_currentChanged(const QModelIndex ¤t,
|
|||
const QModelIndex &previous)
|
||||
{
|
||||
int currow = current.row();
|
||||
// int prevrow = previous.row();
|
||||
|
||||
m_mapper->setCurrentIndex(currow);
|
||||
// ui->lineEdit->setText(QString::number(currow));
|
||||
// ui->lineEdit_2->setText(QString::number(prevrow));
|
||||
|
||||
// if(selection.indexes().isEmpty()) {
|
||||
// clearMyView();
|
||||
// } else {
|
||||
// displayModelIndexInMyView(selection.indexes().first());
|
||||
// }
|
||||
}
|
||||
|
||||
void ConnectionManagerWindow::on_actionDelete_connection_triggered()
|
||||
{
|
||||
auto ci = ui->listView->selectionModel()->currentIndex();
|
||||
if (ci.isValid()) {
|
||||
//m_listModel->removeRow(ci.row());
|
||||
m_listModel->removeRow(ci.row());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -76,3 +69,27 @@ void ConnectionManagerWindow::setupWidgetMappings()
|
|||
m_mapper->addMapping(ui->edtDbname, 6);
|
||||
m_mapper->toFirst();
|
||||
}
|
||||
|
||||
void ConnectionManagerWindow::on_actionConnect_triggered()
|
||||
{
|
||||
// Open a window for this connection, maybe we should first check the connection?
|
||||
auto ci = ui->listView->selectionModel()->currentIndex();
|
||||
auto cc = m_listModel->get(ci.row());
|
||||
if (cc.valid()) {
|
||||
auto w = new MainWindow;
|
||||
w->setAttribute( Qt::WA_DeleteOnClose );
|
||||
w->setConfig(cc.get());
|
||||
w->show();
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionManagerWindow::on_actionQuit_application_triggered()
|
||||
{
|
||||
auto res = QMessageBox::question(this, "pglab",
|
||||
tr("Close ALL windows?"), QMessageBox::Yes, QMessageBox::No);
|
||||
if (res == QMessageBox::Yes) {
|
||||
QApplication::quit();
|
||||
}
|
||||
|
||||
//closeAllWindows();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,10 @@ private slots:
|
|||
void on_currentChanged(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
void on_actionDelete_connection_triggered();
|
||||
|
||||
void on_actionConnect_triggered();
|
||||
|
||||
void on_actionQuit_application_triggered();
|
||||
|
||||
private:
|
||||
Ui::ConnectionManagerWindow *ui;
|
||||
ConnectionListModel *m_listModel = nullptr;
|
||||
|
|
|
|||
|
|
@ -197,6 +197,13 @@
|
|||
<height>25</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<property name="title">
|
||||
<string>File</string>
|
||||
</property>
|
||||
<addaction name="actionQuit_application"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
<widget class="QToolBar" name="toolBar">
|
||||
|
|
@ -250,6 +257,11 @@
|
|||
<string>Connect</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionQuit_application">
|
||||
<property name="text">
|
||||
<string>Quit application</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="resources.qrc"/>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,103 @@
|
|||
#include "databasewindow.h"
|
||||
#include "databasewindow.h"
|
||||
#include "ui_databasewindow.h"
|
||||
#include <QTimer>
|
||||
|
||||
DatabaseWindow::DatabaseWindow(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::DatabaseWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
m_dbConnection.setStateCallback([this](ASyncDBConnection::State st)
|
||||
{
|
||||
QueueTask([this, st]() { connectionStateChanged(st); });
|
||||
});
|
||||
|
||||
m_dbConnection.setNoticeCallback([this](Pgsql::ErrorDetails details)
|
||||
{
|
||||
QueueTask([this, details]() { receiveNotice(details); });
|
||||
});
|
||||
}
|
||||
|
||||
DatabaseWindow::~DatabaseWindow()
|
||||
{
|
||||
m_dbConnection.closeConnection();
|
||||
m_dbConnection.setStateCallback(nullptr);
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void DatabaseWindow::setConfig(const ConnectionConfig &config)
|
||||
{
|
||||
m_config = config;
|
||||
QString title = "pglab - ";
|
||||
title += m_config.name().c_str();
|
||||
setWindowTitle(title);
|
||||
QueueTask([this]() { startConnect(); });
|
||||
}
|
||||
|
||||
void DatabaseWindow::QueueTask(TSQueue::t_Callable c)
|
||||
{
|
||||
m_taskQueue.add(c);
|
||||
// Theoretically this needs to be only called if the queue was empty because otherwise it already would
|
||||
// be busy emptying the queue. For now however I think it is safer to call it just to make sure.
|
||||
QMetaObject::invokeMethod(this, "processCallableQueue", Qt::QueuedConnection); // queues on main thread
|
||||
}
|
||||
|
||||
void DatabaseWindow::processCallableQueue()
|
||||
{
|
||||
if (!m_taskQueue.empty()) {
|
||||
auto c = m_taskQueue.pop();
|
||||
c();
|
||||
if (!m_taskQueue.empty()) {
|
||||
QTimer::singleShot(0, this, SLOT(processCallableQueue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseWindow::startConnect()
|
||||
{
|
||||
m_dbConnection.setupConnection(m_config);
|
||||
}
|
||||
|
||||
void DatabaseWindow::connectionStateChanged(ASyncDBConnection::State state)
|
||||
{
|
||||
QString status_str;
|
||||
switch (state) {
|
||||
case ASyncDBConnection::State::NotConnected:
|
||||
status_str = tr("Geen verbinding");
|
||||
break;
|
||||
case ASyncDBConnection::State::Connecting:
|
||||
status_str = tr("Verbinden");
|
||||
break;
|
||||
case ASyncDBConnection::State::Connected:
|
||||
status_str = tr("Verbonden");
|
||||
break;
|
||||
case ASyncDBConnection::State::QuerySend:
|
||||
status_str = tr("Query verstuurd");
|
||||
break;
|
||||
case ASyncDBConnection::State::CancelSend:
|
||||
status_str = tr("Query geannuleerd");
|
||||
break;
|
||||
}
|
||||
// addLog(status_str);
|
||||
statusBar()->showMessage(status_str);
|
||||
}
|
||||
|
||||
|
||||
void DatabaseWindow::receiveNotice(Pgsql::ErrorDetails notice)
|
||||
{
|
||||
// QTextCursor cursor = ui->messagesEdit->textCursor();
|
||||
// cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
|
||||
|
||||
// QTextTable *table = cursor.insertTable(4, 2);
|
||||
// if (table) {
|
||||
// table->cellAt(1, 0).firstCursorPosition().insertText("State");
|
||||
// table->cellAt(1, 1).firstCursorPosition().insertText(QString::fromStdString(notice.state));
|
||||
// table->cellAt(2, 0).firstCursorPosition().insertText("Primary");
|
||||
// table->cellAt(2, 1).firstCursorPosition().insertText(QString::fromStdString(notice.messagePrimary));
|
||||
// table->cellAt(3, 0).firstCursorPosition().insertText("Detail");
|
||||
// table->cellAt(3, 1).firstCursorPosition().insertText(QString::fromStdString(notice.messageDetail));
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
#ifndef DATABASEWINDOW_H
|
||||
#ifndef DATABASEWINDOW_H
|
||||
#define DATABASEWINDOW_H
|
||||
|
||||
#include "asyncdbconnection.h"
|
||||
#include "tsqueue.h"
|
||||
#include <QMainWindow>
|
||||
|
||||
|
||||
namespace Ui {
|
||||
class DatabaseWindow;
|
||||
}
|
||||
|
|
@ -15,8 +18,26 @@ public:
|
|||
explicit DatabaseWindow(QWidget *parent = 0);
|
||||
~DatabaseWindow();
|
||||
|
||||
void setConfig(const ConnectionConfig &config);
|
||||
/* Meant to be called from other threads to pass a code block
|
||||
* that has to be executed in the context of the thread of the window.
|
||||
*/
|
||||
void QueueTask(TSQueue::t_Callable c);
|
||||
|
||||
private:
|
||||
Ui::DatabaseWindow *ui;
|
||||
TSQueue m_taskQueue;
|
||||
ASyncDBConnection m_dbConnection;
|
||||
ConnectionConfig m_config;
|
||||
|
||||
|
||||
void connectionStateChanged(ASyncDBConnection::State state);
|
||||
void receiveNotice(Pgsql::ErrorDetails notice);
|
||||
|
||||
void startConnect();
|
||||
private slots:
|
||||
|
||||
void processCallableQueue();
|
||||
};
|
||||
|
||||
#endif // DATABASEWINDOW_H
|
||||
|
|
|
|||
|
|
@ -21,6 +21,11 @@
|
|||
<attribute name="title">
|
||||
<string>Tab 1</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QTableView" name="tableView"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
|
|
|
|||
77
expected.h
77
expected.h
|
|
@ -4,77 +4,78 @@
|
|||
template <typename T>
|
||||
class Expected {
|
||||
union {
|
||||
T ham;
|
||||
std::exception_ptr spam;
|
||||
T m_value;
|
||||
std::exception_ptr m_error;
|
||||
};
|
||||
bool gotHam;
|
||||
bool m_valid;
|
||||
Expected() {} // internal use
|
||||
|
||||
public:
|
||||
|
||||
Expected(const T& rhs)
|
||||
: ham(rhs), gotHam(true)
|
||||
: m_value(rhs), m_valid(true)
|
||||
{}
|
||||
|
||||
Expected(T&& rhs)
|
||||
: ham(std::move(rhs))
|
||||
, gotHam(true)
|
||||
: m_value(std::move(rhs))
|
||||
, m_valid(true)
|
||||
{}
|
||||
|
||||
|
||||
Expected(const Expected& ths)
|
||||
: gotHam(rhs.gotHam)
|
||||
: m_valid(rhs.valid)
|
||||
{
|
||||
if (gotHam) {
|
||||
new (&ham) T(rhs.ham);
|
||||
if (m_valid) {
|
||||
new (&m_value) T(rhs.ham);
|
||||
}
|
||||
else {
|
||||
new (&spam) std::exception_ptr(rhs.spam);
|
||||
new (&m_error) std::exception_ptr(rhs.spam);
|
||||
}
|
||||
}
|
||||
|
||||
Expected(Expected &&rhs)
|
||||
: gotHam(rhs.getHam)
|
||||
: m_valid(rhs.m_valid)
|
||||
{
|
||||
if (gotHam) {
|
||||
new (&ham) T(std::move(rhs.ham));
|
||||
if (m_valid) {
|
||||
new (&m_value) T(std::move(rhs.m_value));
|
||||
}
|
||||
else {
|
||||
new (&spam) std::exception_ptr(std::move(rhs.spam));
|
||||
new (&m_error) std::exception_ptr(std::move(rhs.m_error));
|
||||
}
|
||||
}
|
||||
|
||||
~Expected()
|
||||
{
|
||||
if (gotHam) {
|
||||
ham.~T();
|
||||
if (m_valid) {
|
||||
m_value.~T();
|
||||
}
|
||||
else {
|
||||
using std::exception_ptr;
|
||||
spam.~exception_ptr();
|
||||
m_error.~exception_ptr();
|
||||
}
|
||||
}
|
||||
|
||||
void swap(Expected& rhs)
|
||||
{
|
||||
if (gotHam) {
|
||||
if (rhs.gotHam) {
|
||||
if (m_valid) {
|
||||
if (rhs.m_valid) {
|
||||
using std::swamp;
|
||||
swap(ham, rhs.ham);
|
||||
swap(m_value, rhs.m_value);
|
||||
}
|
||||
else {
|
||||
auto t = std::move(rhs.spam);
|
||||
new(&rhs.ham) T(std::move(ham));
|
||||
new(&spam) std::exception_ptr(t);
|
||||
std::swap(gotHam, rhs.getHam);
|
||||
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.getHam);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (rhs.gotHam) {
|
||||
if (rhs.m_valid) {
|
||||
rhs.swap(*this);
|
||||
}
|
||||
else {
|
||||
spam.swap(rhs.spam);
|
||||
std::swap(gotHam, rhs.gotHam);
|
||||
m_error.swap(rhs.m_error);
|
||||
std::swap(m_valid, rhs.m_valid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -91,8 +92,8 @@ public:
|
|||
static Expected<T> fromException(std::exception_ptr p)
|
||||
{
|
||||
Expected<T> result;
|
||||
result.gotHam = false;
|
||||
new (&result.spam) std::exception_ptr(std::move(p));
|
||||
result.m_valid = false;
|
||||
new (&result.m_error) std::exception_ptr(std::move(p));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -103,31 +104,31 @@ public:
|
|||
|
||||
bool valid() const
|
||||
{
|
||||
return gotHam;
|
||||
return m_valid;
|
||||
}
|
||||
|
||||
T& get()
|
||||
{
|
||||
if (!gotHam) {
|
||||
std::rethrow_exception(spam);
|
||||
if (!m_valid) {
|
||||
std::rethrow_exception(m_error);
|
||||
}
|
||||
return ham;
|
||||
return m_value;
|
||||
}
|
||||
|
||||
const T& get() const
|
||||
{
|
||||
if (!gotHam) {
|
||||
std::rethrow_exception(spam);
|
||||
if (!m_valid) {
|
||||
std::rethrow_exception(m_error);
|
||||
}
|
||||
return ham;
|
||||
return m_value;
|
||||
}
|
||||
|
||||
template <class E>
|
||||
bool hasException() const
|
||||
{
|
||||
try {
|
||||
if (!gotHam) {
|
||||
std::rethrow_exception(spam);
|
||||
if (!m_valid) {
|
||||
std::rethrow_exception(m_error);
|
||||
}
|
||||
}
|
||||
catch (const E& object) {
|
||||
|
|
|
|||
|
|
@ -2,3 +2,12 @@
|
|||
server_go.png=@server_go.png,0
|
||||
server_add.png=@server_add.png,0
|
||||
server_delete.png=@server_delete.png,0
|
||||
script_lightning.png=@script_lightning.png,0
|
||||
script_delete.png=@script_delete.png,0
|
||||
script_go.png=@script_go.png,0
|
||||
database.png=@database.png,0
|
||||
script.png=@script.png,0
|
||||
folder.png=@folder.png,0
|
||||
script_save.png=@script_save.png,0
|
||||
lightbulb.png=@lightbulb.png,0
|
||||
table_save.png=@table_save.png,0
|
||||
|
|
|
|||
BIN
icons/folder.png
Normal file
BIN
icons/folder.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
BIN
icons/lightbulb.png
Normal file
BIN
icons/lightbulb.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
BIN
icons/script_delete.png
Normal file
BIN
icons/script_delete.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
BIN
icons/script_go.png
Normal file
BIN
icons/script_go.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
BIN
icons/script_save.png
Normal file
BIN
icons/script_save.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
BIN
icons/table_save.png
Normal file
BIN
icons/table_save.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
|
|
@ -93,21 +93,18 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
font.setPointSize(10);
|
||||
ui->queryEdit->setFont(font);
|
||||
highlighter.reset(new SqlHighlighter(ui->queryEdit->document()));
|
||||
ui->queryEdit->setPlainText(test_query);
|
||||
ui->connectionStringEdit->setText("user=postgres dbname=foutrapport password=admin");
|
||||
// ui->queryEdit->setPlainText(test_query);
|
||||
// ui->connectionStringEdit->setText("user=postgres dbname=foutrapport password=admin");
|
||||
|
||||
QAction *action;
|
||||
action = ui->mainToolBar->addAction("connect");
|
||||
connect(action, &QAction::triggered, this, &MainWindow::startConnect);
|
||||
// QAction *action;
|
||||
// action = ui->mainToolBar->addAction("connect");
|
||||
// connect(action, &QAction::triggered, this, &MainWindow::startConnect);
|
||||
|
||||
action = ui->mainToolBar->addAction("execute");
|
||||
connect(action, &QAction::triggered, this, &MainWindow::performQuery);
|
||||
// action = ui->mainToolBar->addAction("explain");
|
||||
// connect(action, &QAction::triggered, this, &MainWindow::performExplain);
|
||||
|
||||
action = ui->mainToolBar->addAction("explain");
|
||||
connect(action, &QAction::triggered, this, &MainWindow::performExplain);
|
||||
|
||||
action = ui->mainToolBar->addAction("cancel");
|
||||
connect(action, &QAction::triggered, this, &MainWindow::cancel_query);
|
||||
// action = ui->mainToolBar->addAction("cancel");
|
||||
// connect(action, &QAction::triggered, this, &MainWindow::cancel_query);
|
||||
|
||||
m_dbConnection.setStateCallback([this](ASyncDBConnection::State st)
|
||||
{
|
||||
|
|
@ -130,6 +127,15 @@ MainWindow::~MainWindow()
|
|||
delete ui;
|
||||
}
|
||||
|
||||
void MainWindow::setConfig(const ConnectionConfig &config)
|
||||
{
|
||||
m_config = config;
|
||||
QString title = "pglab - ";
|
||||
title += m_config.name().c_str();
|
||||
setWindowTitle(title);
|
||||
QueueTask([this]() { startConnect(); });
|
||||
}
|
||||
|
||||
void MainWindow::QueueTask(TSQueue::t_Callable c)
|
||||
{
|
||||
m_taskQueue.add(c);
|
||||
|
|
@ -175,8 +181,9 @@ void MainWindow::connectionStateChanged(ASyncDBConnection::State state)
|
|||
|
||||
void MainWindow::startConnect()
|
||||
{
|
||||
std::string connstr = ui->connectionStringEdit->text().toUtf8().data();
|
||||
m_dbConnection.setupConnection(connstr);
|
||||
// std::string connstr = ui->connectionStringEdit->text().toUtf8().data();
|
||||
// m_dbConnection.setupConnection(connstr);
|
||||
m_dbConnection.setupConnection(m_config);
|
||||
}
|
||||
|
||||
void MainWindow::performQuery()
|
||||
|
|
@ -206,6 +213,7 @@ void MainWindow::query_ready(std::shared_ptr<Pgsql::Result> dbres)
|
|||
if (st == PGRES_TUPLES_OK) {
|
||||
resultModel.reset(new QueryResultModel(nullptr , dbres));
|
||||
ui->ResultView->setModel(resultModel.get());
|
||||
ui->tabWidget->setCurrentWidget(ui->dataTab);
|
||||
statusBar()->showMessage(tr("Query ready."));
|
||||
}
|
||||
else {
|
||||
|
|
@ -239,6 +247,7 @@ void MainWindow::query_ready(std::shared_ptr<Pgsql::Result> dbres)
|
|||
else {
|
||||
statusBar()->showMessage(tr("No tuples returned, possibly an error..."));
|
||||
}
|
||||
ui->tabWidget->setCurrentWidget(ui->messageTab);
|
||||
receiveNotice(dbres->diagDetails());
|
||||
}
|
||||
}
|
||||
|
|
@ -303,10 +312,12 @@ void MainWindow::explain_ready(ExplainRoot::SPtr explain)
|
|||
ui->explainTreeView->setColumnWidth(4, 80);
|
||||
ui->explainTreeView->setColumnWidth(5, 80);
|
||||
ui->explainTreeView->setColumnWidth(6, 600);
|
||||
ui->tabWidget->setCurrentWidget(ui->explainTab);
|
||||
statusBar()->showMessage(tr("Explain ready."));
|
||||
}
|
||||
else {
|
||||
addLog("Explain no result");
|
||||
ui->tabWidget->setCurrentWidget(ui->messageTab);
|
||||
statusBar()->showMessage(tr("Explain failed."));
|
||||
}
|
||||
}
|
||||
|
|
@ -321,10 +332,6 @@ void MainWindow::receiveNotice(Pgsql::ErrorDetails notice)
|
|||
QTextCursor cursor = ui->messagesEdit->textCursor();
|
||||
cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
|
||||
|
||||
|
||||
// QString msg;
|
||||
// cursor.insertText("TEST\r\n");
|
||||
|
||||
QTextTable *table = cursor.insertTable(4, 2);
|
||||
if (table) {
|
||||
table->cellAt(1, 0).firstCursorPosition().insertText("State");
|
||||
|
|
@ -466,3 +473,18 @@ void Copy( )
|
|||
QApplication.clipboard().setText(selected_text);
|
||||
}
|
||||
#endif
|
||||
|
||||
void MainWindow::on_actionExecute_SQL_triggered()
|
||||
{
|
||||
performQuery();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionExplain_Analyze_triggered()
|
||||
{
|
||||
performExplain();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionCancel_triggered()
|
||||
{
|
||||
cancel_query();
|
||||
}
|
||||
|
|
|
|||
20
mainwindow.h
20
mainwindow.h
|
|
@ -2,6 +2,7 @@
|
|||
#define MAINWINDOW_H
|
||||
|
||||
#include "asyncdbconnection.h"
|
||||
#include "connectionconfig.h"
|
||||
#include "tsqueue.h"
|
||||
#include <QLabel>
|
||||
#include <QMainWindow>
|
||||
|
|
@ -9,6 +10,8 @@
|
|||
#include <memory>
|
||||
#include <future>
|
||||
#include "PgsqlConn.h"
|
||||
#include <deque>
|
||||
#include <mutex>
|
||||
|
||||
class ExplainRoot;
|
||||
class QueryResultModel;
|
||||
|
|
@ -20,28 +23,18 @@ namespace Ui {
|
|||
}
|
||||
|
||||
namespace Pgsql {
|
||||
|
||||
class Connection;
|
||||
|
||||
}
|
||||
|
||||
#include <deque>
|
||||
#include <mutex>
|
||||
|
||||
class TaskQueue {
|
||||
public:
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = 0);
|
||||
~MainWindow();
|
||||
|
||||
void setConfig(const ConnectionConfig &config);
|
||||
/* Meant to be called from other threads to pass a code block
|
||||
* that has to be executed in the context of the thread of the window.
|
||||
*/
|
||||
|
|
@ -52,6 +45,8 @@ private:
|
|||
QLabel *m_timeElapsedLabel;
|
||||
std::unique_ptr<QTimer> m_timer;
|
||||
std::chrono::time_point<std::chrono::steady_clock> m_startTime;
|
||||
ConnectionConfig m_config;
|
||||
|
||||
|
||||
void startTimer();
|
||||
void endTimer();
|
||||
|
|
@ -88,6 +83,9 @@ private slots:
|
|||
void on_actionExport_data_triggered();
|
||||
void on_actionClose_triggered();
|
||||
void on_actionAbout_triggered();
|
||||
void on_actionExecute_SQL_triggered();
|
||||
void on_actionExplain_Analyze_triggered();
|
||||
void on_actionCancel_triggered();
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
<string>pglab - database</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralWidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
|
|
@ -27,9 +27,6 @@
|
|||
<property name="bottomMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="connectionStringEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="orientation">
|
||||
|
|
@ -211,19 +208,38 @@
|
|||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<addaction name="actionLoad_SQL"/>
|
||||
<addaction name="actionSave_SQL"/>
|
||||
<addaction name="actionExport_data"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionExecute_SQL"/>
|
||||
<addaction name="actionExplain_Analyze"/>
|
||||
<addaction name="actionCancel"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusBar"/>
|
||||
<action name="actionLoad_SQL">
|
||||
<property name="icon">
|
||||
<iconset resource="resources.qrc">
|
||||
<normaloff>:/icons/folder.png</normaloff>:/icons/folder.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Load SQL</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSave_SQL">
|
||||
<property name="icon">
|
||||
<iconset resource="resources.qrc">
|
||||
<normaloff>:/icons/script_save.png</normaloff>:/icons/script_save.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save SQL</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExport_data">
|
||||
<property name="icon">
|
||||
<iconset resource="resources.qrc">
|
||||
<normaloff>:/icons/table_save.png</normaloff>:/icons/table_save.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Export data</string>
|
||||
</property>
|
||||
|
|
@ -238,8 +254,39 @@
|
|||
<string>About</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExecute_SQL">
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normalon>:/icons/script_go.png</normalon>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Execute SQL</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCancel">
|
||||
<property name="icon">
|
||||
<iconset>
|
||||
<normalon>:/icons/script_delete.png</normalon>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Cancel</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExplain_Analyze">
|
||||
<property name="icon">
|
||||
<iconset resource="resources.qrc">
|
||||
<normaloff>:/icons/lightbulb.png</normaloff>:/icons/lightbulb.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Explain Analyze</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
<resources>
|
||||
<include location="resources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
<RCC>
|
||||
<qresource>
|
||||
<qresource prefix="/">
|
||||
<file>icons/server_add.png</file>
|
||||
<file>icons/server_delete.png</file>
|
||||
<file>icons/server_go.png</file>
|
||||
<file>icons/script_delete.png</file>
|
||||
<file>icons/script_go.png</file>
|
||||
<file>icons/folder.png</file>
|
||||
<file>icons/script_save.png</file>
|
||||
<file>icons/lightbulb.png</file>
|
||||
<file>icons/table_save.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue