This way children do not need to include the full header to get access to some utility functions for changing the titles and icons of tabpages (and in fact do not need to know that there are tabs, could be something else)
517 lines
14 KiB
C++
517 lines
14 KiB
C++
#include "DatabaseWindow.h"
|
|
#include "util.h"
|
|
#include "OpenDatabase.h"
|
|
#include "MasterController.h"
|
|
#include "TaskExecutor.h"
|
|
#include <QAction>
|
|
#include <QApplication>
|
|
#include <QFileDialog>
|
|
#include <QMenuBar>
|
|
#include <QMessageBox>
|
|
#include <QMetaMethod>
|
|
#include <QStandardPaths>
|
|
#include <QStatusBar>
|
|
#include <QTableView>
|
|
|
|
#include "EditTableWidget.h"
|
|
#include "CatalogInspector.h"
|
|
#include "CodeGenerator.h"
|
|
#include "QueryTool.h"
|
|
|
|
namespace pg = Pgsql;
|
|
|
|
|
|
DatabaseWindow::DatabaseWindow(MasterController *master, QWidget *parent)
|
|
: QMainWindow(parent)
|
|
, m_masterController(master)
|
|
{
|
|
connect(&loadWatcher, &QFutureWatcher<LoadCatalog::Result>::finished,
|
|
this, &DatabaseWindow::catalogLoaded);
|
|
|
|
m_tabWidget = new QTabWidget(this);
|
|
setCentralWidget(m_tabWidget);
|
|
|
|
createActions();
|
|
initMenus();
|
|
|
|
QMetaObject::connectSlotsByName(this);
|
|
}
|
|
|
|
DatabaseWindow::~DatabaseWindow() = default;
|
|
|
|
void DatabaseWindow::addPage(QWidget* page, QString caption)
|
|
{
|
|
m_tabWidget->addTab(page, caption);
|
|
m_tabWidget->setCurrentWidget(page);
|
|
}
|
|
|
|
void DatabaseWindow::setTabCaptionForWidget(QWidget *widget, const QString &caption, const QString &hint)
|
|
{
|
|
auto index = m_tabWidget->indexOf(widget);
|
|
m_tabWidget->setTabText(index, caption);
|
|
m_tabWidget->setTabToolTip(index, hint);
|
|
}
|
|
|
|
void DatabaseWindow::setTabIcon(QWidget *widget, const QString &iconname)
|
|
{
|
|
auto index = m_tabWidget->indexOf(widget);
|
|
auto n = ":/icons/16x16/" + iconname;
|
|
m_tabWidget->setTabIcon(index, QIcon(n));
|
|
}
|
|
|
|
void DatabaseWindow::newCreateTablePage()
|
|
{
|
|
auto w = new EditTableWidget(m_database, this);
|
|
m_tabWidget->addTab(w, "Create table");
|
|
}
|
|
|
|
void DatabaseWindow::newCodeGenPage(QString query, std::shared_ptr<const Pgsql::Result> dbres)
|
|
{
|
|
// TODO should this call be this direct or should it go through module system
|
|
// yes it should otherwise context cannot properly setup toolbar and menu!!!
|
|
// auto cgtab = new CodeGenerator(context(), pluginModule(), this);
|
|
// cgtab->Init(m_database->catalog(), query, dbres);
|
|
// addPage(cgtab, "Codegen");
|
|
//
|
|
}
|
|
|
|
QueryTool *DatabaseWindow::GetActiveQueryTool()
|
|
{
|
|
auto widget = m_tabWidget->currentWidget();
|
|
auto qt = dynamic_cast<QueryTool*>(widget);
|
|
return qt;
|
|
}
|
|
|
|
void DatabaseWindow::setConfig(const ConnectionConfig &config)
|
|
{
|
|
m_config = config;
|
|
try {
|
|
QString title = "pglab - ";
|
|
title += m_config.name().c_str();
|
|
setWindowTitle(title);
|
|
|
|
auto f = TaskExecutor::run(new LoadCatalog(m_config));
|
|
loadWatcher.setFuture(f);
|
|
|
|
} catch (std::runtime_error &ex) {
|
|
QMessageBox::critical(this, "Error reading database",
|
|
QString::fromUtf8(ex.what()));
|
|
|
|
close();
|
|
}
|
|
}
|
|
|
|
|
|
void DatabaseWindow::createActions()
|
|
{
|
|
{
|
|
QIcon icon;
|
|
icon.addFile(QString::fromUtf8(":/icons/about.png"), QSize(), QIcon::Normal, QIcon::On);
|
|
auto action = actionAbout = new QAction(icon, tr("About"), this);
|
|
action->setObjectName("actionAbout");
|
|
}
|
|
{
|
|
QIcon icon;
|
|
icon.addFile(QString::fromUtf8(":/icons/script_delete.png"), QSize(), QIcon::Normal, QIcon::On);
|
|
auto action = actionCancelQuery = new QAction(icon, tr("Cancel query"), this);
|
|
action->setObjectName("actionCancelQuery");
|
|
}
|
|
{
|
|
QIcon icon;
|
|
icon.addFile(QString::fromUtf8(":/icons/page_white_delete.png"), QSize(), QIcon::Normal, QIcon::On);
|
|
auto action = actionClose = new QAction(icon, tr("Close"), this);
|
|
action->setObjectName("actionClose");
|
|
action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_W));
|
|
}
|
|
{
|
|
QIcon icon;
|
|
icon.addFile(QString::fromUtf8(":/icons/page_white_copy.png"), QSize(), QIcon::Normal, QIcon::On);
|
|
auto action = actionCopy = new QAction(icon, tr("Copy"), this);
|
|
action->setObjectName("actionCopy");
|
|
action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_C));
|
|
}
|
|
{
|
|
QIcon icon;
|
|
icon.addFile(QString::fromUtf8(":/icons/token_shortland_character.png"), QSize(), QIcon::Normal, QIcon::On);
|
|
auto action = actionCopyAsCString = new QAction(icon, tr("Copy as C string"), this);
|
|
action->setObjectName("actionCopyAsCString");
|
|
action->setShortcut(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_C));
|
|
}
|
|
{
|
|
QIcon icon;
|
|
icon.addFile(QString::fromUtf8(":/icons/token_shortland_character.png"), QSize(), QIcon::Normal, QIcon::On);
|
|
auto action = actionCopyAsRawCppString = new QAction(icon, tr("Copy as raw C++-string"), this);
|
|
action->setObjectName("actionCopyAsRawCppString");
|
|
action->setShortcut(QKeySequence(Qt::CTRL + Qt::ALT + Qt::Key_C));
|
|
}
|
|
{
|
|
QIcon icon;
|
|
icon.addFile(QString::fromUtf8(":/icons/script_go.png"), QSize(), QIcon::Normal, QIcon::On);
|
|
auto action = actionExecuteQuery = new QAction(icon, tr("Execute query"), this);
|
|
action->setObjectName("actionExecuteQuery");
|
|
action->setShortcut(QKeySequence(Qt::Key_F5));
|
|
}
|
|
{
|
|
QIcon icon;
|
|
icon.addFile(QString::fromUtf8(":/icons/lightbulb_off.png"), QSize(), QIcon::Normal, QIcon::On);
|
|
auto action = actionExplain = new QAction(icon, tr("Explain"), this);
|
|
action->setObjectName("actionExplain");
|
|
action->setShortcut(QKeySequence(Qt::Key_F7));
|
|
}
|
|
{
|
|
QIcon icon;
|
|
icon.addFile(QString::fromUtf8(":/icons/lightbulb.png"), QSize(), QIcon::Normal, QIcon::On);
|
|
auto action = actionExplainAnalyze = new QAction(icon, tr("Explain analyze"), this);
|
|
action->setObjectName("actionExplainAnalyze");
|
|
action->setShortcut(QKeySequence(Qt::SHIFT + Qt::Key_F7));
|
|
}
|
|
{
|
|
QIcon icon;
|
|
icon.addFile(QString::fromUtf8(":/icons/table_save.png"), QSize(), QIcon::Normal, QIcon::On);
|
|
auto action = actionExportData = new QAction(icon, tr("Export data"), this);
|
|
action->setObjectName("actionExportData");
|
|
}
|
|
{
|
|
auto action = actionGenerateCode = new QAction(tr("Generate code"), this);
|
|
action->setObjectName("actionGenerateCode");
|
|
}
|
|
{
|
|
QIcon icon;
|
|
icon.addFile(QString::fromUtf8(":/icons/page_white_add.png"), QSize(), QIcon::Normal, QIcon::On);
|
|
auto action = actionInspectInformationSchema = new QAction(icon, tr("Inspect information_schema"), this);
|
|
action->setObjectName("actionInspectInformationSchema");
|
|
}
|
|
{
|
|
QIcon icon;
|
|
icon.addFile(QString::fromUtf8(":/icons/page_white_add.png"), QSize(), QIcon::Normal, QIcon::On);
|
|
auto action = actionInspectPgCatalog = new QAction(icon, tr("Inspect pg_catalog"), this);
|
|
action->setObjectName("actionInspectPgCatalog");
|
|
}
|
|
{
|
|
QIcon icon;
|
|
icon.addFile(QString::fromUtf8(":/icons/page_white_add.png"), QSize(), QIcon::Normal, QIcon::On);
|
|
auto action = actionInspectUserSchemas = new QAction(icon, tr("Inspect user schemas"), this);
|
|
action->setObjectName("actionInspectUserSchemas");
|
|
}
|
|
{
|
|
QIcon icon;
|
|
icon.addFile(QString::fromUtf8(":/icons/new_query_tab.png"), QSize(), QIcon::Normal, QIcon::On);
|
|
auto action = actionNewSql = new QAction(icon, tr("New Query"), this);
|
|
action->setObjectName("actionNewSql");
|
|
action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_N));
|
|
}
|
|
{
|
|
QIcon icon;
|
|
icon.addFile(QString::fromUtf8(":/icons/folder.png"), QSize(), QIcon::Normal, QIcon::On);
|
|
auto action = actionOpenSql = new QAction(icon, tr("Open Query"), this);
|
|
action->setObjectName("actionOpenSql");
|
|
action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_O));
|
|
}
|
|
{
|
|
QIcon icon;
|
|
icon.addFile(QString::fromUtf8(":/icons/script_save.png"), QSize(), QIcon::Normal, QIcon::On);
|
|
auto action = actionSaveSql = new QAction(icon, tr("Save query"), this);
|
|
action->setObjectName("actionSaveSql");
|
|
action->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S));
|
|
}
|
|
{
|
|
auto action = actionSaveSqlAs = new QAction(tr("Save query as"), this);
|
|
action->setObjectName("actionSaveSqlAs");
|
|
}
|
|
{
|
|
auto action = actionSaveCopyOfSqlAs = new QAction(tr("Save copy of query as"), this);
|
|
action->setObjectName("actionSaveCopyOfSqlAs");
|
|
}
|
|
{
|
|
auto action = actionShowConnectionManager = new QAction(tr("Show connection manager"), this);
|
|
action->setObjectName("actionShowConnectionManager");
|
|
}
|
|
}
|
|
|
|
|
|
void DatabaseWindow::initMenus()
|
|
{
|
|
auto mb = new QMenuBar(this);
|
|
menuFile = mb->addMenu(tr("File"));
|
|
menuFile->addActions({
|
|
actionNewSql,
|
|
actionOpenSql,
|
|
seperator(),
|
|
actionSaveSql,
|
|
actionSaveSqlAs,
|
|
actionSaveCopyOfSqlAs,
|
|
seperator(),
|
|
actionExportData,
|
|
seperator(),
|
|
actionClose
|
|
});
|
|
|
|
menuEdit = mb->addMenu(tr("Edit"));
|
|
menuEdit->addActions({
|
|
actionCopy,
|
|
actionCopyAsCString,
|
|
actionCopyAsRawCppString,
|
|
actionGenerateCode
|
|
});
|
|
|
|
menuQuery = mb->addMenu(tr("Query"));
|
|
menuQuery->addActions({
|
|
actionExecuteQuery,
|
|
actionExplain,
|
|
actionExplainAnalyze,
|
|
actionCancelQuery
|
|
});
|
|
|
|
menuWindow = mb->addMenu(tr("Window"));
|
|
menuWindow->addActions({
|
|
actionInspectUserSchemas,
|
|
actionInspectPgCatalog,
|
|
actionInspectInformationSchema,
|
|
seperator(),
|
|
actionShowConnectionManager
|
|
});
|
|
|
|
|
|
menuHelp = mb->addMenu(tr("Help"));
|
|
menuHelp->addActions({
|
|
seperator(),
|
|
actionAbout
|
|
});
|
|
|
|
setMenuBar(mb);
|
|
}
|
|
|
|
QAction *DatabaseWindow::seperator()
|
|
{
|
|
auto ac = new QAction(this);
|
|
ac->setSeparator(true);
|
|
return ac;
|
|
}
|
|
|
|
|
|
|
|
void DatabaseWindow::catalogLoaded()
|
|
{
|
|
try {
|
|
m_database = loadWatcher.future().result();
|
|
|
|
for (auto f : { "user", "pg_catalog", "information_schema" }) {
|
|
// TODO open inspector windows
|
|
}
|
|
|
|
|
|
newCreateTablePage();
|
|
} catch (const OpenDatabaseException &ex) {
|
|
QMessageBox::critical(this, "Error reading database", ex.text());
|
|
close();
|
|
}
|
|
}
|
|
|
|
|
|
void DatabaseWindow::on_actionAbout_triggered()
|
|
{
|
|
QMessageBox::about(this, "pgLab 0.1", tr(
|
|
"Copyrights 2016-2019, Eelke Klein, All Rights Reserved.\n"
|
|
"\n"
|
|
"The program is provided AS IS with NO WARRANTY OF ANY KIND, "
|
|
"INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS "
|
|
"FOR A PARTICULAR PURPOSE.\n"
|
|
"\n"
|
|
"This program is dynamically linked with Qt 5.12 Copyright (C) 2018 "
|
|
"The Qt Company Ltd. https://www.qt.io/licensing/. \n"
|
|
"\n"
|
|
"Icons by fatcow http://www.fatcow.com/free-icons provided under Creative Commons "
|
|
"attribution 3.0 license."
|
|
));
|
|
|
|
}
|
|
|
|
void DatabaseWindow::on_actionCancelQuery_triggered()
|
|
{
|
|
auto query_tool = GetActiveQueryTool();
|
|
if (query_tool) {
|
|
query_tool->cancel();
|
|
}
|
|
}
|
|
|
|
void DatabaseWindow::on_actionCopy_triggered()
|
|
{
|
|
QWidget *w = QApplication::focusWidget();
|
|
QTableView *tv = dynamic_cast<QTableView*>(w);
|
|
if (tv) {
|
|
copySelectionToClipboard(tv);
|
|
}
|
|
else {
|
|
const QMetaObject *meta = w->metaObject();
|
|
int i = meta->indexOfSlot("copy");
|
|
if (i != -1) {
|
|
QMetaMethod method = meta->method(i);
|
|
method.invoke(w, Qt::AutoConnection);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DatabaseWindow::on_actionCopyAsCString_triggered()
|
|
{
|
|
auto query_tool = GetActiveQueryTool();
|
|
if (query_tool) {
|
|
query_tool->copyQueryAsCString();
|
|
}
|
|
}
|
|
|
|
void DatabaseWindow::on_actionCopyAsRawCppString_triggered()
|
|
{
|
|
auto query_tool = GetActiveQueryTool();
|
|
if (query_tool) {
|
|
query_tool->copyQueryAsRawCppString();
|
|
}
|
|
}
|
|
|
|
void DatabaseWindow::on_actionExecuteQuery_triggered()
|
|
{
|
|
auto query_tool = GetActiveQueryTool();
|
|
if (query_tool) {
|
|
query_tool->execute();
|
|
}
|
|
}
|
|
|
|
void DatabaseWindow::on_actionExplain_triggered()
|
|
{
|
|
auto query_tool = GetActiveQueryTool();
|
|
if (query_tool) {
|
|
query_tool->explain(false);
|
|
}
|
|
}
|
|
|
|
void DatabaseWindow::on_actionExplainAnalyze_triggered()
|
|
{
|
|
auto query_tool = GetActiveQueryTool();
|
|
if (query_tool) {
|
|
query_tool->explain(true);
|
|
}
|
|
}
|
|
|
|
void DatabaseWindow::on_actionExportData_triggered()
|
|
{
|
|
auto query_tool = GetActiveQueryTool();
|
|
if (query_tool) {
|
|
query_tool->exportData();
|
|
}
|
|
}
|
|
|
|
void DatabaseWindow::on_actionGenerateCode_triggered()
|
|
{
|
|
auto query_tool = GetActiveQueryTool();
|
|
if (query_tool) {
|
|
query_tool->generateCode();
|
|
}
|
|
}
|
|
|
|
void DatabaseWindow::on_actionClose_triggered()
|
|
{
|
|
m_tabWidget->tabCloseRequested(m_tabWidget->currentIndex());
|
|
}
|
|
|
|
void DatabaseWindow::on_actionInspectInformationSchema_triggered()
|
|
{
|
|
auto ct = new CatalogInspector(m_database, this);
|
|
addPage(ct, "information_schema");
|
|
ct->setNamespaceFilter(NamespaceFilter::InformationSchema);
|
|
}
|
|
|
|
void DatabaseWindow::on_actionInspectPgCatalog_triggered()
|
|
{
|
|
auto ct = new CatalogInspector(m_database, this);
|
|
addPage(ct, "pg_catalog");
|
|
ct->setNamespaceFilter(NamespaceFilter::PgCatalog);
|
|
}
|
|
|
|
void DatabaseWindow::on_actionInspectUserSchemas_triggered()
|
|
{
|
|
auto ct = new CatalogInspector(m_database, this);
|
|
addPage(ct, "Schema");
|
|
ct->setNamespaceFilter(NamespaceFilter::User);
|
|
}
|
|
|
|
void DatabaseWindow::on_actionNewSql_triggered()
|
|
{
|
|
auto *ct = new QueryTool(this, this);
|
|
addPage(ct, "query");
|
|
ct->newdoc();
|
|
}
|
|
|
|
void DatabaseWindow::on_actionOpenSql_triggered()
|
|
{
|
|
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()) {
|
|
auto *ct = new QueryTool(this, this);
|
|
if (ct->load(file_name)) {
|
|
addPage(ct, "");
|
|
}
|
|
else {
|
|
delete ct;
|
|
}
|
|
}
|
|
}
|
|
|
|
void DatabaseWindow::on_actionSaveSql_triggered()
|
|
{
|
|
auto query_tool = GetActiveQueryTool();
|
|
if (query_tool) {
|
|
query_tool->save();
|
|
}
|
|
}
|
|
|
|
void DatabaseWindow::on_actionSaveSqlAs_triggered()
|
|
{
|
|
auto query_tool = GetActiveQueryTool();
|
|
if (query_tool) {
|
|
query_tool->saveAs();
|
|
}
|
|
}
|
|
|
|
void DatabaseWindow::on_actionSaveCopyOfSqlAs_triggered()
|
|
{
|
|
auto query_tool = GetActiveQueryTool();
|
|
if (query_tool) {
|
|
query_tool->saveCopyAs();
|
|
}
|
|
}
|
|
|
|
void DatabaseWindow::on_actionShowConnectionManager_triggered()
|
|
{
|
|
m_masterController->showConnectionManager();
|
|
}
|
|
|
|
|
|
|
|
void DatabaseWindow::setTitleForWidget(QWidget *widget, QString title, QString hint)
|
|
{
|
|
int i = m_tabWidget->indexOf(widget);
|
|
if (i >= 0) {
|
|
m_tabWidget->setTabText(i, title);
|
|
m_tabWidget->setTabToolTip(i, hint);
|
|
}
|
|
}
|
|
|
|
void DatabaseWindow::setIconForWidget(QWidget *widget, QIcon icon)
|
|
{
|
|
int i = m_tabWidget->indexOf(widget);
|
|
if (i >= 0) {
|
|
m_tabWidget->setTabIcon(i, icon);
|
|
}
|
|
}
|
|
|
|
|
|
std::shared_ptr<OpenDatabase> DatabaseWindow::openDatabase()
|
|
{
|
|
return m_database;
|
|
}
|
|
|
|
|
|
void DatabaseWindow::showStatusBarMessage(QString message)
|
|
{
|
|
statusBar()->showMessage(message);
|
|
}
|