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:
Eelke Klein 2017-01-15 21:01:40 +01:00
parent 88fcc0338d
commit d19741f111
26 changed files with 408 additions and 116 deletions

1
.gitignore vendored
View file

@ -4,3 +4,4 @@ DIST/
Makefile
Makefile.Debug
Makefile.Release
desktop.ini

View file

@ -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);

View file

@ -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();

View file

@ -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();

View file

@ -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();

View file

@ -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);

View file

@ -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()
{

View file

@ -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:

View file

@ -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 &current,
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();
}

View file

@ -25,6 +25,10 @@ private slots:
void on_currentChanged(const QModelIndex &current, 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;

View file

@ -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"/>

View file

@ -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));
// }
}

View file

@ -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

View file

@ -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">

View file

@ -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) {

View file

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
icons/lightbulb.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -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();
}

View file

@ -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

View file

@ -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>

View file

@ -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>