#include "DatabaseWindow.h" #include "util.h" #include "OpenDatabase.h" #include "MasterController.h" #include "TaskExecutor.h" #include #include #include #include #include #include #include #include #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::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 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"); // } 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/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_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)); } // { // auto ca = makeContextAction(tr("Save SQL"), &QueryTool::save); // ca->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S)); // ca->setMenuLocation(MenuPath("File/Save")); // ca->setToolbarLocation(ToolbarLocation("main", "save")); // // how we tell the system we want this to become a menu button with this as it's default action // registerContextAction(ca); // } // { // auto ca = makeContextAction(tr("Save SQL as"), &QueryTool::saveAs); // ca->setMenuLocation(MenuPath("File/Save")); // ca->setToolbarLocation(ToolbarLocation("main", "save")); // // how we tell the system we want this to become a secondary action for the previous button? // registerContextAction(ca); // } // { // auto ca = makeContextAction(tr("Save copy of SQL as"), &QueryTool::saveCopyAs); // ca->setMenuLocation(MenuPath("File/Save")); // ca->setToolbarLocation(ToolbarLocation("main", "save")); // // how we tell the system we want this to become a secondary action for the previous button? // registerContextAction(ca); // } } void DatabaseWindow::initMenus() { auto seperator = new QAction(this); seperator->setSeparator(true); auto mb = new QMenuBar(this); menuFile = mb->addMenu(tr("File")); menuFile->addActions({ actionNewSql, actionOpenSql, seperator, actionInspectUserSchemas, actionInspectPgCatalog, actionInspectInformationSchema, seperator, actionClose }); menuHelp = mb->addMenu(tr("Help")); menuHelp->addActions({ seperator, actionAbout }); setMenuBar(mb); } void DatabaseWindow::on_actionClose_triggered() { m_tabWidget->tabCloseRequested(m_tabWidget->currentIndex()); } void DatabaseWindow::on_actionNewSql_triggered() { auto *ct = new QueryTool(m_database, this); addPage(ct, "query"); ct->newdoc(); } 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_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(m_database, this); addPage(ct, ""); if (!ct->load(file_name)) { // TODO load has failed remove widget or never add it? } } } 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_actionShow_connection_manager_triggered() { m_masterController->showConnectionManager(); } void DatabaseWindow::on_actionCopy_triggered() { // What should be copied? QWidget *w = QApplication::focusWidget(); QTableView *tv = dynamic_cast(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); } } }