Show UnsavedDocumentsDialog when closing window or quitting application

so user can save and or discard docs more efficiently.
This commit is contained in:
eelke 2026-10-19 18:16:25 +02:00
parent b97adced4c
commit 784ad68758
16 changed files with 544 additions and 164 deletions

View file

@ -21,12 +21,16 @@
#include "util.h"
#include "UserConfiguration.h"
#include "IDatabaseWindow.h"
#include "UnsavedDocumentsDialog.h"
#include <QPlainTextDocumentLayout>
#include <QTextDocument>
QueryTool::QueryTool(IDatabaseWindow *context, QWidget *parent)
QueryTool::QueryTool(IDatabaseWindow *context, std::shared_ptr<SqlDocument> document, QWidget *parent)
: ManagedPage(parent)
, m_context(context)
, ui(new Ui::QueryTab)
, m_document(std::move(document))
, m_dbConnection()
{
ui->setupUi(this);
@ -40,13 +44,15 @@ QueryTool::QueryTool(IDatabaseWindow *context, QWidget *parent)
ui->queryEdit->setFont(UserConfiguration::instance()->codeFont());
highlighter = new SqlSyntaxHighlighter(ui->queryEdit->document());
ui->queryEdit->setDocument(m_document->textDocument());
m_document->addEditor(this);
auto types = m_catalog->types();
if (types) {
highlighter->setTypes(*types);
m_document->highlighter()->setTypes(*types);
}
connect(ui->queryEdit, &QPlainTextEdit::textChanged, this, &QueryTool::queryTextChanged);
connect(m_document.get(), &SqlDocument::modifiedChanged, this, &QueryTool::updateTitle);
connect(m_document.get(), &SqlDocument::fileNameChanged, this, &QueryTool::updateTitle);
ui->queryEdit->setAcceptDrops(false);
m_queryParamListController = new QueryParamListController(ui->paramTableView, m_context->openDatabase(), this);
@ -60,87 +66,42 @@ QueryTool::QueryTool(IDatabaseWindow *context, QWidget *parent)
QueryTool::~QueryTool()
{
// Detach the editor from the shared document, it may be destroyed together with this tool
auto detached = new QTextDocument(ui->queryEdit);
detached->setDocumentLayout(new QPlainTextDocumentLayout(detached));
ui->queryEdit->setDocument(detached);
m_document->removeEditor(this);
delete ui;
}
bool QueryTool::CanClose(bool prompt_user)
{
bool can_close;
if (m_queryTextChanged) {
if (prompt_user)
can_close = continueWithoutSavingWarning();
else
can_close = false;
}
else {
can_close = true;
}
return can_close;
}
if (!m_document->isModified())
return true;
void QueryTool::newdoc()
{
ui->queryEdit->clear();
setFileName(tr("new"));
setQueryTextChanged(false);
m_new = true;
}
// The document stays open in another editor, so it is not closed with this tool
if (m_document->editors().size() > 1)
return true;
bool QueryTool::load(const QString &filename)
{
bool result = false;
QFile file(filename);
if (file.open(QIODevice::ReadOnly)) {
QByteArray ba = file.readAll();
auto toUtf16 = QStringDecoder(QStringDecoder::Utf8);
QString text = toUtf16(ba);
if (toUtf16.hasError()) {
file.reset();
QTextStream stream(&file);
text = stream.readAll();
}
if (!prompt_user)
return false;
ui->queryEdit->setPlainText(text);
setQueryTextChanged(false);
setFileName(filename);
m_new = false;
result = true;
}
return result;
return confirmClose(this, {m_document});
}
bool QueryTool::save()
{
bool result;
if (m_fileName.isEmpty() || m_new) {
result = saveAs();
}
else {
result = saveSqlTo(m_fileName);
}
return result;
return m_document->save(this);
}
bool QueryTool::saveAs()
{
bool result = false;
QString filename = promptUserForSaveSqlFilename();
if (!filename.isEmpty()) {
result = saveSqlTo(filename);
if (result) {
setFileName(filename);
m_new = false;
}
}
return result;
return m_document->saveAs(this);
}
void QueryTool::saveCopyAs()
{
QString filename = promptUserForSaveSqlFilename();
if (!filename.isEmpty()) {
saveSqlTo(filename);
}
m_document->saveCopyAs(this);
}
void QueryTool::execute()
@ -245,81 +206,21 @@ void QueryTool::cancel()
QString QueryTool::title() const
{
QFileInfo fileInfo(m_fileName);
QFileInfo fileInfo(m_document->fileName());
QString fn(fileInfo.fileName());
return fn;
}
void QueryTool::setFileName(const QString &filename)
{
m_fileName = filename;
updateTitle();
}
void QueryTool::updateTitle()
{
QFileInfo fileInfo(m_fileName);
QFileInfo fileInfo(m_document->fileName());
QString title = fileInfo.fileName();
if (m_queryTextChanged) {
if (m_document->isModified()) {
title = "*" + title;
}
m_context->setTitleForWidget(this, title, m_fileName);
}
bool QueryTool::continueWithoutSavingWarning()
{
QMessageBox msgBox;
msgBox.setIcon(QMessageBox::Warning);
msgBox.setText(QString("Save changes in document \"%1\" before closing?").arg(m_fileName));
msgBox.setInformativeText("The changes will be lost when you choose Discard.");
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Cancel);
int ret = msgBox.exec();
if (ret == QMessageBox::Save) {
if (!save()) {
// save failed or was a saveAs and was cancelled, don't close!
ret = QMessageBox::Cancel;
}
}
return ret != QMessageBox::Cancel;
}
bool QueryTool::saveSqlTo(const QString &filename)
{
bool result = false;
QFileInfo fileinfo(filename);
QFile file(filename);
if (file.open(QIODevice::WriteOnly)) {
QTextStream stream(&file);
//stream.setCodec("utf-8");
stream.setEncoding(QStringConverter::Utf8);
QString text = ui->queryEdit->toPlainText();
stream << text;
stream.flush();
if (stream.status() == QTextStream::Ok) {
setQueryTextChanged(false);
result = true;
}
}
return result;
}
QString QueryTool::promptUserForSaveSqlFilename()
{
QString home_dir = QStandardPaths::locate(QStandardPaths::HomeLocation, "", QStandardPaths::LocateDirectory);
return QFileDialog::getSaveFileName(this, tr("Save query"), home_dir, tr("SQL file (*.sql)"));
}
void QueryTool::queryTextChanged()
{
setQueryTextChanged(true);
m_context->setTitleForWidget(this, title, m_document->fileName());
}
void QueryTool::connectionStateChanged()
@ -618,10 +519,3 @@ void QueryTool::exportData()
exportDataToFilename(file_name);
}
void QueryTool::setQueryTextChanged(bool queryTextChanged)
{
if (m_queryTextChanged != queryTextChanged) {
m_queryTextChanged = queryTextChanged;
updateTitle();
}
}