pgLab/pglab/querytool/UnsavedDocumentsDialog.cpp
eelke 784ad68758 Show UnsavedDocumentsDialog when closing window or quitting application
so user can save and or discard docs more efficiently.
2026-10-19 18:16:25 +02:00

112 lines
3.4 KiB
C++

#include "UnsavedDocumentsDialog.h"
#include <QDialogButtonBox>
#include <QListWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QLabel>
#include <algorithm>
UnsavedDocumentsDialog::UnsavedDocumentsDialog(const QList<std::shared_ptr<SqlDocument>> &docs, QWidget *parent)
: QDialog(parent)
, m_docs(docs)
, m_list(new QListWidget(this))
{
setWindowTitle(tr("Unsaved changes"));
auto layout = new QVBoxLayout(this);
layout->addWidget(new QLabel(tr("The following documents have unsaved changes. Select the documents to save or discard:"), this));
for (const auto &doc : m_docs) {
QStringList windows;
for (const QWidget *editor : doc->editors()) {
QString title = editor->window()->windowTitle();
if (!windows.contains(title))
windows.append(title);
}
auto item = new QListWidgetItem(QString("%1 (%2)").arg(doc->fileName(), windows.join(", ")), m_list);
item->setToolTip(doc->fileName());
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
item->setCheckState(Qt::Checked);
}
layout->addWidget(m_list);
auto buttons = new QDialogButtonBox(this);
auto save_button = buttons->addButton(tr("Save selected"), QDialogButtonBox::AcceptRole);
auto discard_button = buttons->addButton(tr("Discard selected"), QDialogButtonBox::DestructiveRole);
buttons->addButton(QDialogButtonBox::Cancel);
layout->addWidget(buttons);
connect(save_button, &QPushButton::clicked, this, [this]() {
m_choice = Choice::Save;
accept();
});
connect(discard_button, &QPushButton::clicked, this, [this]() {
m_choice = Choice::Discard;
accept();
});
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
}
QList<std::shared_ptr<SqlDocument>> UnsavedDocumentsDialog::checkedDocuments() const
{
QList<std::shared_ptr<SqlDocument>> result;
for (int i = 0; i < m_docs.size(); ++i) {
if (m_list->item(i)->checkState() == Qt::Checked)
result.append(m_docs[i]);
}
return result;
}
QList<std::shared_ptr<SqlDocument>> UnsavedDocumentsDialog::uncheckedDocuments() const
{
QList<std::shared_ptr<SqlDocument>> result;
for (int i = 0; i < m_docs.size(); ++i) {
if (m_list->item(i)->checkState() != Qt::Checked)
result.append(m_docs[i]);
}
return result;
}
QList<std::shared_ptr<SqlDocument>> documentsClosedWith(const QList<std::shared_ptr<SqlDocument>> &docs,
const std::function<bool(const QWidget*)> &isClosing)
{
QList<std::shared_ptr<SqlDocument>> result;
for (const auto &doc : docs) {
const auto &editors = doc->editors();
if (!doc->isModified() || editors.isEmpty())
continue;
bool all_closing = std::all_of(editors.begin(), editors.end(),
[&isClosing](const QWidget *editor) { return isClosing(editor); });
if (all_closing)
result.append(doc);
}
return result;
}
bool confirmClose(QWidget *parent, const QList<std::shared_ptr<SqlDocument>> &docs)
{
auto remaining = docs;
while (!remaining.isEmpty()) {
UnsavedDocumentsDialog dlg(remaining, parent);
if (dlg.exec() != QDialog::Accepted || dlg.choice() == UnsavedDocumentsDialog::Choice::Cancel)
return false;
bool save = dlg.choice() == UnsavedDocumentsDialog::Choice::Save;
for (const auto &doc : dlg.checkedDocuments()) {
if (save) {
if (!doc->save(parent))
return false;
}
else {
doc->setModified(false);
}
}
// Show the dialog again for the documents the user did not select.
remaining = dlg.uncheckedDocuments();
}
return true;
}