#include "DatabaseWindow.h" #include "ui_DatabaseWindow.h" #include "util.h" #include "crud/CrudTab.h" #include "catalog/widgets/CatalogTablesPage.h" #include "OpenDatabase.h" #include "catalog/PgDatabaseCatalog.h" #include "ConnectionController.h" #include "MasterController.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "EditTableWidget.h" #include "CodeGenerator.h" #include "querytool/QueryTool.h" #include namespace pg = Pgsql; DatabaseWindow::DatabaseWindow(MasterController *master, QWidget *parent) : QMainWindow(parent) , ui(new Ui::DatabaseWindow) , m_masterController(master) { ui->setupUi(this); connect(ui->mainTabs, &QTabWidget::tabCloseRequested, this, &DatabaseWindow::mainTabCloseRequested); connect(ui->mainTabs, &QTabWidget::currentChanged, this, &DatabaseWindow::currentMainTabChanged); setAcceptDrops(true); } DatabaseWindow::~DatabaseWindow() { delete ui; } void DatabaseWindow::addPage(QWidget* page, QString caption) { ui->mainTabs->addTab(page, caption); ui->mainTabs->setCurrentWidget(page); } void DatabaseWindow::setTabCaptionForWidget(QWidget *widget, const QString &caption, const QString &hint) { auto index = ui->mainTabs->indexOf(widget); ui->mainTabs->setTabText(index, caption); ui->mainTabs->setTabToolTip(index, hint); } void DatabaseWindow::setTabIcon(QWidget *widget, const QString &iconname) { auto index = ui->mainTabs->indexOf(widget); auto n = ":/icons/16x16/" + iconname; ui->mainTabs->setTabIcon(index, QIcon(n)); } void DatabaseWindow::newCodeGenPage(QString query, std::shared_ptr dbres) { auto cgtab = new CodeGenerator(this); cgtab->Init(m_database->catalog(), query, dbres); addPage(cgtab, "Codegen"); } QueryTool *DatabaseWindow::GetActiveQueryTool() { auto widget = ui->mainTabs->currentWidget(); auto qt = dynamic_cast(widget); return qt; } CrudTab *DatabaseWindow::GetActiveCrud() { auto widget = ui->mainTabs->currentWidget(); auto ct = dynamic_cast(widget); return ct; } void DatabaseWindow::closeEvent(QCloseEvent *event) { for (int idx = 0; idx < ui->mainTabs->count(); ++idx) { if (!canCloseTab(idx)) { event->ignore(); return; } } } void DatabaseWindow::setConfig(const ConnectionConfig &config) { m_config = config; try { QString title = "pglab - "; title += m_config.name(); setWindowTitle(title); auto cfg = m_config; auto qthis = QPointer(this); QtConcurrent::run([cfg] { return OpenDatabase::createOpenDatabase(cfg); } ).then(qApp, [qthis](OpenDatabase::OpenDatabaseSPtr db) { if (qthis) qthis.data()->catalogLoaded(db); } ); } catch (std::runtime_error &ex) { QMessageBox::critical(this, "Error reading database", QString::fromUtf8(ex.what())); close(); } } void DatabaseWindow::newCreateTablePage() { auto w = new EditTableWidget(m_database, this); ui->mainTabs->addTab(w, "Create table"); } void DatabaseWindow::newCrudPage(Oid tableoid) { CrudTab *ct = new CrudTab(this, this); ct->addAction(ui->actionRefreshCrud); addPage(ct, "crud"); ct->setConfig(tableoid); } void DatabaseWindow::newCatalogInspectorPage(QString caption, NamespaceFilter filter) { if (!m_database) return; // would be better if we queued the operation for later auto ct = new CatalogInspector(m_database, this); ct->addAction(ui->actionRefreshCatalog); addPage(ct, caption); ct->setNamespaceFilter(filter); connect(ct->tablesPage(), &CatalogTablesPage::tableSelected, this, &DatabaseWindow::tableSelected); } void DatabaseWindow::newServerInspectorPage() { auto si = new ServerInspector(m_database, this); addPage(si, tr("Server")); } void DatabaseWindow::closeTab(int index) { if (index < 0) return; if (canCloseTab(index)) { QWidget *widget = ui->mainTabs->widget(index); ui->mainTabs->removeTab(index); delete widget; } } bool DatabaseWindow::canCloseTab(int index) const { QWidget *widget = ui->mainTabs->widget(index); auto mp = dynamic_cast(widget); if (mp) return mp->CanClose(true); return true; } void DatabaseWindow::openSqlFile(QString file_name) { if (!file_name.isEmpty()) { auto *ct = new QueryTool(this, this); if (ct->load(file_name)) { ct->addAction(ui->actionExecute_query); addPage(ct, ct->title()); } else delete ct; } } void DatabaseWindow::catalogLoaded(OpenDatabase::OpenDatabaseSPtr db) { try { m_database = db; on_actionNew_Query_triggered(); } catch (const OpenDatabaseException &ex) { QMessageBox::critical(this, "Error reading database", ex.text()); close(); } } void DatabaseWindow::tableSelected(Oid tableoid) { newCrudPage(tableoid); } void DatabaseWindow::InvokeCopyIfPresent(QWidget *w) { const QMetaObject *meta = w->metaObject(); int i = meta->indexOfMethod("copy()"); if (i != -1) { QMetaMethod method = meta->method(i); method.invoke(w, Qt::AutoConnection); } } void DatabaseWindow::mainTabCloseRequested(int index) { closeTab(index); } void DatabaseWindow::currentMainTabChanged(int) { auto widget = ui->mainTabs->currentWidget(); auto qt = dynamic_cast(widget); auto ct = dynamic_cast(widget); auto ci = dynamic_cast(widget); ui->menuQuery->menuAction()->setVisible(qt != nullptr); ui->menuCatalog->menuAction()->setVisible(ci != nullptr); ui->menuCRUD->menuAction()->setVisible(ct != nullptr); } void DatabaseWindow::setTitleForWidget(QWidget *widget, QString title, QString hint) { int i = ui->mainTabs->indexOf(widget); if (i >= 0) { ui->mainTabs->setTabText(i, title); ui->mainTabs->setTabToolTip(i, hint); } } void DatabaseWindow::setIconForWidget(QWidget *widget, QIcon icon) { int i = ui->mainTabs->indexOf(widget); if (i >= 0) ui->mainTabs->setTabIcon(i, icon); } std::shared_ptr DatabaseWindow::openDatabase() { return m_database; } void DatabaseWindow::showStatusBarMessage(QString message) { statusBar()->showMessage(message); } void DatabaseWindow::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasUrls()) event->acceptProposedAction(); } void DatabaseWindow::dropEvent(QDropEvent *event) { foreach (const QUrl &url, event->mimeData()->urls()) { QString file_name = url.toLocalFile(); qDebug() << "Dropped file:" << file_name; openSqlFile(file_name); } } 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_actionCancel_query_triggered() { CallOnActiveQueryTool(&QueryTool::cancel); } void DatabaseWindow::on_actionClose_triggered() { ui->mainTabs->tabCloseRequested(ui->mainTabs->currentIndex()); } void DatabaseWindow::on_actionCopy_triggered() { QWidget *w = QApplication::focusWidget(); if (w == nullptr) return; QTableView *tv = dynamic_cast(w); if (tv) copySelectionToClipboard(tv); else InvokeCopyIfPresent(w); } void DatabaseWindow::on_actionCopy_as_C_string_triggered() { CallOnActiveQueryTool(&QueryTool::copyQueryAsCString); } void DatabaseWindow::on_actionCopy_as_raw_C_string_triggered() { CallOnActiveQueryTool(&QueryTool::copyQueryAsRawCppString); } void DatabaseWindow::on_actionExecute_query_triggered() { CallOnActiveQueryTool(&QueryTool::execute); } void DatabaseWindow::on_actionExplain_triggered() { CallOnActiveQueryTool(&QueryTool::explain, false); } void DatabaseWindow::on_actionExplain_analyze_triggered() { CallOnActiveQueryTool(&QueryTool::explain, true); } void DatabaseWindow::on_actionExport_data_triggered() { CallOnActiveQueryTool(&QueryTool::exportData); } void DatabaseWindow::on_actionGenerate_code_triggered() { CallOnActiveQueryTool(&QueryTool::generateCode); } void DatabaseWindow::on_actionInspect_information_schema_triggered() { newCatalogInspectorPage("information_schema", NamespaceFilter::InformationSchema); } void DatabaseWindow::on_actionInspect_pg_catalog_triggered() { newCatalogInspectorPage("pg_catalog", NamespaceFilter::PgCatalog); } void DatabaseWindow::on_actionInspect_user_schemas_triggered() { newCatalogInspectorPage("Schema", NamespaceFilter::User); } void DatabaseWindow::on_actionInspect_server_triggered() { newServerInspectorPage(); } void DatabaseWindow::on_actionNew_Query_triggered() { auto *ct = new QueryTool(this, this); ct->addAction(ui->actionExecute_query); addPage(ct, "new"); ct->newdoc(); } void DatabaseWindow::on_actionOpen_Query_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)")); openSqlFile(file_name); } void DatabaseWindow::on_actionSave_Query_triggered() { CallOnActiveQueryTool(&QueryTool::save); } void DatabaseWindow::on_actionPaste_lang_string_triggered() { CallOnActiveQueryTool(&QueryTool::pasteLangString); } void DatabaseWindow::on_actionRefreshCatalog_triggered() { m_database->refresh(); } void DatabaseWindow::on_actionRefreshCrud_triggered() { CallOnActiveCrud(&CrudTab::refresh); } void DatabaseWindow::on_actionSave_query_as_triggered() { CallOnActiveQueryTool(&QueryTool::saveAs); } void DatabaseWindow::on_actionSave_copy_of_query_as_triggered() { CallOnActiveQueryTool(&QueryTool::saveCopyAs); } void DatabaseWindow::on_actionShow_connection_manager_triggered() { m_masterController->connectionController()->showConnectionManager(); }