Module can register action Window adds this action to its menu Clicking the menu item for the action has the expected result But menu structure still needs work (everything is now put into one dropdown menu)
480 lines
11 KiB
C++
480 lines
11 KiB
C++
#include "DatabaseWindow.h"
|
|
#include "ui_DatabaseWindow.h"
|
|
#include "TablesPage.h"
|
|
#include "FunctionsPage.h"
|
|
#include "SequencesPage.h"
|
|
|
|
#include <QStandardPaths>
|
|
#include <QFileDialog>
|
|
#include <QMessageBox>
|
|
#include <QTextTable>
|
|
#include <QElapsedTimer>
|
|
#include <algorithm>
|
|
#include <QCloseEvent>
|
|
#include <QMetaObject>
|
|
#include <QMetaMethod>
|
|
#include "QueryTab.h"
|
|
#include "util.h"
|
|
#include "plugin_support/PluginContentWidget.h"
|
|
#include "CodeGenerator.h"
|
|
#include "MasterController.h"
|
|
#include "ScopeGuard.h"
|
|
#include "EditTableWidget.h"
|
|
#include "plugin_support/PluginContentWidgetContextBase.h"
|
|
#include "TaskExecutor.h"
|
|
|
|
namespace pg = Pgsql;
|
|
|
|
namespace DatabaseWindow_details {
|
|
|
|
class DatabaseWindowContentContext: public PluginContentWidgetContextBase {
|
|
public:
|
|
explicit DatabaseWindowContentContext(DatabaseWindow *window)
|
|
: m_window(window)
|
|
{}
|
|
|
|
void setCaption(PluginContentWidget *content, const QString &caption, const QString &hint = {}) override
|
|
{
|
|
m_window->setTabCaptionForWidget(content, caption, hint);
|
|
}
|
|
|
|
void setIcon(PluginContentWidget *content, const QString &iconname) override
|
|
{
|
|
m_window->setTabIcon(content, iconname);
|
|
}
|
|
|
|
std::shared_ptr<OpenDatabase> getDatabase() override
|
|
{
|
|
return m_window->getDatabase();
|
|
}
|
|
|
|
void showStatusMessage(const QString &msg) override
|
|
{
|
|
m_window->statusBar()->showMessage(msg);
|
|
}
|
|
|
|
void addContentWidget(PluginContentWidget *widget) override
|
|
{
|
|
m_window->addPage(widget, "");
|
|
}
|
|
private:
|
|
DatabaseWindow *m_window;
|
|
};
|
|
|
|
}
|
|
using namespace DatabaseWindow_details;
|
|
|
|
|
|
LMainWindow::LMainWindow(QWidget *parent)
|
|
: QMainWindow(parent)
|
|
{
|
|
m_fileMenu = new QMenu("File T", this);
|
|
|
|
|
|
}
|
|
|
|
void LMainWindow::initModuleMenus()
|
|
{
|
|
menuBar()->addMenu(m_fileMenu);
|
|
addModuleMenuActions();
|
|
}
|
|
|
|
void LMainWindow::addModuleMenuActions()
|
|
{
|
|
auto reg = PluginRegister::getInstance();
|
|
auto mods = reg->modules();
|
|
for (auto && mod : mods) {
|
|
auto items = mod.second->menuActions();
|
|
for (auto && item : items) {
|
|
addMenuAction(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
void LMainWindow::addMenuAction(const MenuAction &ma)
|
|
{
|
|
qDebug() << "add action " << ma.text();
|
|
//auto ac =
|
|
m_fileMenu->addAction(ma.icon(), ma.text(),
|
|
[ma, this] ()
|
|
{
|
|
ma.perform(m_context);
|
|
},
|
|
ma.shortCut());
|
|
|
|
|
|
// auto ac = new QAction(this);
|
|
// ac->
|
|
|
|
|
|
}
|
|
|
|
DatabaseWindow::DatabaseWindow(MasterController *master, QWidget *parent)
|
|
: LMainWindow(parent)
|
|
, ui(new Ui::DatabaseWindow)
|
|
, m_masterController(master)
|
|
{
|
|
ui->setupUi(this);
|
|
ui->tabWidget->setDocumentMode(true);
|
|
|
|
m_context = new DatabaseWindowContentContext(this);
|
|
|
|
connect(&loadWatcher, &QFutureWatcher<LoadCatalog::Result>::finished,
|
|
this, &DatabaseWindow::catalogLoaded);
|
|
|
|
initModuleMenus();
|
|
}
|
|
|
|
DatabaseWindow::~DatabaseWindow()
|
|
{
|
|
delete m_context;
|
|
delete ui;
|
|
}
|
|
|
|
QueryTab* DatabaseWindow::newSqlPage()
|
|
{
|
|
QueryTab *qt = new QueryTab(m_context);
|
|
qt->newdoc();
|
|
qt->focusEditor();
|
|
addPage(qt, "Tab");
|
|
return qt;
|
|
}
|
|
|
|
void DatabaseWindow::newCreateTablePage()
|
|
{
|
|
auto w = new EditTableWidget(m_database, this);
|
|
ui->tabWidget->addTab(w, "Create table");
|
|
}
|
|
|
|
void DatabaseWindow::newCodeGenPage(QString query, std::shared_ptr<const Pgsql::Result> dbres)
|
|
{
|
|
auto cgtab = new CodeGenerator(m_context, this);
|
|
cgtab->Init(m_database->catalog(), query, dbres);
|
|
addPage(cgtab, "Codegen");
|
|
}
|
|
|
|
QueryTab *DatabaseWindow::GetActiveQueryTab()
|
|
{
|
|
QWidget *widget = ui->tabWidget->currentWidget();
|
|
QueryTab *qt = dynamic_cast<QueryTab*>(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::catalogLoaded()
|
|
{
|
|
try {
|
|
//SCOPE_EXIT { loadFuture = {}; };
|
|
m_database = loadWatcher.future().result();
|
|
|
|
auto tt = new TablesPage(m_context, this);
|
|
tt->setCatalog(m_database->catalog());
|
|
ui->tabWidget->addTab(tt, "Tables");
|
|
|
|
auto pg_cat_tables = new TablesPage(m_context, this);
|
|
pg_cat_tables->setNamespaceFilter(TablesTableModel::PgCatalog);
|
|
pg_cat_tables->setCatalog(m_database->catalog());
|
|
ui->tabWidget->addTab(pg_cat_tables, "pg_catalog");
|
|
|
|
auto info_schema_tables = new TablesPage(m_context, this);
|
|
info_schema_tables->setNamespaceFilter(TablesTableModel::InformationSchema);
|
|
info_schema_tables->setCatalog(m_database->catalog());
|
|
ui->tabWidget->addTab(info_schema_tables, "information_schema");
|
|
|
|
auto functions_page = new FunctionsPage(this);
|
|
functions_page->setCatalog(m_database->catalog());
|
|
ui->tabWidget->addTab(functions_page, "Functions");
|
|
|
|
auto sequences_page = new SequencesPage(this);
|
|
sequences_page->setCatalog(m_database->catalog());
|
|
ui->tabWidget->addTab(sequences_page, "Sequences");
|
|
|
|
newSqlPage();
|
|
newCreateTablePage();
|
|
} catch (std::runtime_error &ex) {
|
|
QMessageBox::critical(this, "Error reading database",
|
|
QString::fromUtf8(ex.what()));
|
|
|
|
close();
|
|
}
|
|
}
|
|
|
|
void DatabaseWindow::on_actionLoad_SQL_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()) {
|
|
QueryTab* qt = newSqlPage();
|
|
qt->load(file_name);
|
|
}
|
|
|
|
}
|
|
|
|
void DatabaseWindow::on_actionSave_SQL_triggered()
|
|
{
|
|
QueryTab *tab = GetActiveQueryTab();
|
|
if (tab) {
|
|
tab->save();
|
|
}
|
|
}
|
|
|
|
void DatabaseWindow::on_actionSave_SQL_as_triggered()
|
|
{
|
|
QueryTab *tab = GetActiveQueryTab();
|
|
if (tab) {
|
|
tab->saveAs();
|
|
}
|
|
|
|
}
|
|
|
|
void DatabaseWindow::on_actionSave_copy_of_SQL_as_triggered()
|
|
{
|
|
QueryTab *tab = GetActiveQueryTab();
|
|
if (tab) {
|
|
tab->saveCopyAs();
|
|
}
|
|
}
|
|
|
|
void DatabaseWindow::on_actionExport_data_triggered()
|
|
{
|
|
QueryTab *tab = GetActiveQueryTab();
|
|
if (tab) {
|
|
QString home_dir = QStandardPaths::locate(QStandardPaths::HomeLocation, "", QStandardPaths::LocateDirectory);
|
|
QString file_name = QFileDialog::getSaveFileName(this,
|
|
tr("Export data"), home_dir, tr("CSV file (*.csv)"));
|
|
|
|
tab->exportData(file_name);
|
|
}
|
|
}
|
|
|
|
void DatabaseWindow::on_actionClose_triggered()
|
|
{
|
|
//close();
|
|
on_tabWidget_tabCloseRequested(ui->tabWidget->currentIndex());
|
|
}
|
|
|
|
void DatabaseWindow::on_actionAbout_triggered()
|
|
{
|
|
QMessageBox::about(this, "pgLab 0.1", tr(
|
|
"Copyrights 2016-2018, 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::closeEvent(QCloseEvent* /*event*/)
|
|
{
|
|
// TODO collect which files need saving
|
|
// std::vector<QString> files_to_save;
|
|
// int n = ui->tabWidget->count();
|
|
// for (int i = 0; i < n; ++i) {
|
|
// QWidget *w = ui->tabWidget->widget(i);
|
|
// QueryTab *qt = dynamic_cast<QueryTab*>(w);
|
|
// if (qt) {
|
|
// if (qt->isChanged()) {
|
|
// files_to_save.push_back(qt->fileName());
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
// QString s;
|
|
// for (const auto& e : files_to_save) {
|
|
// s += e + "\n";
|
|
// }
|
|
|
|
// QMessageBox msgBox;
|
|
// msgBox.setIcon(QMessageBox::Warning);
|
|
// msgBox.setText("The following documents need to be saved");
|
|
// msgBox.setInformativeText(s);
|
|
// msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
|
|
// msgBox.setDefaultButton(QMessageBox::Cancel);
|
|
// //int ret =
|
|
// msgBox.exec();
|
|
|
|
|
|
}
|
|
|
|
void DatabaseWindow::showEvent(QShowEvent *event)
|
|
{
|
|
if (!event->spontaneous()) {
|
|
// m_queryTextChanged = false;
|
|
}
|
|
event->accept();
|
|
}
|
|
|
|
void DatabaseWindow::on_actionNew_SQL_triggered()
|
|
{
|
|
newSqlPage();
|
|
}
|
|
|
|
|
|
void DatabaseWindow::on_tabWidget_tabCloseRequested(int index)
|
|
{
|
|
QWidget *widget = ui->tabWidget->widget(index);
|
|
PluginContentWidget *plg_page = dynamic_cast<PluginContentWidget*>(widget);
|
|
if (plg_page) {
|
|
if (plg_page->canClose()) {
|
|
removePage(plg_page);
|
|
ui->tabWidget->removeTab(index);
|
|
}
|
|
}
|
|
else {
|
|
// old behaviour shouldn't be needed any more when all pages have been migrated
|
|
// to PlgPage
|
|
QueryTab *qt = dynamic_cast<QueryTab*>(widget);
|
|
if (qt && qt->canClose()) {
|
|
ui->tabWidget->removeTab(index);
|
|
}
|
|
else if (index > 0) {
|
|
ui->tabWidget->removeTab(index);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
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<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_actionCopy_as_C_string_triggered()
|
|
{
|
|
// Find which edit is active, copy the selected text or all text if no selection present
|
|
// Put quote's around each line and add escapes.
|
|
|
|
QueryTab *tab = GetActiveQueryTab();
|
|
if (tab) {
|
|
tab->copyQueryAsCString();
|
|
}
|
|
}
|
|
|
|
|
|
void DatabaseWindow::on_actionCopy_as_raw_Cpp_string_triggered()
|
|
{
|
|
QueryTab *tab = GetActiveQueryTab();
|
|
if (tab) {
|
|
tab->copyQueryAsRawCppString();
|
|
}
|
|
}
|
|
|
|
void DatabaseWindow::addToolBarButtonsForPage(PluginContentWidget *page)
|
|
{
|
|
std::vector<QAction*> actions = page->getToolbarActions();
|
|
QList<QAction*> list;
|
|
for (auto act : actions) {
|
|
list.append(act);
|
|
}
|
|
ui->mainToolBar->addActions(list);
|
|
}
|
|
|
|
void DatabaseWindow::removeToolBarButtonsForPage(PluginContentWidget *page)
|
|
{
|
|
std::vector<QAction*> actions = page->getToolbarActions();
|
|
for (auto act : actions) {
|
|
ui->mainToolBar->removeAction(act);
|
|
}
|
|
}
|
|
|
|
|
|
void DatabaseWindow::addPage(PluginContentWidget* page, QString caption)
|
|
{
|
|
ui->tabWidget->addTab(page, caption);
|
|
ui->tabWidget->setCurrentWidget(page);
|
|
|
|
//addToolBarButtonsForPage(page);
|
|
}
|
|
|
|
void DatabaseWindow::removePage(PluginContentWidget *)
|
|
{
|
|
|
|
}
|
|
|
|
void DatabaseWindow::on_tabWidget_currentChanged(int index)
|
|
{
|
|
// remove buttons of old page
|
|
if (m_previousPage) {
|
|
removeToolBarButtonsForPage(m_previousPage);
|
|
}
|
|
|
|
// add buttons of new page
|
|
PluginContentWidget * page = nullptr;
|
|
if (index >= 0) {
|
|
QWidget *widget = ui->tabWidget->widget(index);
|
|
page = dynamic_cast<PluginContentWidget*>(widget);
|
|
if (page) {
|
|
addToolBarButtonsForPage(page);
|
|
}
|
|
}
|
|
m_previousPage = page;
|
|
}
|
|
|
|
void DatabaseWindow::on_actionGenerate_code_triggered()
|
|
{
|
|
QueryTab *tab = GetActiveQueryTab();
|
|
if (tab) {
|
|
tab->generateCode();
|
|
}
|
|
|
|
}
|
|
|
|
void DatabaseWindow::setTabCaptionForWidget(QWidget *widget, const QString &caption, const QString &hint)
|
|
{
|
|
auto index = ui->tabWidget->indexOf(widget);
|
|
ui->tabWidget->setTabText(index, caption);
|
|
ui->tabWidget->setTabToolTip(index, hint);
|
|
}
|
|
|
|
void DatabaseWindow::setTabIcon(QWidget *widget, const QString &iconname)
|
|
{
|
|
auto index = ui->tabWidget->indexOf(widget);
|
|
auto n = ":/icons/16x16/" + iconname;
|
|
ui->tabWidget->setTabIcon(index, QIcon(n));
|
|
}
|