diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 4e0ab1d3..a2f18ab7 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -26,6 +26,7 @@ #include "RunSql.h" #include "ExtendedTableWidget.h" #include "Data.h" +#include "TableBrowser.h" #include #include @@ -119,34 +120,22 @@ void MainWindow::init() connect(&db, &DBBrowserDB::sqlExecuted, this, &MainWindow::logSql, Qt::QueuedConnection); connect(&db, &DBBrowserDB::requestCollation, this, &MainWindow::requestCollation); - // Initialise table browser first - ui->tableBrowser->init(&db); - - // Set project modified flag when the settings in the table browser were changed - connect(ui->tableBrowser, &TableBrowser::projectModified, this, [this]() { - isProjectModified = true; - }); - - connect(ui->tableBrowser->model(), &SqliteTableModel::dataChanged, this, &MainWindow::dataTableSelectionChanged); - connect(ui->tableBrowser, &TableBrowser::selectionChanged, this, &MainWindow::dataTableSelectionChanged); - connect(ui->tableBrowser, &TableBrowser::selectionChangedByDoubleClick, this, &MainWindow::doubleClickTable); - connect(ui->tableBrowser, &TableBrowser::updatePlot, this, &MainWindow::attachPlot); - connect(ui->tableBrowser, &TableBrowser::createView, this, &MainWindow::saveAsView); - connect(ui->tableBrowser, &TableBrowser::requestFileOpen, this, [this](const QString& file) { - fileOpen(file); - }); - connect(ui->tableBrowser, &TableBrowser::statusMessageRequested, ui->statusbar, [this](const QString& message) { - ui->statusbar->showMessage(message); - }); - - m_currentTabTableModel = ui->tableBrowser->model(); - // Set up DB structure tab dbStructureModel = new DbStructureModel(db, this); connect(&db, &DBBrowserDB::structureUpdated, this, [this]() { - sqlb::ObjectIdentifier old_table = ui->tableBrowser->currentlyBrowsedTableName(); + std::vector old_tables; + for(int i=0;itabBrowsers->count();i++) + { + TableBrowser* w = qobject_cast(ui->tabBrowsers->widget(i)); + if(w) + old_tables.push_back(w->currentlyBrowsedTableName()); + else + old_tables.push_back(sqlb::ObjectIdentifier{}); + } + dbStructureModel->reloadData(); - populateStructure(old_table); + + populateStructure(old_tables); }); ui->dbTreeWidget->setModel(dbStructureModel); ui->dbTreeWidget->setColumnWidth(DbStructureModel::ColumnName, 300); @@ -158,8 +147,8 @@ void MainWindow::init() ui->treeSchemaDock->setColumnHidden(DbStructureModel::ColumnObjectType, true); ui->treeSchemaDock->setColumnHidden(DbStructureModel::ColumnSchema, true); - // Set up the table combo box in the Browse Data tab - ui->tableBrowser->setStructure(dbStructureModel); + // Create initial table browser tab + newTableBrowserTab(); // Create docks ui->dockEdit->setWidget(editDock); @@ -433,11 +422,6 @@ void MainWindow::init() ui->actionDropQualifiedCheck->setChecked(Settings::getValue("SchemaDock", "dropQualifiedNames").toBool()); ui->actionEnquoteNamesCheck->setChecked(Settings::getValue("SchemaDock", "dropEnquotedNames").toBool()); - connect(ui->tableBrowser->model(), &SqliteTableModel::finishedFetch, [this](){ - auto& settings = ui->tableBrowser->settings(ui->tableBrowser->currentlyBrowsedTableName()); - plotDock->updatePlot(ui->tableBrowser->model(), &settings, true, false); - }); - connect(ui->actionSqlStop, &QAction::triggered, [this]() { if(execute_sql_worker && execute_sql_worker->isRunning()) execute_sql_worker->stop(); @@ -612,7 +596,7 @@ void MainWindow::fileNewInMemoryDatabase() createTable(); } -void MainWindow::populateStructure(const sqlb::ObjectIdentifier& old_table) +void MainWindow::populateStructure(const std::vector& old_tables) { // Refresh the structure tab ui->dbTreeWidget->setRootIndex(dbStructureModel->index(1, 0)); // Show the 'All' part of the db structure @@ -620,8 +604,13 @@ void MainWindow::populateStructure(const sqlb::ObjectIdentifier& old_table) ui->treeSchemaDock->setRootIndex(dbStructureModel->index(1, 0)); // Show the 'All' part of the db structure ui->treeSchemaDock->expandToDepth(0); - // Refresh the browse data tab - ui->tableBrowser->setStructure(dbStructureModel, old_table); + // Refresh the browse data tabs + for(int i=0;itabBrowsers->count()&&static_cast(i)(ui->tabBrowsers->widget(i)); + if(w) + w->setStructure(dbStructureModel, old_tables.at(static_cast(i))); + } // Cancel here if no database is opened if(!db.isOpen()) @@ -670,7 +659,9 @@ void MainWindow::populateTable() return; QApplication::setOverrideCursor(Qt::WaitCursor); - ui->tableBrowser->updateTable(); + TableBrowser* w = qobject_cast(ui->tabBrowsers->currentWidget()); + if(w) + w->updateTable(); QApplication::restoreOverrideCursor(); } @@ -693,13 +684,19 @@ bool MainWindow::fileClose() if(!db.close()) return false; + TableBrowser::resetSharedSettings(); setCurrentFile(QString()); loadPragmas(); statusEncryptionLabel->setVisible(false); statusReadOnlyLabel->setVisible(false); // Reset the table browser of the Browse Data tab - ui->tableBrowser->reset(); + while(ui->tabBrowsers->count()) + closeTableBrowserTab(0, true); + newTableBrowserTab(true); + TableBrowser* w = qobject_cast(ui->tabBrowsers->currentWidget()); + if(w) + w->setEnabled(false); // Clear edit dock editDock->setCurrentIndex(QModelIndex()); @@ -934,7 +931,9 @@ void MainWindow::editObject() db.setPragma("foreign_keys", foreign_keys); } if(ok) { - ui->tableBrowser->clearFilters(); + TableBrowser* w = qobject_cast(ui->tabBrowsers->currentWidget()); + if(w) + w->clearFilters(); populateTable(); } } else if(type == "index") { @@ -976,13 +975,17 @@ void MainWindow::toggleEditDock(bool visible) { if (!visible) { // Update main window - ui->tableBrowser->setFocus(); + ui->tabBrowsers->setFocus(); } else { // fill edit dock with actual data, when the current index has changed while the dock was invisible. // (note that this signal is also emitted when the widget is docked or undocked, so we have to avoid // reloading data when the user is editing and (un)docks the editor). - if (editDock->currentIndex() != ui->tableBrowser->currentIndex()) - editDock->setCurrentIndex(ui->tableBrowser->currentIndex()); + TableBrowser* w = qobject_cast(ui->tabBrowsers->currentWidget()); + if(w) + { + if (editDock->currentIndex() != w->currentIndex()) + editDock->setCurrentIndex(w->currentIndex()); + } } } @@ -994,8 +997,10 @@ void MainWindow::doubleClickTable(const QModelIndex& index) } // * Don't allow editing of other objects than tables and editable views - bool isEditingAllowed = !db.readOnly() && m_currentTabTableModel == ui->tableBrowser->model() && - ui->tableBrowser->model()->isEditable(index); + bool isEditingAllowed = !db.readOnly(); + TableBrowser* w = qobject_cast(ui->tabBrowsers->currentWidget()); + if(w) + isEditingAllowed = isEditingAllowed && m_currentTabTableModel == w->model() && w->model()->isEditable(index); // Enable or disable the Apply, Null, & Import buttons in the Edit Cell // dock depending on the value of the "isEditingAllowed" bool above @@ -1018,8 +1023,10 @@ void MainWindow::dataTableSelectionChanged(const QModelIndex& index) return; } - bool editingAllowed = !db.readOnly() && (m_currentTabTableModel == ui->tableBrowser->model()) && - ui->tableBrowser->model()->isEditable(index); + bool editingAllowed = !db.readOnly(); + TableBrowser* w = qobject_cast(ui->tabBrowsers->currentWidget()); + if(w) + editingAllowed = editingAllowed && m_currentTabTableModel == w->model() && w->model()->isEditable(index); // Don't allow editing of other objects than tables and editable views editDock->setReadOnly(!editingAllowed); @@ -1282,7 +1289,9 @@ void MainWindow::mainTabSelected(int /*tabindex*/) if(ui->mainTab->currentWidget() == ui->browser) { - m_currentTabTableModel = ui->tableBrowser->model(); + TableBrowser* w = qobject_cast(ui->tabBrowsers->currentWidget()); + if(w) + m_currentTabTableModel = w->model(); populateTable(); } else if(ui->mainTab->currentWidget() == ui->pragmas) { loadPragmas(); @@ -1341,7 +1350,7 @@ void MainWindow::exportTableToCSV() current_table = sqlb::ObjectIdentifier(schema.toStdString(), name.toStdString()); } } else if(ui->mainTab->currentWidget() == ui->browser) { - current_table = ui->tableBrowser->currentlyBrowsedTableName(); + current_table = currentlyBrowsedTableName(); } // Open dialog @@ -1363,7 +1372,7 @@ void MainWindow::exportTableToJson() current_table = sqlb::ObjectIdentifier(schema.toStdString(), name.toStdString()); } } else if(ui->mainTab->currentWidget() == ui->browser) { - current_table = ui->tableBrowser->currentlyBrowsedTableName(); + current_table = currentlyBrowsedTableName(); } // Open dialog @@ -1406,7 +1415,7 @@ void MainWindow::exportDatabaseToSQL() { QString current_table; if(ui->mainTab->currentWidget() == ui->browser) - current_table = QString::fromStdString(ui->tableBrowser->currentlyBrowsedTableName().name()); + current_table = QString::fromStdString(currentlyBrowsedTableName().name()); ExportSqlDialog dialog(&db, this, current_table); dialog.exec(); @@ -1752,7 +1761,6 @@ void MainWindow::activateFields(bool enable) bool write = !db.readOnly(); bool tempDb = db.currentFile() == ":memory:"; - ui->tableBrowser->setEnabled(enable); ui->fileCloseAction->setEnabled(enable); ui->fileAttachAction->setEnabled(enable); ui->fileCompactAction->setEnabled(enable && write); @@ -1783,11 +1791,20 @@ void MainWindow::activateFields(bool enable) ui->actionSqlResultsSave->setEnabled(false); remoteDock->enableButtons(); + + for(int i=0;itabBrowsers->count();i++) + { + TableBrowser* w = qobject_cast(ui->tabBrowsers->currentWidget()); + if(w) + w->setEnabled(enable); + } } void MainWindow::resizeEvent(QResizeEvent*) { - ui->tableBrowser->updateRecordsetLabel(); + TableBrowser* w = qobject_cast(ui->tabBrowsers->currentWidget()); + if(w) + w->updateRecordsetLabel(); } void MainWindow::loadPragmas() @@ -2130,7 +2147,12 @@ void MainWindow::reloadSettings() qobject_cast(qApp)->reloadSettings(); // Set data browser font - ui->tableBrowser->reloadSettings(); + for(int i=0;itabBrowsers->count();i++) + { + TableBrowser* w = qobject_cast(ui->tabBrowsers->widget(i)); + if(w) + w->reloadSettings(); + } switch (static_cast(Settings::getValue("General", "appStyle").toInt())) { case Settings::FollowDesktopStyle : @@ -2198,6 +2220,7 @@ void MainWindow::reloadSettings() sqlb::setIdentifierQuoting(static_cast(Settings::getValue("editor", "identifier_quotes").toInt())); ui->tabSqlAreas->setTabsClosable(Settings::getValue("editor", "close_button_on_tabs").toBool()); + ui->tabBrowsers->setTabsClosable(Settings::getValue("editor", "close_button_on_tabs").toBool()); } void MainWindow::checkNewVersion(const QString& versionstring, const QString& url) @@ -2488,7 +2511,6 @@ bool MainWindow::loadProject(QString filename, bool readOnly) addToRecentFilesMenu(filename, readOnly); currentProjectFilename = filename; - QString currentTable; while(!xml.atEnd() && !xml.hasError()) { // Read next token @@ -2574,17 +2596,68 @@ bool MainWindow::loadProject(QString filename, bool readOnly) } } } else if(xml.name() == "tab_browse") { + // Close all open tabs first + for(int i=ui->tabBrowsers->count()-1;i>=0;i--) + closeTableBrowserTab(i, true); + // Browse Data tab settings while(xml.readNext() != QXmlStreamReader::EndElement && xml.name() != "tab_browse") { if(xml.name() == "current_table") { + // TODO This attribute was only created until version 3.12.0 which means we can remove support for this + // in the future. + // Currently selected table - currentTable = xml.attributes().value("name").toString(); + QString table_name = xml.attributes().value("name").toString(); + sqlb::ObjectIdentifier currentTable; + if(!currentTable.fromSerialised(table_name.toStdString())) + { + // This is an old project file format which doesn't yet contain serialised table identifiers. This means + // we have to try our best to unserialise this one manually. The only problem is when the name of an + // attached database or of a table contains a dot character. In that case the name becomes ambigious and + // we just try to split it at the first dot. I don't think it affects many (if any) project files. But if + // it turn out to be wrong, we can always add a loop here which checks for any possible combination of schema + // and table name whether an object with that combination exists. + // TODO: Delete this code in the future when we don't expect there to be any project files in the old format anymore. + if(table_name.contains('.')) + { + currentTable.setSchema(table_name.left(table_name.indexOf('.')).toStdString()); + currentTable.setName(table_name.mid(table_name.indexOf('.')+1).toStdString()); + } else { + currentTable.setName(table_name.toStdString()); + } + } + + if (!currentTable.isEmpty()) + { + int tab_index = newTableBrowserTab(true); + TableBrowser* w = qobject_cast(ui->tabBrowsers->widget(tab_index)); + if(w) + w->setCurrentTable(currentTable); + } + + xml.skipCurrentElement(); + } else if(xml.name() == "table") { + // New browser tab + QString title = xml.attributes().value("title").toString(); + sqlb::ObjectIdentifier table; + table.fromSerialised(xml.attributes().value("table").toString().toStdString()); + + int tab_index = newTableBrowserTab(true); + ui->tabBrowsers->setTabText(tab_index, title); + TableBrowser* w = qobject_cast(ui->tabBrowsers->widget(tab_index)); + if(w) + w->setCurrentTable(table); + + xml.skipCurrentElement(); + } else if(xml.name() == "current_tab") { + // Currently selected tab + ui->tabBrowsers->setCurrentIndex(xml.attributes().value("id").toString().toInt()); xml.skipCurrentElement(); } else if(xml.name() == "default_encoding") { // Default text encoding - ui->tableBrowser->setDefaultEncoding(xml.attributes().value("codec").toString()); + TableBrowser::setDefaultEncoding(xml.attributes().value("codec").toString()); xml.skipCurrentElement(); } else if(xml.name() == "browsetable_info") { // This tag is only found in old project files. In newer versions (>= 3.11) it is replaced by a new implementation. @@ -2615,9 +2688,11 @@ bool MainWindow::loadProject(QString filename, bool readOnly) xml.attributes().value("name").toString().toStdString()); BrowseDataTableSettings settings; loadBrowseDataTableSettings(settings, xml); - ui->tableBrowser->setSettings(tableIdentifier, settings); + TableBrowser::setSettings(tableIdentifier, settings); } } + } else { + xml.skipCurrentElement(); } } @@ -2650,28 +2725,6 @@ bool MainWindow::loadProject(QString filename, bool readOnly) file.close(); if(ui->mainTab->currentWidget() == ui->browser) { - if (!currentTable.isEmpty()) - { - sqlb::ObjectIdentifier obj; - if(!obj.fromSerialised(currentTable.toStdString())) - { - // This is an old project file format which doesn't yet contain serialised table identifiers. This means - // we have to try our best to unserialise this one manually. The only problem is when the name of an - // attached database or of a table contains a dot character. In that case the name becomes ambigious and - // we just try to split it at the first dot. I don't think it affects many (if any) project files. But if - // it turn out to be wrong, we can always add a loop here which checks for any possible combination of schema - // and table name whether an object with that combination exists. - // TODO: Delete this code in the future when we don't expect there to be any project files in the old format anymore. - if(currentTable.contains('.')) - { - obj.setSchema(currentTable.left(currentTable.indexOf('.')).toStdString()); - obj.setName(currentTable.mid(currentTable.indexOf('.')+1).toStdString()); - } else { - obj.setName(currentTable.toStdString()); - } - } - switchToBrowseDataTab(obj); - } populateTable(); // Refresh view } @@ -2889,15 +2942,26 @@ void MainWindow::saveProject(const QString& currentFilename) // Browse Data tab settings xml.writeStartElement("tab_browse"); - xml.writeStartElement("current_table"); // Currently selected table - xml.writeAttribute("name", QString::fromStdString(ui->tableBrowser->currentlyBrowsedTableName().toSerialised())); + + for(int i=0;itabBrowsers->count();i++) + { + TableBrowser* w = qobject_cast(ui->tabBrowsers->widget(i)); + xml.writeStartElement("table"); + xml.writeAttribute("title", ui->tabBrowsers->tabText(i)); + xml.writeAttribute("table", QString::fromStdString(w->currentlyBrowsedTableName().toSerialised())); + xml.writeEndElement(); + } + + xml.writeStartElement("current_tab"); // Currently selected tab + xml.writeAttribute("id", QString::number(ui->tabBrowsers->currentIndex())); xml.writeEndElement(); + xml.writeStartElement("default_encoding"); // Default encoding for text stored in tables - xml.writeAttribute("codec", ui->tableBrowser->defaultEncoding()); + xml.writeAttribute("codec", TableBrowser::defaultEncoding()); xml.writeEndElement(); xml.writeStartElement("browse_table_settings"); - const auto settings = ui->tableBrowser->allSettings(); + const auto settings = TableBrowser::allSettings(); for(auto tableIt=settings.cbegin(); tableIt!=settings.cend(); ++tableIt) { xml.writeStartElement("table"); @@ -3062,7 +3126,11 @@ void MainWindow::switchToBrowseDataTab(sqlb::ObjectIdentifier tableToBrowse) tableToBrowse.setName(ui->dbTreeWidget->model()->data(ui->dbTreeWidget->currentIndex().sibling(ui->dbTreeWidget->currentIndex().row(), DbStructureModel::ColumnName), Qt::EditRole).toString().toStdString()); } - ui->tableBrowser->setCurrentTable(tableToBrowse); + int tab_index = newTableBrowserTab(); + TableBrowser* w = qobject_cast(ui->tabBrowsers->widget(tab_index)); + if(w) + w->setCurrentTable(tableToBrowse); + if (ui->mainTab->indexOf(ui->browser) == -1) ui->mainTab->addTab(ui->browser, ui->browser->accessibleName()); ui->mainTab->setCurrentWidget(ui->browser); @@ -3480,3 +3548,124 @@ void MainWindow::clearRecentFiles() for(int i=0; i < MaxRecentFiles; ++i) recentFileActs[i]->setVisible(false); } + +sqlb::ObjectIdentifier MainWindow::currentlyBrowsedTableName() const +{ + TableBrowser* w = qobject_cast(ui->tabBrowsers->currentWidget()); + + if(w) + return w->currentlyBrowsedTableName(); + else + return sqlb::ObjectIdentifier{}; +} + +void MainWindow::closeTableBrowserTab(int index, bool force) +{ + // Remove the tab and delete the widget + QWidget* w = ui->tabBrowsers->widget(index); + ui->tabBrowsers->removeTab(index); + delete w; + + // Don't let an empty tab widget + if(ui->tabBrowsers->count() == 0 && !force) + newTableBrowserTab(true); +} + +int MainWindow::newTableBrowserTab(bool resetCounter) +{ + static int tabNumber = 0; + + if(resetCounter) + tabNumber = 0; + + // Create and initialise widget + TableBrowser* w = new TableBrowser(&db, this); + w->setStructure(dbStructureModel); + w->setEnabled(ui->fileCloseAction->isEnabled()); + + // Connect signals and slots + connect(w, &TableBrowser::projectModified, this, [this]() { + isProjectModified = true; + }); + connect(w->model(), &SqliteTableModel::dataChanged, this, &MainWindow::dataTableSelectionChanged); + connect(w, &TableBrowser::selectionChanged, this, &MainWindow::dataTableSelectionChanged); + connect(w, &TableBrowser::selectionChangedByDoubleClick, this, &MainWindow::doubleClickTable); + connect(w, &TableBrowser::updatePlot, this, &MainWindow::attachPlot); + connect(w, &TableBrowser::createView, this, &MainWindow::saveAsView); + connect(w, &TableBrowser::requestFileOpen, this, [this](const QString& file) { + fileOpen(file); + }); + connect(w, &TableBrowser::statusMessageRequested, ui->statusbar, [this](const QString& message) { + ui->statusbar->showMessage(message); + }); + connect(w->model(), &SqliteTableModel::finishedFetch, [this, w](){ + auto& settings = w->settings(w->currentlyBrowsedTableName()); + plotDock->updatePlot(w->model(), &settings, true, false); + }); + + // Set current model + m_currentTabTableModel = w->model(); + + // Create new tab, add it to the tab widget and select it + int index = ui->tabBrowsers->addTab(w, QIcon(":icons/table"), QString("Browse %1").arg(++tabNumber)); + ui->tabBrowsers->setCurrentIndex(index); + + return index; +} + +void MainWindow::changeTableBrowserTab(int index) +{ + TableBrowser* w = qobject_cast(ui->tabBrowsers->widget(index)); + if(w) + { + m_currentTabTableModel = w->model(); + w->updateTable(); + } +} + +void MainWindow::renameTableBrowserTab(int index) +{ + QString new_name = QInputDialog::getText(this, + qApp->applicationName(), + tr("Set a new name for the Browse Data tab. Use the '&&' character to allow using the following character as a keyboard shortcut."), + QLineEdit::EchoMode::Normal, + ui->tabBrowsers->tabText(index)); + + if(!new_name.isNull()) // Don't do anything if the Cancel button was clicked + ui->tabBrowsers->setTabText(index, new_name); +} + +void MainWindow::showContextMenuTableBrowserTabBar(const QPoint& pos) +{ + // Don't show context menu if the mouse click was outside of all the tabs + int tab = ui->tabBrowsers->tabBar()->tabAt(pos); + if(tab == -1) + return; + + // Prepare all menu actions + QAction* actionNewTab = new QAction(this); + actionNewTab->setText(tr("New Tab")); + connect(actionNewTab, &QAction::triggered, [this]() { + newTableBrowserTab(); + }); + + QAction* actionRename = new QAction(this); + actionRename->setText(tr("Rename Tab")); + connect(actionRename, &QAction::triggered, [this, tab]() { + renameTableBrowserTab(tab); + }); + + QAction* actionClose = new QAction(this); + actionClose->setText(tr("Close Tab")); + actionClose->setShortcut(tr("Ctrl+W")); + connect(actionClose, &QAction::triggered, [this, tab]() { + closeTableBrowserTab(tab); + }); + + // Show menu + QMenu* menuTabs = new QMenu(this); + menuTabs->addAction(actionNewTab); + menuTabs->addAction(actionRename); + menuTabs->addAction(actionClose); + menuTabs->exec(ui->tabBrowsers->mapToGlobal(pos)); +} diff --git a/src/MainWindow.h b/src/MainWindow.h index c1e51ccd..7a2f432d 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -116,6 +116,9 @@ private: void focusSqlEditor(); void moveDocksTo(Qt::DockWidgetArea area); + // Identifier of the currently browsed table in the current data browser tab + sqlb::ObjectIdentifier currentlyBrowsedTableName() const; + protected: void closeEvent(QCloseEvent *) override; void dragEnterEvent(QDragEnterEvent *event) override; @@ -128,7 +131,7 @@ public slots: void dbState(bool dirty); void refresh(); void switchToBrowseDataTab(sqlb::ObjectIdentifier tableToBrowse = sqlb::ObjectIdentifier()); - void populateStructure(const sqlb::ObjectIdentifier& old_table = sqlb::ObjectIdentifier{}); + void populateStructure(const std::vector& old_tables = {}); void reloadSettings(); bool closeFiles(); @@ -164,9 +167,6 @@ private slots: void updatePragmaUi(); void savePragmas(); void mainTabSelected( int tabindex ); - int openSqlTab(bool resetCounter = false); - void closeSqlTab(int index, bool force = false, bool askSaving = true); - void changeSqlTab(int index); void openSqlFile(); void saveSqlFile(); void saveSqlFileAs(); @@ -188,7 +188,6 @@ private slots: void copyCurrentCreateStatement(); void fileOpenReadOnly(); void requestCollation(const QString& name, int eTextRep); - void renameSqlTab(int index); void setFindFrameVisibility(bool show); void openFindReplaceDialog(); void toggleSqlBlockComment(); @@ -201,8 +200,19 @@ private slots: void showStatusMessage5s(QString message); void saveSqlFile(int tabIndex); void saveAll(); - void showContextMenuSqlTabBar(const QPoint& pos); void openUrlOrFile(const QString& urlString); + + int openSqlTab(bool resetCounter = false); + void closeSqlTab(int index, bool force = false, bool askSaving = true); + void changeSqlTab(int index); + void renameSqlTab(int index); + void showContextMenuSqlTabBar(const QPoint& pos); + + int newTableBrowserTab(bool resetCounter = false); + void closeTableBrowserTab(int index, bool force = false); + void changeTableBrowserTab(int index); + void renameTableBrowserTab(int index); + void showContextMenuTableBrowserTabBar(const QPoint& pos); }; #endif diff --git a/src/MainWindow.ui b/src/MainWindow.ui index 719d632d..d5e73a36 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -137,7 +137,17 @@ You can drag SQL statements from an object row and drop them into other applicat 3 - + + + Qt::CustomContextMenu + + + -1 + + + true + + @@ -174,8 +184,8 @@ You can drag SQL statements from an object row and drop them into other applicat 0 0 - 639 - 574 + 641 + 544 @@ -744,7 +754,7 @@ You can drag SQL statements from an object row and drop them into other applicat 0 0 1037 - 22 + 23 @@ -2202,12 +2212,6 @@ You can drag SQL statements from the Schema column and drop them into the SQL ed
ExtendedScintilla.h
1 - - TableBrowser - QWidget -
TableBrowser.h
- 1 -
mainTab @@ -3600,6 +3604,70 @@ You can drag SQL statements from the Schema column and drop them into the SQL ed + + tabBrowsers + currentChanged(int) + MainWindow + changeTableBrowserTab(int) + + + 336 + 347 + + + 518 + 314 + + + + + tabBrowsers + tabCloseRequested(int) + MainWindow + closeTableBrowserTab(int) + + + 336 + 347 + + + 518 + 314 + + + + + tabBrowsers + tabBarDoubleClicked(int) + MainWindow + renameTableBrowserTab(int) + + + 336 + 347 + + + 518 + 314 + + + + + tabBrowsers + customContextMenuRequested(QPoint) + MainWindow + showContextMenuTableBrowserTabBar(QPoint) + + + 336 + 347 + + + 518 + 314 + + + fileOpen() @@ -3654,5 +3722,10 @@ You can drag SQL statements from the Schema column and drop them into the SQL ed renameSqlTab(int) fileNewInMemoryDatabase() showContextMenuSqlTabBar(QPoint) + closeTableBrowserTab(int) + openTableBrowserTab() + changeTableBrowserTab(int) + renameTableBrowserTab(int) + showContextMenuTableBrowserTabBar(QPoint) diff --git a/src/TableBrowser.cpp b/src/TableBrowser.cpp index dbf8522f..66d5df43 100644 --- a/src/TableBrowser.cpp +++ b/src/TableBrowser.cpp @@ -23,11 +23,11 @@ std::map TableBrowser::m_settings; QString TableBrowser::m_defaultEncoding; -TableBrowser::TableBrowser(QWidget* parent) : +TableBrowser::TableBrowser(DBBrowserDB* _db, QWidget* parent) : QWidget(parent), ui(new Ui::TableBrowser), gotoValidator(new QIntValidator(0, 0, this)), - db(nullptr), + db(_db), dbStructureModel(nullptr), m_model(nullptr), m_adjustRows(false), @@ -317,17 +317,6 @@ TableBrowser::TableBrowser(QWidget* parent) : connect(ui->buttonReplaceAll, &QToolButton::clicked, this, [this](){ find(ui->editFindExpression->text(), true, true, ReplaceMode::ReplaceAll); }); -} - -TableBrowser::~TableBrowser() -{ - delete gotoValidator; - delete ui; -} - -void TableBrowser::init(DBBrowserDB* _db) -{ - db = _db; // Recreate the model if(m_model) @@ -338,15 +327,17 @@ void TableBrowser::init(DBBrowserDB* _db) connect(m_model, &SqliteTableModel::finishedFetch, this, &TableBrowser::fetchedData); } +TableBrowser::~TableBrowser() +{ + delete gotoValidator; + delete ui; +} + void TableBrowser::reset() { // Reset the model m_model->reset(); - // Remove all stored table information browse data tab - m_settings.clear(); - m_defaultEncoding = QString(); - // Reset the recordset label inside the Browse tab now updateRecordsetLabel(); @@ -357,6 +348,13 @@ void TableBrowser::reset() emit updatePlot(nullptr, nullptr, nullptr, true); } +void TableBrowser::resetSharedSettings() +{ + // Remove all stored table information browse data tab + m_settings.clear(); + m_defaultEncoding = QString(); +} + sqlb::ObjectIdentifier TableBrowser::currentlyBrowsedTableName() const { return sqlb::ObjectIdentifier(dbStructureModel->index(ui->comboBrowseTable->currentIndex(), diff --git a/src/TableBrowser.h b/src/TableBrowser.h index 93d07931..ce740cde 100644 --- a/src/TableBrowser.h +++ b/src/TableBrowser.h @@ -54,16 +54,16 @@ class TableBrowser : public QWidget Q_OBJECT public: - explicit TableBrowser(QWidget* parent = nullptr); + explicit TableBrowser(DBBrowserDB* _db, QWidget* parent = nullptr); ~TableBrowser(); - void init(DBBrowserDB* _db); void reset(); + static void resetSharedSettings(); sqlb::ObjectIdentifier currentlyBrowsedTableName() const; - std::map allSettings() const { return m_settings; } - BrowseDataTableSettings& settings(const sqlb::ObjectIdentifier& object); - void setSettings(const sqlb::ObjectIdentifier& table, const BrowseDataTableSettings& table_settings); + static std::map allSettings() { return m_settings; } + static BrowseDataTableSettings& settings(const sqlb::ObjectIdentifier& object); + static void setSettings(const sqlb::ObjectIdentifier& table, const BrowseDataTableSettings& table_settings); void setStructure(QAbstractItemModel* model, const sqlb::ObjectIdentifier& old_table = sqlb::ObjectIdentifier{}); @@ -71,8 +71,8 @@ public: QModelIndex currentIndex() const; - void setDefaultEncoding(const QString& encoding) { m_defaultEncoding = encoding; } - QString defaultEncoding() const { return m_defaultEncoding; } + static void setDefaultEncoding(const QString& encoding) { m_defaultEncoding = encoding; } + static QString defaultEncoding() { return m_defaultEncoding; } public slots: void setEnabled(bool enable); diff --git a/src/TableBrowser.ui b/src/TableBrowser.ui index ea82b1fe..1c92090c 100644 --- a/src/TableBrowser.ui +++ b/src/TableBrowser.ui @@ -449,9 +449,6 @@ - - false - <html><head/><body><p>Scroll to the beginning</p></body></html> @@ -469,9 +466,6 @@ - - false - Scroll one page upwards @@ -496,9 +490,6 @@ - - false - Scroll one page downwards @@ -516,9 +507,6 @@ - - false - Scroll to the end