From 6e852f466f6e606a1382332283073b7e18fdc436 Mon Sep 17 00:00:00 2001 From: Eelke Klein Date: Sun, 22 Jan 2017 08:50:41 +0100 Subject: [PATCH] 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. --- mainwindow.cpp | 103 ++++++++--------------------------- mainwindow.h | 20 ++----- querytab.cpp | 143 +++++++++++++++++++++++++++++++++++++++---------- querytab.h | 17 ++++-- querytab.ui | 38 +++++++------ stopwatch.cpp | 62 +++++++++++++++------ stopwatch.h | 12 +++-- 7 files changed, 232 insertions(+), 163 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index feba16f..a84761b 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -14,23 +14,10 @@ #include #include #include "util.h" -//#include - 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) : QMainWindow(parent) @@ -38,37 +25,22 @@ MainWindow::MainWindow(QWidget *parent) { ui->setupUi(this); - - m_timeElapsedLabel = new QLabel(this); - statusBar()->addPermanentWidget(m_timeElapsedLabel); - - -// { -// QVBoxLayout *layout = new QVBoxLayout; -// layout->addWidget(m_queryTab); -// layout->setMargin(4); -// ui->tab_2->setLayout(layout); -// } - + ui->tabWidget->setDocumentMode(true); + ui->tabWidget->setTabsClosable(true); } MainWindow::~MainWindow() { -// m_dbConnection.closeConnection(); -// m_dbConnection.setStateCallback(nullptr); delete ui; } -void MainWindow::newSqlPage() +QueryTab* MainWindow::newSqlPage() { QueryTab *qt = new QueryTab(this); qt->setConfig(m_config); -// QVBoxLayout *layout = new QVBoxLayout; -// layout->addWidget(qt); -// layout->setMargin(4); - ui->tabWidget->addTab(qt, "Tab"); - + ui->tabWidget->setCurrentWidget(qt); + return qt; } 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(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 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() { - QueryTab *tab = GetActiveQueryTab(); - if (tab) { - tab->open(); + 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()) { + QueryTab* qt = newSqlPage(); + qt->load(file_name); } + } void MainWindow::on_actionSave_SQL_triggered() @@ -272,11 +208,16 @@ void MainWindow::showEvent(QShowEvent *event) event->accept(); } - - - - 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(widget); + if (qt->canClose()) { + ui->tabWidget->removeTab(index); + } } diff --git a/mainwindow.h b/mainwindow.h index 424d7ca..57f6fa1 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -45,34 +45,21 @@ public: private: - TSQueue m_taskQueue; - QLabel *m_timeElapsedLabel; - std::chrono::duration elapsedTime; + Ui::MainWindow *ui; + TSQueue m_taskQueue; ConnectionConfig m_config; - std::unique_ptr m_timer; - std::chrono::time_point m_startTime; - void startTimer(); - void endTimer(); - - - Ui::MainWindow *ui; - QueryTab *GetActiveQueryTab(); - - - void closeEvent(QCloseEvent *event); void showEvent(QShowEvent *event); - void newSqlPage(); + QueryTab *newSqlPage(); private slots: void processCallableQueue(); - void updateTimer(); void on_actionLoad_SQL_triggered(); void on_actionSave_SQL_triggered(); void on_actionExport_data_triggered(); @@ -84,6 +71,7 @@ private slots: void on_actionSave_SQL_as_triggered(); void on_actionSave_copy_of_SQL_as_triggered(); void on_actionNew_SQL_triggered(); + void on_tabWidget_tabCloseRequested(int index); }; #endif // MAINWINDOW_H diff --git a/querytab.cpp b/querytab.cpp index 194814e..b52da2a 100644 --- a/querytab.cpp +++ b/querytab.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #include #include "explaintreemodelitem.h" @@ -38,7 +40,9 @@ QueryTab::QueryTab(MainWindow *win, QWidget *parent) : highlighter.reset(new SqlHighlighter(ui->queryEdit->document())); connect(ui->queryEdit, &QPlainTextEdit::textChanged, this, &QueryTab::queryTextChanged); - + m_stopwatch.setOutputLabel(ui->lblElapsedTime); + ui->lblElapsedTime->clear(); + ui->lblRowCount->clear(); } QueryTab::~QueryTab() @@ -57,28 +61,72 @@ void QueryTab::setConfig(const ConnectionConfig &config) m_win->QueueTask([this]() { startConnect(); }); } -void QueryTab::open() +bool QueryTab::canClose() { - if (m_queryTextChanged && !continueWithoutSavingWarning()) { - return; + bool can_close; + if (m_queryTextChanged) { + can_close = continueWithoutSavingWarning(); } + else { + can_close = true; + } + return can_close; +} - 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)) { +//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); - ui->queryEdit->clear(); - while (!stream.atEnd()){ - QString line = stream.readLine(); - ui->queryEdit->appendPlainText(line); - } - m_queryTextChanged = false; - setFileName(file_name); + text = stream.readAll(); } + + ui->queryEdit->setPlainText(text); + m_queryTextChanged = false; + setFileName(filename); + result = true; } + return result; } void QueryTab::save() @@ -113,12 +161,11 @@ void QueryTab::execute() if (m_dbConnection.state() == ASyncDBConnection::State::Connected) { addLog("Query clicked"); - ui->ResultView->setModel(nullptr); - resultModel.reset(); + clearResult(); ui->messagesEdit->clear(); std::string cmd = getCommand(); - //startTimer(); + m_stopwatch.start(); m_dbConnection.send(cmd, [this](std::shared_ptr res) { @@ -135,7 +182,7 @@ void QueryTab::explainAnalyze() addLog("Explain clicked"); - //startTimer(); + m_stopwatch.start(); std::string cmd = "EXPLAIN (ANALYZE, VERBOSE, BUFFERS, FORMAT JSON) " + getCommand(); m_dbConnection.send(cmd, [this](std::shared_ptr res) @@ -169,6 +216,7 @@ void QueryTab::cancel() void QueryTab::setFileName(const QString &filename) { m_fileName = filename; + setTabCaption(m_fileName); } bool QueryTab::continueWithoutSavingWarning() @@ -183,15 +231,32 @@ bool QueryTab::continueWithoutSavingWarning() return ret == QMessageBox::Yes; } -void QueryTab::saveSqlTo(const QString &filename) +bool QueryTab::saveSqlTo(const QString &filename) { + bool result = false; QFile file(filename); - if (file.open(QIODevice::ReadWrite)) { + if (file.open(QIODevice::WriteOnly)) { QTextStream stream(&file); + stream.setCodec("utf-8"); QString text = ui->queryEdit->toPlainText(); stream << text; - m_queryTextChanged = false; +/* + + + 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; + result = true; + } } + return result; } QString QueryTab::promptUserForSaveSqlFilename() @@ -297,7 +362,7 @@ void QueryTab::startConnect() void QueryTab::explain_ready(ExplainRoot::SPtr explain) { -// endTimer(); + m_stopwatch.stop(); if (explain) { addLog("Explain ready"); QString times_str = QString("Execution time: %1, Planning time: %2") @@ -338,13 +403,30 @@ std::string QueryTab::getCommand() const return command.toUtf8().data(); } +void QueryTab::setTabCaption(const QString &caption) +{ + QWidget * w = parentWidget(); + QWidget * p = w->parentWidget(); + QTabWidget *tabwidget = dynamic_cast(p); + if (tabwidget) { + int i = tabwidget->indexOf(this); + if (i >= 0) { + tabwidget->setTabText(i, caption); + } + } + +} + void QueryTab::query_ready(std::shared_ptr dbres) { - //endTimer(); + m_stopwatch.stop(); if (dbres) { addLog("query_ready with result"); auto st = dbres->resultStatus(); 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)); ui->ResultView->setModel(resultModel.get()); ui->tabWidget->setCurrentWidget(ui->dataTab); @@ -355,7 +437,7 @@ void QueryTab::query_ready(std::shared_ptr dbres) // statusBar()->showMessage(tr("Command OK.")); QString msg = tr("Query returned succesfully: %1 rows affected, %2 execution time.") .arg(QString::number(dbres->tuplesAffected())) - .arg(0); //msfloatToHumanReadableString(elapsedTime.count())); + .arg(m_stopwatch.elapsed()); //msfloatToHumanReadableString(elapsedTime.count())); ui->messagesEdit->append(msg); ui->tabWidget->setCurrentWidget(ui->messageTab); @@ -398,3 +480,10 @@ void QueryTab::query_ready(std::shared_ptr dbres) // statusBar()->showMessage(tr("Query cancelled.")); } } + +void QueryTab::clearResult() +{ + ui->ResultView->setModel(nullptr); + resultModel.reset(); + ui->lblRowCount->clear(); +} diff --git a/querytab.h b/querytab.h index 8273bcb..a57c8a9 100644 --- a/querytab.h +++ b/querytab.h @@ -2,8 +2,9 @@ #define QUERYTAB_H #include "asyncdbconnection.h" -#include "QueryResultModel.h" -#include "QueryExplainModel.h" +#include "queryresultmodel.h" +#include "queryexplainmodel.h" +#include "stopwatch.h" #include #include @@ -29,7 +30,9 @@ public: void setConfig(const ConnectionConfig &config); - void open(); + void newdoc(); +// void open(); + bool load(const QString &filename); void save(); void saveAs(); void saveCopyAs(); @@ -37,18 +40,21 @@ public: void execute(); void explainAnalyze(); void cancel(); + + bool canClose(); private: Ui::QueryTab *ui; MainWindow *m_win; std::unique_ptr highlighter; ConnectionConfig m_config; + StopWatch m_stopwatch; QString m_fileName; ///< use setFileName function to set bool m_queryTextChanged = false; void setFileName(const QString &filename); bool continueWithoutSavingWarning(); - void saveSqlTo(const QString &filename); + bool saveSqlTo(const QString &filename); QString promptUserForSaveSqlFilename(); @@ -61,6 +67,9 @@ private: std::string getCommand() const; void explain_ready(ExplainRoot::SPtr explain); void query_ready(std::shared_ptr dbres); + + void setTabCaption(const QString &caption); + void clearResult(); private slots: void queryTextChanged(); diff --git a/querytab.ui b/querytab.ui index cbe5677..e8f75fe 100644 --- a/querytab.ui +++ b/querytab.ui @@ -37,7 +37,7 @@ - 0 + 1 @@ -69,20 +69,8 @@ Data - - - 2 - - - 2 - - - 2 - - - 2 - - + + @@ -110,6 +98,26 @@ + + + + + + + 0ms + + + + + + + TextLabel + + + + + + diff --git a/stopwatch.cpp b/stopwatch.cpp index d2d33b6..ab68712 100644 --- a/stopwatch.cpp +++ b/stopwatch.cpp @@ -1,16 +1,24 @@ #include "stopwatch.h" #include "util.h" +#include + StopWatch::StopWatch() - : m_elapsed(std::make_unique()) {} void StopWatch::start() { - m_elapsed->start(); - m_timer = std::make_unique(nullptr); - connect(m_timer.get(), SIGNAL(timeout()), this, SLOT(updateTimer())); - m_timer->start(18); + m_elapsed.start(); + connect(&m_timer, SIGNAL(timeout()), this, SLOT(updateTimer())); + m_timer.start(18); +} + +void StopWatch::stop() +{ + m_timeTaken = m_elapsed.elapsed(); + m_timer.stop(); + updateTimer(); + m_elapsed.invalidate(); } void StopWatch::updateTimer() @@ -19,20 +27,40 @@ void StopWatch::updateTimer() // std::chrono::duration diff = nu - m_startTime; // elapsedTime = diff; // 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) { - int interval = 18; - if (ms >= 10000) { - int rem = ms % 1000; - interval = 1000 - rem; + if (m_timer.isActive()) { + int interval; + if (ms >= 10000) { + int rem = ms % 1000; + interval = 1000 - rem; + } + else if (ms >= 1000) + interval = 100; + else + interval = 18; + + if (interval != m_timer.interval()) + m_timer.setInterval(interval); } - else if (ms >= 1000) { - interval = 100; - } - - m_timer->start(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; +} diff --git a/stopwatch.h b/stopwatch.h index 8506b18..91c61ce 100644 --- a/stopwatch.h +++ b/stopwatch.h @@ -3,7 +3,8 @@ #include #include -#include + +class QLabel; class StopWatch : public QObject { Q_OBJECT @@ -12,9 +13,14 @@ public: void start(); qint64 elapsed(); + void stop(); + + void setOutputLabel(QLabel *label); private: - std::unique_ptr m_elapsed = nullptr; ///< Keeps time - std::unique_ptr m_timer = nullptr; ///< triggers updates + QElapsedTimer m_elapsed; // = nullptr; ///< Keeps time + QTimer m_timer; ///< triggers updates + QLabel* m_output = nullptr; + qint64 m_timeTaken = 0LL; private slots: