Allow multiple TableBrowser tabs in the Browse Data tab

This adds a new tab widget inside the Browse Data tab which allows you
to create multiple TableBrowser widgets. This way you can browse
multiple tables at the same time and switch between them.

I don't consider this done. The UI for this is likely to change in the
future. This commit is just a first step towards this goal.

See issue #2283.
This commit is contained in:
Martin Kleusberg
2020-08-15 20:00:14 +02:00
parent 8323f2a1b6
commit 1e1e87e61c
6 changed files with 392 additions and 134 deletions

View File

@@ -26,6 +26,7 @@
#include "RunSql.h"
#include "ExtendedTableWidget.h"
#include "Data.h"
#include "TableBrowser.h"
#include <chrono>
#include <QFile>
@@ -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<sqlb::ObjectIdentifier> old_tables;
for(int i=0;i<ui->tabBrowsers->count();i++)
{
TableBrowser* w = qobject_cast<TableBrowser*>(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<sqlb::ObjectIdentifier>& 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;i<ui->tabBrowsers->count()&&static_cast<size_t>(i)<old_tables.size();i++)
{
TableBrowser* w = qobject_cast<TableBrowser*>(ui->tabBrowsers->widget(i));
if(w)
w->setStructure(dbStructureModel, old_tables.at(static_cast<size_t>(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<TableBrowser*>(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<TableBrowser*>(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<TableBrowser*>(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<TableBrowser*>(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<TableBrowser*>(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<TableBrowser*>(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<TableBrowser*>(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;i<ui->tabBrowsers->count();i++)
{
TableBrowser* w = qobject_cast<TableBrowser*>(ui->tabBrowsers->currentWidget());
if(w)
w->setEnabled(enable);
}
}
void MainWindow::resizeEvent(QResizeEvent*)
{
ui->tableBrowser->updateRecordsetLabel();
TableBrowser* w = qobject_cast<TableBrowser*>(ui->tabBrowsers->currentWidget());
if(w)
w->updateRecordsetLabel();
}
void MainWindow::loadPragmas()
@@ -2130,7 +2147,12 @@ void MainWindow::reloadSettings()
qobject_cast<Application*>(qApp)->reloadSettings();
// Set data browser font
ui->tableBrowser->reloadSettings();
for(int i=0;i<ui->tabBrowsers->count();i++)
{
TableBrowser* w = qobject_cast<TableBrowser*>(ui->tabBrowsers->widget(i));
if(w)
w->reloadSettings();
}
switch (static_cast<Settings::AppStyle>(Settings::getValue("General", "appStyle").toInt())) {
case Settings::FollowDesktopStyle :
@@ -2198,6 +2220,7 @@ void MainWindow::reloadSettings()
sqlb::setIdentifierQuoting(static_cast<sqlb::escapeQuoting>(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<TableBrowser*>(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<TableBrowser*>(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;i<ui->tabBrowsers->count();i++)
{
TableBrowser* w = qobject_cast<TableBrowser*>(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<TableBrowser*>(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<TableBrowser*>(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<TableBrowser*>(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));
}

View File

@@ -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<sqlb::ObjectIdentifier>& 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

View File

@@ -137,7 +137,17 @@ You can drag SQL statements from an object row and drop them into other applicat
<number>3</number>
</property>
<item>
<widget class="TableBrowser" name="tableBrowser" native="true"/>
<widget class="QTabWidget" name="tabBrowsers">
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
<property name="currentIndex">
<number>-1</number>
</property>
<property name="movable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
@@ -174,8 +184,8 @@ You can drag SQL statements from an object row and drop them into other applicat
<rect>
<x>0</x>
<y>0</y>
<width>639</width>
<height>574</height>
<width>641</width>
<height>544</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
@@ -744,7 +754,7 @@ You can drag SQL statements from an object row and drop them into other applicat
<x>0</x>
<y>0</y>
<width>1037</width>
<height>22</height>
<height>23</height>
</rect>
</property>
<widget class="QMenu" name="fileMenu">
@@ -2202,12 +2212,6 @@ You can drag SQL statements from the Schema column and drop them into the SQL ed
<header>ExtendedScintilla.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>TableBrowser</class>
<extends>QWidget</extends>
<header>TableBrowser.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>mainTab</tabstop>
@@ -3600,6 +3604,70 @@ You can drag SQL statements from the Schema column and drop them into the SQL ed
</hint>
</hints>
</connection>
<connection>
<sender>tabBrowsers</sender>
<signal>currentChanged(int)</signal>
<receiver>MainWindow</receiver>
<slot>changeTableBrowserTab(int)</slot>
<hints>
<hint type="sourcelabel">
<x>336</x>
<y>347</y>
</hint>
<hint type="destinationlabel">
<x>518</x>
<y>314</y>
</hint>
</hints>
</connection>
<connection>
<sender>tabBrowsers</sender>
<signal>tabCloseRequested(int)</signal>
<receiver>MainWindow</receiver>
<slot>closeTableBrowserTab(int)</slot>
<hints>
<hint type="sourcelabel">
<x>336</x>
<y>347</y>
</hint>
<hint type="destinationlabel">
<x>518</x>
<y>314</y>
</hint>
</hints>
</connection>
<connection>
<sender>tabBrowsers</sender>
<signal>tabBarDoubleClicked(int)</signal>
<receiver>MainWindow</receiver>
<slot>renameTableBrowserTab(int)</slot>
<hints>
<hint type="sourcelabel">
<x>336</x>
<y>347</y>
</hint>
<hint type="destinationlabel">
<x>518</x>
<y>314</y>
</hint>
</hints>
</connection>
<connection>
<sender>tabBrowsers</sender>
<signal>customContextMenuRequested(QPoint)</signal>
<receiver>MainWindow</receiver>
<slot>showContextMenuTableBrowserTabBar(QPoint)</slot>
<hints>
<hint type="sourcelabel">
<x>336</x>
<y>347</y>
</hint>
<hint type="destinationlabel">
<x>518</x>
<y>314</y>
</hint>
</hints>
</connection>
</connections>
<slots>
<slot>fileOpen()</slot>
@@ -3654,5 +3722,10 @@ You can drag SQL statements from the Schema column and drop them into the SQL ed
<slot>renameSqlTab(int)</slot>
<slot>fileNewInMemoryDatabase()</slot>
<slot>showContextMenuSqlTabBar(QPoint)</slot>
<slot>closeTableBrowserTab(int)</slot>
<slot>openTableBrowserTab()</slot>
<slot>changeTableBrowserTab(int)</slot>
<slot>renameTableBrowserTab(int)</slot>
<slot>showContextMenuTableBrowserTabBar(QPoint)</slot>
</slots>
</ui>

View File

@@ -23,11 +23,11 @@
std::map<sqlb::ObjectIdentifier, BrowseDataTableSettings> 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(),

View File

@@ -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<sqlb::ObjectIdentifier, BrowseDataTableSettings> allSettings() const { return m_settings; }
BrowseDataTableSettings& settings(const sqlb::ObjectIdentifier& object);
void setSettings(const sqlb::ObjectIdentifier& table, const BrowseDataTableSettings& table_settings);
static std::map<sqlb::ObjectIdentifier, BrowseDataTableSettings> 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);

View File

@@ -449,9 +449,6 @@
</property>
<item>
<widget class="QToolButton" name="buttonBegin">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Scroll to the beginning&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
@@ -469,9 +466,6 @@
</item>
<item>
<widget class="QToolButton" name="buttonPrevious">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Scroll one page upwards</string>
</property>
@@ -496,9 +490,6 @@
</item>
<item>
<widget class="QToolButton" name="buttonNext">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Scroll one page downwards</string>
</property>
@@ -516,9 +507,6 @@
</item>
<item>
<widget class="QToolButton" name="buttonEnd">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Scroll to the end</string>
</property>