The querytab now shows the elapsed time of the query using the new stopwatch class.

The old elapsedtime code from the mainwindow has been removed.
This commit is contained in:
Eelke Klein 2017-01-22 08:50:41 +01:00
parent 7f379f3b80
commit 6e852f466f
7 changed files with 232 additions and 163 deletions

View file

@ -14,23 +14,10 @@
#include <QCloseEvent> #include <QCloseEvent>
#include <querytab.h> #include <querytab.h>
#include "util.h" #include "util.h"
//#include <thread>
namespace pg = Pgsql; namespace pg = Pgsql;
const char * test_query =
//"SELECT id, program, version, lic_bedrijf, lic_plaats, "
//"lic_number, callstack_crc_1, callstack_crc_2, callstack_crc_3, exception_class, "
//"exception_message \nFROM foutrapport"
"SELECT f1.id, f1.program, f1.version, f1.lic_number, f1.callstack_crc_1, f1.callstack_crc_2, array_agg(f2.id) \n"
"FROM foutrapport f1 JOIN foutrapport f2 USING (callstack_crc_2) \n"
"WHERE f1.actief \n"
"GROUP BY f1.id"
;
MainWindow::MainWindow(QWidget *parent) MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent) : QMainWindow(parent)
@ -38,37 +25,22 @@ MainWindow::MainWindow(QWidget *parent)
{ {
ui->setupUi(this); ui->setupUi(this);
ui->tabWidget->setDocumentMode(true);
m_timeElapsedLabel = new QLabel(this); ui->tabWidget->setTabsClosable(true);
statusBar()->addPermanentWidget(m_timeElapsedLabel);
// {
// QVBoxLayout *layout = new QVBoxLayout;
// layout->addWidget(m_queryTab);
// layout->setMargin(4);
// ui->tab_2->setLayout(layout);
// }
} }
MainWindow::~MainWindow() MainWindow::~MainWindow()
{ {
// m_dbConnection.closeConnection();
// m_dbConnection.setStateCallback(nullptr);
delete ui; delete ui;
} }
void MainWindow::newSqlPage() QueryTab* MainWindow::newSqlPage()
{ {
QueryTab *qt = new QueryTab(this); QueryTab *qt = new QueryTab(this);
qt->setConfig(m_config); qt->setConfig(m_config);
// QVBoxLayout *layout = new QVBoxLayout;
// layout->addWidget(qt);
// layout->setMargin(4);
ui->tabWidget->addTab(qt, "Tab"); ui->tabWidget->addTab(qt, "Tab");
ui->tabWidget->setCurrentWidget(qt);
return qt;
} }
QueryTab *MainWindow::GetActiveQueryTab() QueryTab *MainWindow::GetActiveQueryTab()
@ -106,52 +78,16 @@ void MainWindow::processCallableQueue()
} }
} }
void MainWindow::startTimer()
{
m_startTime = std::chrono::steady_clock::now();
m_timer = std::make_unique<QTimer>(nullptr);
m_timer->setTimerType(Qt::CoarseTimer);
connect(m_timer.get(), SIGNAL(timeout()), this, SLOT(updateTimer()));
m_timer->start(18);
}
void MainWindow::updateTimer()
{
auto nu = std::chrono::steady_clock::now();
std::chrono::duration<float, std::milli> diff = nu - m_startTime;
elapsedTime = diff;
m_timeElapsedLabel->setText(msfloatToHumanReadableString(diff.count()));
if (m_timer) {
int ms = diff.count();
int interval = 18;
if (ms >= 10000) {
int rem = ms % 1000;
interval = 1000 - rem;
}
else if (ms >= 1000) {
interval = 100;
}
m_timer->start(interval);
}
}
void MainWindow::endTimer()
{
if (m_timer) {
m_timer.reset();
updateTimer();
}
}
void MainWindow::on_actionLoad_SQL_triggered() void MainWindow::on_actionLoad_SQL_triggered()
{ {
QueryTab *tab = GetActiveQueryTab(); QString home_dir = QStandardPaths::locate(QStandardPaths::HomeLocation, "", QStandardPaths::LocateDirectory);
if (tab) { QString file_name = QFileDialog::getOpenFileName(this,
tab->open(); tr("Open sql query"), home_dir, tr("SQL files (*.sql *.txt)"));
if ( ! file_name.isEmpty()) {
QueryTab* qt = newSqlPage();
qt->load(file_name);
} }
} }
void MainWindow::on_actionSave_SQL_triggered() void MainWindow::on_actionSave_SQL_triggered()
@ -272,11 +208,16 @@ void MainWindow::showEvent(QShowEvent *event)
event->accept(); event->accept();
} }
void MainWindow::on_actionNew_SQL_triggered() void MainWindow::on_actionNew_SQL_triggered()
{ {
newSqlPage(); newSqlPage()->newdoc();
}
void MainWindow::on_tabWidget_tabCloseRequested(int index)
{
QWidget *widget = ui->tabWidget->widget(index);
QueryTab *qt = dynamic_cast<QueryTab*>(widget);
if (qt->canClose()) {
ui->tabWidget->removeTab(index);
}
} }

View file

@ -45,34 +45,21 @@ public:
private: private:
TSQueue m_taskQueue; Ui::MainWindow *ui;
QLabel *m_timeElapsedLabel;
std::chrono::duration<float, std::milli> elapsedTime;
TSQueue m_taskQueue;
ConnectionConfig m_config; ConnectionConfig m_config;
std::unique_ptr<QTimer> m_timer;
std::chrono::time_point<std::chrono::steady_clock> m_startTime;
void startTimer();
void endTimer();
Ui::MainWindow *ui;
QueryTab *GetActiveQueryTab(); QueryTab *GetActiveQueryTab();
void closeEvent(QCloseEvent *event); void closeEvent(QCloseEvent *event);
void showEvent(QShowEvent *event); void showEvent(QShowEvent *event);
void newSqlPage(); QueryTab *newSqlPage();
private slots: private slots:
void processCallableQueue(); void processCallableQueue();
void updateTimer();
void on_actionLoad_SQL_triggered(); void on_actionLoad_SQL_triggered();
void on_actionSave_SQL_triggered(); void on_actionSave_SQL_triggered();
void on_actionExport_data_triggered(); void on_actionExport_data_triggered();
@ -84,6 +71,7 @@ private slots:
void on_actionSave_SQL_as_triggered(); void on_actionSave_SQL_as_triggered();
void on_actionSave_copy_of_SQL_as_triggered(); void on_actionSave_copy_of_SQL_as_triggered();
void on_actionNew_SQL_triggered(); void on_actionNew_SQL_triggered();
void on_tabWidget_tabCloseRequested(int index);
}; };
#endif // MAINWINDOW_H #endif // MAINWINDOW_H

View file

@ -6,6 +6,8 @@
#include <QStandardPaths> #include <QStandardPaths>
#include <QFileDialog> #include <QFileDialog>
#include <QMessageBox> #include <QMessageBox>
#include <QTabWidget>
#include <QTextCodec>
#include <QTextDocumentFragment> #include <QTextDocumentFragment>
#include <QTextStream> #include <QTextStream>
#include "explaintreemodelitem.h" #include "explaintreemodelitem.h"
@ -38,7 +40,9 @@ QueryTab::QueryTab(MainWindow *win, QWidget *parent) :
highlighter.reset(new SqlHighlighter(ui->queryEdit->document())); highlighter.reset(new SqlHighlighter(ui->queryEdit->document()));
connect(ui->queryEdit, &QPlainTextEdit::textChanged, this, &QueryTab::queryTextChanged); connect(ui->queryEdit, &QPlainTextEdit::textChanged, this, &QueryTab::queryTextChanged);
m_stopwatch.setOutputLabel(ui->lblElapsedTime);
ui->lblElapsedTime->clear();
ui->lblRowCount->clear();
} }
QueryTab::~QueryTab() QueryTab::~QueryTab()
@ -57,28 +61,72 @@ void QueryTab::setConfig(const ConnectionConfig &config)
m_win->QueueTask([this]() { startConnect(); }); m_win->QueueTask([this]() { startConnect(); });
} }
void QueryTab::open() bool QueryTab::canClose()
{ {
if (m_queryTextChanged && !continueWithoutSavingWarning()) { bool can_close;
return; if (m_queryTextChanged) {
can_close = continueWithoutSavingWarning();
}
else {
can_close = true;
}
return can_close;
}
//void QueryTab::open()
//{
// if (m_queryTextChanged && !continueWithoutSavingWarning()) {
// return;
// }
// QString home_dir = QStandardPaths::locate(QStandardPaths::HomeLocation, "", QStandardPaths::LocateDirectory);
// QString file_name = QFileDialog::getOpenFileName(this,
// tr("Open sql query"), home_dir, tr("SQL files (*.sql *.txt)"));
// if ( ! file_name.isEmpty()) {
// QFile file(file_name);
// if (file.open(QIODevice::ReadWrite)) {
// QTextStream stream(&file);
// ui->queryEdit->clear();
// while (!stream.atEnd()){
// QString line = stream.readLine();
// ui->queryEdit->appendPlainText(line);
// }
// m_queryTextChanged = false;
// setFileName(file_name);
// }
// }
//}
void QueryTab::newdoc()
{
ui->queryEdit->clear();
setFileName(QString());
m_queryTextChanged = false;
}
bool QueryTab::load(const QString &filename)
{
bool result = false;
QFile file(filename);
if (file.open(QIODevice::ReadOnly)) {
QByteArray ba = file.readAll();
const char *ptr = ba.constData();
QTextCodec *codec = QTextCodec::codecForUtfText(ba, QTextCodec::codecForName("utf-8"));
QTextCodec::ConverterState state;
QString text = codec->toUnicode(ptr, ba.size(), &state);
if (state.invalidChars > 0) {
file.reset();
QTextStream stream(&file);
text = stream.readAll();
} }
QString home_dir = QStandardPaths::locate(QStandardPaths::HomeLocation, "", QStandardPaths::LocateDirectory); ui->queryEdit->setPlainText(text);
QString file_name = QFileDialog::getOpenFileName(this,
tr("Open sql query"), home_dir, tr("SQL files (*.sql *.txt)"));
if ( ! file_name.isEmpty()) {
QFile file(file_name);
if (file.open(QIODevice::ReadWrite)) {
QTextStream stream(&file);
ui->queryEdit->clear();
while (!stream.atEnd()){
QString line = stream.readLine();
ui->queryEdit->appendPlainText(line);
}
m_queryTextChanged = false; m_queryTextChanged = false;
setFileName(file_name); setFileName(filename);
} result = true;
} }
return result;
} }
void QueryTab::save() void QueryTab::save()
@ -113,12 +161,11 @@ void QueryTab::execute()
if (m_dbConnection.state() == ASyncDBConnection::State::Connected) { if (m_dbConnection.state() == ASyncDBConnection::State::Connected) {
addLog("Query clicked"); addLog("Query clicked");
ui->ResultView->setModel(nullptr); clearResult();
resultModel.reset();
ui->messagesEdit->clear(); ui->messagesEdit->clear();
std::string cmd = getCommand(); std::string cmd = getCommand();
//startTimer(); m_stopwatch.start();
m_dbConnection.send(cmd, m_dbConnection.send(cmd,
[this](std::shared_ptr<Pgsql::Result> res) [this](std::shared_ptr<Pgsql::Result> res)
{ {
@ -135,7 +182,7 @@ void QueryTab::explainAnalyze()
addLog("Explain clicked"); addLog("Explain clicked");
//startTimer(); m_stopwatch.start();
std::string cmd = "EXPLAIN (ANALYZE, VERBOSE, BUFFERS, FORMAT JSON) " + getCommand(); std::string cmd = "EXPLAIN (ANALYZE, VERBOSE, BUFFERS, FORMAT JSON) " + getCommand();
m_dbConnection.send(cmd, m_dbConnection.send(cmd,
[this](std::shared_ptr<Pgsql::Result> res) [this](std::shared_ptr<Pgsql::Result> res)
@ -169,6 +216,7 @@ void QueryTab::cancel()
void QueryTab::setFileName(const QString &filename) void QueryTab::setFileName(const QString &filename)
{ {
m_fileName = filename; m_fileName = filename;
setTabCaption(m_fileName);
} }
bool QueryTab::continueWithoutSavingWarning() bool QueryTab::continueWithoutSavingWarning()
@ -183,15 +231,32 @@ bool QueryTab::continueWithoutSavingWarning()
return ret == QMessageBox::Yes; return ret == QMessageBox::Yes;
} }
void QueryTab::saveSqlTo(const QString &filename) bool QueryTab::saveSqlTo(const QString &filename)
{ {
bool result = false;
QFile file(filename); QFile file(filename);
if (file.open(QIODevice::ReadWrite)) { if (file.open(QIODevice::WriteOnly)) {
QTextStream stream(&file); QTextStream stream(&file);
stream.setCodec("utf-8");
QString text = ui->queryEdit->toPlainText(); QString text = ui->queryEdit->toPlainText();
stream << text; stream << text;
/*
QTextDocument *doc = ui->queryEdit->document();
QTextBlock block = doc->firstBlock();
while (stream.status() == QTextStream::Ok && block.isValid()) {
QString plain = block.text();
stream << plain << "\n";
block = block.next();
}*/
if (stream.status() == QTextStream::Ok) {
m_queryTextChanged = false; m_queryTextChanged = false;
result = true;
} }
}
return result;
} }
QString QueryTab::promptUserForSaveSqlFilename() QString QueryTab::promptUserForSaveSqlFilename()
@ -297,7 +362,7 @@ void QueryTab::startConnect()
void QueryTab::explain_ready(ExplainRoot::SPtr explain) void QueryTab::explain_ready(ExplainRoot::SPtr explain)
{ {
// endTimer(); m_stopwatch.stop();
if (explain) { if (explain) {
addLog("Explain ready"); addLog("Explain ready");
QString times_str = QString("Execution time: %1, Planning time: %2") QString times_str = QString("Execution time: %1, Planning time: %2")
@ -338,13 +403,30 @@ std::string QueryTab::getCommand() const
return command.toUtf8().data(); return command.toUtf8().data();
} }
void QueryTab::setTabCaption(const QString &caption)
{
QWidget * w = parentWidget();
QWidget * p = w->parentWidget();
QTabWidget *tabwidget = dynamic_cast<QTabWidget*>(p);
if (tabwidget) {
int i = tabwidget->indexOf(this);
if (i >= 0) {
tabwidget->setTabText(i, caption);
}
}
}
void QueryTab::query_ready(std::shared_ptr<Pgsql::Result> dbres) void QueryTab::query_ready(std::shared_ptr<Pgsql::Result> dbres)
{ {
//endTimer(); m_stopwatch.stop();
if (dbres) { if (dbres) {
addLog("query_ready with result"); addLog("query_ready with result");
auto st = dbres->resultStatus(); auto st = dbres->resultStatus();
if (st == PGRES_TUPLES_OK) { if (st == PGRES_TUPLES_OK) {
//int n_rows = dbres->getRows();
QString rowcount_str = QString("rows: %1").arg(dbres->getRows());
ui->lblRowCount->setText(rowcount_str);
resultModel.reset(new QueryResultModel(nullptr , dbres)); resultModel.reset(new QueryResultModel(nullptr , dbres));
ui->ResultView->setModel(resultModel.get()); ui->ResultView->setModel(resultModel.get());
ui->tabWidget->setCurrentWidget(ui->dataTab); ui->tabWidget->setCurrentWidget(ui->dataTab);
@ -355,7 +437,7 @@ void QueryTab::query_ready(std::shared_ptr<Pgsql::Result> dbres)
// statusBar()->showMessage(tr("Command OK.")); // statusBar()->showMessage(tr("Command OK."));
QString msg = tr("Query returned succesfully: %1 rows affected, %2 execution time.") QString msg = tr("Query returned succesfully: %1 rows affected, %2 execution time.")
.arg(QString::number(dbres->tuplesAffected())) .arg(QString::number(dbres->tuplesAffected()))
.arg(0); //msfloatToHumanReadableString(elapsedTime.count())); .arg(m_stopwatch.elapsed()); //msfloatToHumanReadableString(elapsedTime.count()));
ui->messagesEdit->append(msg); ui->messagesEdit->append(msg);
ui->tabWidget->setCurrentWidget(ui->messageTab); ui->tabWidget->setCurrentWidget(ui->messageTab);
@ -398,3 +480,10 @@ void QueryTab::query_ready(std::shared_ptr<Pgsql::Result> dbres)
// statusBar()->showMessage(tr("Query cancelled.")); // statusBar()->showMessage(tr("Query cancelled."));
} }
} }
void QueryTab::clearResult()
{
ui->ResultView->setModel(nullptr);
resultModel.reset();
ui->lblRowCount->clear();
}

View file

@ -2,8 +2,9 @@
#define QUERYTAB_H #define QUERYTAB_H
#include "asyncdbconnection.h" #include "asyncdbconnection.h"
#include "QueryResultModel.h" #include "queryresultmodel.h"
#include "QueryExplainModel.h" #include "queryexplainmodel.h"
#include "stopwatch.h"
#include <QWidget> #include <QWidget>
#include <memory> #include <memory>
@ -29,7 +30,9 @@ public:
void setConfig(const ConnectionConfig &config); void setConfig(const ConnectionConfig &config);
void open(); void newdoc();
// void open();
bool load(const QString &filename);
void save(); void save();
void saveAs(); void saveAs();
void saveCopyAs(); void saveCopyAs();
@ -37,18 +40,21 @@ public:
void execute(); void execute();
void explainAnalyze(); void explainAnalyze();
void cancel(); void cancel();
bool canClose();
private: private:
Ui::QueryTab *ui; Ui::QueryTab *ui;
MainWindow *m_win; MainWindow *m_win;
std::unique_ptr<SqlHighlighter> highlighter; std::unique_ptr<SqlHighlighter> highlighter;
ConnectionConfig m_config; ConnectionConfig m_config;
StopWatch m_stopwatch;
QString m_fileName; ///< use setFileName function to set QString m_fileName; ///< use setFileName function to set
bool m_queryTextChanged = false; bool m_queryTextChanged = false;
void setFileName(const QString &filename); void setFileName(const QString &filename);
bool continueWithoutSavingWarning(); bool continueWithoutSavingWarning();
void saveSqlTo(const QString &filename); bool saveSqlTo(const QString &filename);
QString promptUserForSaveSqlFilename(); QString promptUserForSaveSqlFilename();
@ -61,6 +67,9 @@ private:
std::string getCommand() const; std::string getCommand() const;
void explain_ready(ExplainRoot::SPtr explain); void explain_ready(ExplainRoot::SPtr explain);
void query_ready(std::shared_ptr<Pgsql::Result> dbres); void query_ready(std::shared_ptr<Pgsql::Result> dbres);
void setTabCaption(const QString &caption);
void clearResult();
private slots: private slots:
void queryTextChanged(); void queryTextChanged();

View file

@ -37,7 +37,7 @@
<widget class="QPlainTextEdit" name="queryEdit"/> <widget class="QPlainTextEdit" name="queryEdit"/>
<widget class="QTabWidget" name="tabWidget"> <widget class="QTabWidget" name="tabWidget">
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>1</number>
</property> </property>
<widget class="QWidget" name="messageTab"> <widget class="QWidget" name="messageTab">
<attribute name="title"> <attribute name="title">
@ -69,20 +69,8 @@
<attribute name="title"> <attribute name="title">
<string>Data</string> <string>Data</string>
</attribute> </attribute>
<layout class="QGridLayout" name="gridLayout"> <layout class="QVBoxLayout" name="verticalLayout_3">
<property name="leftMargin"> <item>
<number>2</number>
</property>
<property name="topMargin">
<number>2</number>
</property>
<property name="rightMargin">
<number>2</number>
</property>
<property name="bottomMargin">
<number>2</number>
</property>
<item row="0" column="0">
<widget class="QTableView" name="ResultView"> <widget class="QTableView" name="ResultView">
<property name="font"> <property name="font">
<font> <font>
@ -110,6 +98,26 @@
</attribute> </attribute>
</widget> </widget>
</item> </item>
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="lblElapsedTime">
<property name="text">
<string>0ms</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblRowCount">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="explainTab"> <widget class="QWidget" name="explainTab">

View file

@ -1,16 +1,24 @@
#include "stopwatch.h" #include "stopwatch.h"
#include "util.h" #include "util.h"
#include <QLabel>
StopWatch::StopWatch() StopWatch::StopWatch()
: m_elapsed(std::make_unique<QElapsedTimer>())
{} {}
void StopWatch::start() void StopWatch::start()
{ {
m_elapsed->start(); m_elapsed.start();
m_timer = std::make_unique<QTimer>(nullptr); connect(&m_timer, SIGNAL(timeout()), this, SLOT(updateTimer()));
connect(m_timer.get(), SIGNAL(timeout()), this, SLOT(updateTimer())); m_timer.start(18);
m_timer->start(18); }
void StopWatch::stop()
{
m_timeTaken = m_elapsed.elapsed();
m_timer.stop();
updateTimer();
m_elapsed.invalidate();
} }
void StopWatch::updateTimer() void StopWatch::updateTimer()
@ -19,20 +27,40 @@ void StopWatch::updateTimer()
// std::chrono::duration<float, std::milli> diff = nu - m_startTime; // std::chrono::duration<float, std::milli> diff = nu - m_startTime;
// elapsedTime = diff; // elapsedTime = diff;
// m_timeElapsedLabel->setText(msfloatToHumanReadableString(diff.count())); // m_timeElapsedLabel->setText(msfloatToHumanReadableString(diff.count()));
if (m_elapsed.isValid()) {
qint64 ms = m_elapsed.elapsed();
m_output->setText(msfloatToHumanReadableString(ms));
qint64 ms = m_elapsed->elapsed();
msfloatToHumanReadableString(ms);
if (m_timer) { if (m_timer.isActive()) {
int interval = 18; int interval;
if (ms >= 10000) { if (ms >= 10000) {
int rem = ms % 1000; int rem = ms % 1000;
interval = 1000 - rem; interval = 1000 - rem;
} }
else if (ms >= 1000) { else if (ms >= 1000)
interval = 100; interval = 100;
} else
interval = 18;
m_timer->start(interval); if (interval != m_timer.interval())
m_timer.setInterval(interval);
}
} }
} }
void StopWatch::setOutputLabel(QLabel *label)
{
m_output = label;
}
qint64 StopWatch::elapsed()
{
qint64 result;
if (m_elapsed.isValid())
result = m_elapsed.elapsed();
else
result = m_timeTaken;
return result;
}

View file

@ -3,7 +3,8 @@
#include <QTimer> #include <QTimer>
#include <QElapsedTimer> #include <QElapsedTimer>
#include <memory>
class QLabel;
class StopWatch : public QObject { class StopWatch : public QObject {
Q_OBJECT Q_OBJECT
@ -12,9 +13,14 @@ public:
void start(); void start();
qint64 elapsed(); qint64 elapsed();
void stop();
void setOutputLabel(QLabel *label);
private: private:
std::unique_ptr<QElapsedTimer> m_elapsed = nullptr; ///< Keeps time QElapsedTimer m_elapsed; // = nullptr; ///< Keeps time
std::unique_ptr<QTimer> m_timer = nullptr; ///< triggers updates QTimer m_timer; ///< triggers updates
QLabel* m_output = nullptr;
qint64 m_timeTaken = 0LL;
private slots: private slots: