Skip to content

Commit

Permalink
Ask user about saving any modified data in SQL tabs
Browse files Browse the repository at this point in the history
User is asked once for saving modified SQL tabs not attached to a file to
the current project file (or to a new project file, when there isn't any
yet).

For each tab linked to a file, the user is asked to save the changes to the
file.

The asking is performed when the tab is closed, or when the application
is closing.

The modified attribute of the editor is set to false when the data is
saved or has just been loaded in the editor.

See issues sqlitebrowser#1386 and sqlitebrowser#1706
  • Loading branch information
mgrojo committed Jan 17, 2019
1 parent fbef621 commit f08cdb1
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 4 deletions.
82 changes: 78 additions & 4 deletions src/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -944,7 +944,7 @@ bool MainWindow::fileClose()

void MainWindow::closeEvent( QCloseEvent* event )
{
if(db.close())
if(closeFiles())
{
Settings::setValue("MainWindow", "geometry", saveGeometry());
Settings::setValue("MainWindow", "windowState", saveState());
Expand All @@ -960,6 +960,17 @@ void MainWindow::closeEvent( QCloseEvent* event )
}
}

bool MainWindow::closeFiles()
{
bool ignoreUnattachedBuffers = false;
// Ask for saving all modified open SQL files in their files and all the unattached tabs in a project file.
for(int i=0; i<ui->tabSqlAreas->count(); i++)
// Ask for saving and comply with cancel answer.
if(!askSaveSqlTab(i, ignoreUnattachedBuffers))
return false;
return db.close();
}

void MainWindow::addRecord()
{
int row = m_browseTableModel->rowCount();
Expand Down Expand Up @@ -2116,6 +2127,59 @@ void MainWindow::logSql(const QString& sql, int msgtype)
}
}

// Ask user to save the buffer in the specified tab index.
// ignoreUnattachedBuffers is used to store answer about buffers not linked to files, so user is only asked once about them.
// Return true unless user wants to cancel the invoking action.
bool MainWindow::askSaveSqlTab(int index, bool& ignoreUnattachedBuffers)
{
SqlExecutionArea* sqlExecArea = qobject_cast<SqlExecutionArea*>(ui->tabSqlAreas->widget(index));

if(sqlExecArea->getEditor()->isModified()) {
if(sqlExecArea->fileName().isEmpty() && !ignoreUnattachedBuffers) {
// Once the project is saved, remaining SQL tabs will not be modified, so this is only expected to be asked once.
QString message = currentProjectFilename.isEmpty() ?
tr("Do you want to save the changes made to SQL tabs in a new project file?") :
tr("Do you want to save the changes made to SQL tabs in the project file %1?").
arg(QFileInfo(currentProjectFilename).fileName());
QMessageBox::StandardButton reply = QMessageBox::question(nullptr,
QApplication::applicationName(),
message,
QMessageBox::Save | QMessageBox::No | QMessageBox::Cancel);
switch(reply) {
case QMessageBox::Save:
saveProject();
break;
case QMessageBox::Cancel:
return false;
default:
ignoreUnattachedBuffers = true;
break;
}
} else if(!sqlExecArea->fileName().isEmpty()) {
// Set the tab as current. This is both for user feedback as well as for saveSqlFile(),
// which requires the file to be saved to be in the current tab.
ui->tabSqlAreas->setCurrentIndex(index);

QMessageBox::StandardButton reply =
QMessageBox::question(nullptr,
QApplication::applicationName(),
tr("Do you want to save the changes made to the SQL file %1?").
arg(QFileInfo(sqlExecArea->fileName()).fileName()),
QMessageBox::Save | QMessageBox::No | QMessageBox::Cancel);
switch(reply) {
case QMessageBox::Save:
saveSqlFile();
break;
case QMessageBox::Cancel:
return false;
default:
break;
}
}
}
return true;
}

void MainWindow::closeSqlTab(int index, bool force)
{
// Don't close last tab
Expand All @@ -2135,7 +2199,10 @@ void MainWindow::closeSqlTab(int index, bool force)
execute_sql_worker->stop();
execute_sql_worker->wait();
}

// Ask for saving and comply with cancel answer.
bool ignoreUnattachedBuffers = false;
if (!askSaveSqlTab(index, ignoreUnattachedBuffers))
return;
// Remove the tab and delete the widget
QWidget* w = ui->tabSqlAreas->widget(index);
ui->tabSqlAreas->removeTab(index);
Expand Down Expand Up @@ -2211,6 +2278,7 @@ void MainWindow::openSqlFile()

SqlExecutionArea* sqlarea = qobject_cast<SqlExecutionArea*>(ui->tabSqlAreas->widget(index));
sqlarea->getEditor()->setText(f.readAll());
sqlarea->getEditor()->setModified(false);
sqlarea->setFileName(file);
QFileInfo fileinfo(file);
ui->tabSqlAreas->setTabText(index, fileinfo.fileName());
Expand All @@ -2234,6 +2302,8 @@ void MainWindow::saveSqlFile()
{
QFileInfo fileinfo(sqlarea->fileName());
ui->tabSqlAreas->setTabText(ui->tabSqlAreas->currentIndex(), fileinfo.fileName());
// Set modified to false so we can get control of unsaved changes when closing.
sqlarea->getEditor()->setModified(false);
} else {
QMessageBox::warning(this, qApp->applicationName(), tr("Couldn't save file: %1.").arg(f.errorString()));
}
Expand Down Expand Up @@ -2762,7 +2832,9 @@ bool MainWindow::loadProject(QString filename, bool readOnly)
// SQL editor tab
unsigned int index = openSqlTab();
ui->tabSqlAreas->setTabText(index, xml.attributes().value("name").toString());
qobject_cast<SqlExecutionArea*>(ui->tabSqlAreas->widget(index))->getEditor()->setText(xml.readElementText());
SqlTextEdit* sqlEditor = qobject_cast<SqlExecutionArea*>(ui->tabSqlAreas->widget(index))->getEditor();
sqlEditor->setText(xml.readElementText());
sqlEditor->setModified(false);
} else if(xml.name() == "current_tab") {
// Currently selected tab
ui->tabSqlAreas->setCurrentIndex(xml.attributes().value("id").toString().toInt());
Expand Down Expand Up @@ -2991,9 +3063,11 @@ QString MainWindow::saveProject(const QString& currentFilename)
xml.writeStartElement("tab_sql");
for(int i=0;i<ui->tabSqlAreas->count();i++) // All SQL tabs content
{
SqlExecutionArea* sqlArea = qobject_cast<SqlExecutionArea*>(ui->tabSqlAreas->widget(i));
xml.writeStartElement("sql");
xml.writeAttribute("name", ui->tabSqlAreas->tabText(i));
xml.writeCharacters(qobject_cast<SqlExecutionArea*>(ui->tabSqlAreas->widget(i))->getSql());
xml.writeCharacters(sqlArea->getSql());
sqlArea->getEditor()->setModified(false);
xml.writeEndElement();
}
xml.writeStartElement("current_tab"); // Currently selected tab
Expand Down
2 changes: 2 additions & 0 deletions src/MainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,8 @@ class MainWindow : public QMainWindow
void restoreOpenTabs(QString tabs);
QString saveOpenTabs();
QString saveProject(const QString& currentFilename);
bool closeFiles();
bool askSaveSqlTab(int index, bool& ignoreUnattachedBuffers);

protected:
void closeEvent(QCloseEvent *) override;
Expand Down

0 comments on commit f08cdb1

Please sign in to comment.