Close subwindows gracefully, prompt save on quit

This commit is contained in:
GriffinR 2024-02-08 16:00:55 -05:00
parent a960456c6e
commit b60e54c07c
8 changed files with 100 additions and 72 deletions

View file

@ -43,7 +43,7 @@ public:
public: public:
Ui::MainWindow* ui; Ui::MainWindow* ui;
QObject *parent = nullptr; QObject *parent = nullptr;
Project *project = nullptr; QPointer<Project> project = nullptr;
Map *map = nullptr; Map *map = nullptr;
Settings *settings; Settings *settings;
void saveProject(); void saveProject();

View file

@ -295,7 +295,7 @@ private slots:
public: public:
Ui::MainWindow *ui; Ui::MainWindow *ui;
Editor *editor = nullptr; QPointer<Editor> editor = nullptr;
private: private:
QLabel *label_MapRulerStatus = nullptr; QLabel *label_MapRulerStatus = nullptr;
@ -331,7 +331,6 @@ private:
bool isProgrammaticEventTabChange; bool isProgrammaticEventTabChange;
bool projectHasUnsavedChanges; bool projectHasUnsavedChanges;
bool projectOpenFailure = false;
bool newMapDefaultsSet = false; bool newMapDefaultsSet = false;
MapSortOrder mapSortOrder; MapSortOrder mapSortOrder;
@ -348,7 +347,9 @@ private:
void openSubWindow(QWidget * window); void openSubWindow(QWidget * window);
QString getExistingDirectory(QString); QString getExistingDirectory(QString);
bool openProject(const QString &dir, bool initial = false); bool openProject(const QString &dir, bool initial = false);
bool closeProject();
void showProjectOpenFailure(); void showProjectOpenFailure();
void saveGlobalConfigs();
bool setInitialMap(); bool setInitialMap();
void setRecentMap(QString map_name); void setRecentMap(QString map_name);
QStandardItem* createMapItem(QString mapName, int groupNum, int inGroupNum); QStandardItem* createMapItem(QString mapName, int groupNum, int inGroupNum);
@ -379,7 +380,7 @@ private:
void setTheme(QString); void setTheme(QString);
void updateTilesetEditor(); void updateTilesetEditor();
Event::Group getEventGroupFromTabWidget(QWidget *tab); Event::Group getEventGroupFromTabWidget(QWidget *tab);
void closeSupplementaryWindows(); bool closeSupplementaryWindows();
void setWindowDisabled(bool); void setWindowDisabled(bool);
void initTilesetEditor(); void initTilesetEditor();

View file

@ -79,10 +79,11 @@ void Editor::saveUiFields() {
} }
void Editor::closeProject() { void Editor::closeProject() {
if (this->project) { if (!this->project)
delete this->project; return;
this->project = nullptr;
} Scripting::cb_ProjectClosed(this->project->root);
delete this->project;
} }
void Editor::setEditingMap() { void Editor::setEditingMap() {

View file

@ -71,6 +71,7 @@ MainWindow::MainWindow(QWidget *parent) :
MainWindow::~MainWindow() MainWindow::~MainWindow()
{ {
delete label_MapRulerStatus; delete label_MapRulerStatus;
delete editor;
delete ui; delete ui;
} }
@ -477,8 +478,12 @@ void MainWindow::setTheme(QString theme) {
} }
bool MainWindow::openProject(const QString &dir, bool initial) { bool MainWindow::openProject(const QString &dir, bool initial) {
if (!this->closeProject()) {
logInfo("Aborted project open.");
return false;
}
if (dir.isNull() || dir.length() <= 0) { if (dir.isNull() || dir.length() <= 0) {
projectOpenFailure = true;
if (!initial) setWindowDisabled(true); if (!initial) setWindowDisabled(true);
return false; return false;
} }
@ -486,7 +491,6 @@ bool MainWindow::openProject(const QString &dir, bool initial) {
const QString projectString = QString("%1project '%2'").arg(initial ? "recent " : "").arg(QDir::toNativeSeparators(dir)); const QString projectString = QString("%1project '%2'").arg(initial ? "recent " : "").arg(QDir::toNativeSeparators(dir));
if (!QDir(dir).exists()) { if (!QDir(dir).exists()) {
projectOpenFailure = true;
const QString errorMsg = QString("Failed to open %1: No such directory").arg(projectString); const QString errorMsg = QString("Failed to open %1: No such directory").arg(projectString);
this->statusBar()->showMessage(errorMsg); this->statusBar()->showMessage(errorMsg);
if (initial) { if (initial) {
@ -503,43 +507,30 @@ bool MainWindow::openProject(const QString &dir, bool initial) {
this->statusBar()->showMessage(openMessage); this->statusBar()->showMessage(openMessage);
logInfo(openMessage); logInfo(openMessage);
// TODO: Don't save these yet
userConfig.setProjectDir(dir); userConfig.setProjectDir(dir);
userConfig.load(); userConfig.load();
projectConfig.setProjectDir(dir); projectConfig.setProjectDir(dir);
projectConfig.load(); projectConfig.load();
this->closeSupplementaryWindows();
this->newMapDefaultsSet = false; this->newMapDefaultsSet = false;
if (isProjectOpen())
Scripting::cb_ProjectClosed(editor->project->root);
Scripting::init(this); Scripting::init(this);
bool already_open = isProjectOpen() && (editor->project->root == dir); this->editor->project = new Project(this);
if (!already_open) { QObject::connect(this->editor->project, &Project::reloadProject, this, &MainWindow::on_action_Reload_Project_triggered);
editor->closeProject(); QObject::connect(this->editor->project, &Project::mapCacheCleared, this, &MainWindow::onMapCacheCleared);
editor->project = new Project(this); QObject::connect(this->editor->project, &Project::uncheckMonitorFilesAction, [this]() {
QObject::connect(editor->project, &Project::reloadProject, this, &MainWindow::on_action_Reload_Project_triggered); porymapConfig.setMonitorFiles(false);
QObject::connect(editor->project, &Project::mapCacheCleared, this, &MainWindow::onMapCacheCleared); if (this->preferenceEditor)
QObject::connect(editor->project, &Project::uncheckMonitorFilesAction, [this]() { this->preferenceEditor->updateFields();
porymapConfig.setMonitorFiles(false); });
if (this->preferenceEditor) this->editor->project->set_root(dir);
this->preferenceEditor->updateFields();
});
editor->project->set_root(dir);
} else {
editor->project->fileWatcher.removePaths(editor->project->fileWatcher.files());
editor->project->clearMapCache();
editor->project->clearTilesetCache();
}
this->projectOpenFailure = !(loadDataStructures() if (!(loadDataStructures() && populateMapList() && setInitialMap())) {
&& populateMapList()
&& setInitialMap());
if (this->projectOpenFailure) {
this->statusBar()->showMessage(QString("Failed to open %1").arg(projectString)); this->statusBar()->showMessage(QString("Failed to open %1").arg(projectString));
showProjectOpenFailure(); showProjectOpenFailure();
delete this->editor->project;
return false; return false;
} }
@ -568,7 +559,7 @@ void MainWindow::showProjectOpenFailure() {
} }
bool MainWindow::isProjectOpen() { bool MainWindow::isProjectOpen() {
return !projectOpenFailure && editor && editor->project; return editor && editor->project;
} }
bool MainWindow::setInitialMap() { bool MainWindow::setInitialMap() {
@ -1228,12 +1219,10 @@ void MainWindow::openNewMapPopupWindow() {
} }
if (!this->newMapPrompt) { if (!this->newMapPrompt) {
this->newMapPrompt = new NewMapPopup(this, this->editor->project); this->newMapPrompt = new NewMapPopup(this, this->editor->project);
connect(this->newMapPrompt, &NewMapPopup::applied, this, &MainWindow::onNewMapCreated);
} }
openSubWindow(this->newMapPrompt); openSubWindow(this->newMapPrompt);
connect(this->newMapPrompt, &NewMapPopup::applied, this, &MainWindow::onNewMapCreated);
this->newMapPrompt->setAttribute(Qt::WA_DeleteOnClose);
} }
void MainWindow::on_action_NewMap_triggered() { void MainWindow::on_action_NewMap_triggered() {
@ -1751,11 +1740,6 @@ void MainWindow::on_mapViewTab_tabBarClicked(int index)
editor->setCursorRectVisible(false); editor->setCursorRectVisible(false);
} }
void MainWindow::on_action_Exit_triggered()
{
QApplication::quit();
}
void MainWindow::on_mainTabBar_tabBarClicked(int index) void MainWindow::on_mainTabBar_tabBarClicked(int index)
{ {
int oldIndex = ui->mainTabBar->currentIndex(); int oldIndex = ui->mainTabBar->currentIndex();
@ -2486,11 +2470,8 @@ void MainWindow::importMapFromAdvanceMap1_92()
void MainWindow::showExportMapImageWindow(ImageExporterMode mode) { void MainWindow::showExportMapImageWindow(ImageExporterMode mode) {
if (!editor->project) return; if (!editor->project) return;
if (this->mapImageExporter) if (!this->mapImageExporter)
delete this->mapImageExporter; this->mapImageExporter = new MapImageExporter(this, this->editor, mode);
this->mapImageExporter = new MapImageExporter(this, this->editor, mode);
this->mapImageExporter->setAttribute(Qt::WA_DeleteOnClose);
openSubWindow(this->mapImageExporter); openSubWindow(this->mapImageExporter);
} }
@ -2923,36 +2904,59 @@ bool MainWindow::initRegionMapEditor(bool silent) {
return true; return true;
} }
void MainWindow::closeSupplementaryWindows() { // Attempt to close any open sub-windows of the main window, giving each a chance to abort the process.
delete this->tilesetEditor; // Each of these are expected to be a QPointer to a widget with WA_DeleteOnClose set, so manually deleting
delete this->regionMapEditor; // and nullifying the pointer members is not necessary here.
delete this->mapImageExporter; // TODO: Testing
delete this->newMapPrompt; bool MainWindow::closeSupplementaryWindows() {
delete this->shortcutsEditor; if (this->tilesetEditor && !this->tilesetEditor->close())
delete this->customScriptsEditor; return false;
if (this->regionMapEditor && !this->regionMapEditor->close())
return false;
if (this->mapImageExporter && !this->mapImageExporter->close())
return false;
if (this->newMapPrompt && !this->newMapPrompt->close())
return false;
if (this->shortcutsEditor && !this->shortcutsEditor->close())
return false;
if (this->preferenceEditor && !this->preferenceEditor->close())
return false;
if (this->customScriptsEditor && !this->customScriptsEditor->close())
return false;
if (this->projectSettingsEditor) this->projectSettingsEditor->closeQuietly(); if (this->projectSettingsEditor) this->projectSettingsEditor->closeQuietly();
return true;
} }
void MainWindow::closeEvent(QCloseEvent *event) { bool MainWindow::closeProject() {
if (isProjectOpen()) { if (!closeSupplementaryWindows())
if (projectHasUnsavedChanges || (editor->map && editor->map->hasUnsavedChanges())) { return false;
QMessageBox::StandardButton result = QMessageBox::question(
this, "porymap", "The project has been modified, save changes?",
QMessageBox::No | QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes);
if (result == QMessageBox::Yes) { if (!isProjectOpen())
editor->saveProject(); return true;
} else if (result == QMessageBox::No) {
logWarn("Closing porymap with unsaved changes."); if (projectHasUnsavedChanges || (editor->map && editor->map->hasUnsavedChanges())) {
} else if (result == QMessageBox::Cancel) { QMessageBox::StandardButton result = QMessageBox::question(
event->ignore(); this, "porymap", "The project has been modified, save changes?",
return; QMessageBox::No | QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes);
}
if (result == QMessageBox::Yes) {
editor->saveProject();
} else if (result == QMessageBox::No) {
logWarn("Closing project with unsaved changes.");
} else if (result == QMessageBox::Cancel) {
return false;
} }
projectConfig.save();
userConfig.save();
} }
projectConfig.save();
userConfig.save();
editor->closeProject();
return true;
}
void MainWindow::saveGlobalConfigs() {
porymapConfig.setMainGeometry( porymapConfig.setMainGeometry(
this->saveGeometry(), this->saveGeometry(),
this->saveState(), this->saveState(),
@ -2962,6 +2966,24 @@ void MainWindow::closeEvent(QCloseEvent *event) {
); );
porymapConfig.save(); porymapConfig.save();
shortcutsConfig.save(); shortcutsConfig.save();
}
void MainWindow::on_action_Exit_triggered() {
if (!closeProject())
return;
saveGlobalConfigs();
QApplication::quit();
}
void MainWindow::closeEvent(QCloseEvent *event) {
if (!closeProject()) {
event->ignore();
return;
}
saveGlobalConfigs();
QMainWindow::closeEvent(event); QMainWindow::closeEvent(event);
} }

View file

@ -27,6 +27,7 @@ MapImageExporter::MapImageExporter(QWidget *parent_, Editor *editor_, ImageExpor
QDialog(parent_), QDialog(parent_),
ui(new Ui::MapImageExporter) ui(new Ui::MapImageExporter)
{ {
this->setAttribute(Qt::WA_DeleteOnClose);
ui->setupUi(this); ui->setupUi(this);
this->map = editor_->map; this->map = editor_->map;
this->editor = editor_; this->editor = editor_;

View file

@ -14,6 +14,7 @@ NewMapPopup::NewMapPopup(QWidget *parent, Project *project) :
QMainWindow(parent), QMainWindow(parent),
ui(new Ui::NewMapPopup) ui(new Ui::NewMapPopup)
{ {
this->setAttribute(Qt::WA_DeleteOnClose);
ui->setupUi(this); ui->setupUi(this);
this->project = project; this->project = project;
this->existingLayout = false; this->existingLayout = false;

View file

@ -26,6 +26,7 @@ RegionMapEditor::RegionMapEditor(QWidget *parent, Project *project) :
QMainWindow(parent), QMainWindow(parent),
ui(new Ui::RegionMapEditor) ui(new Ui::RegionMapEditor)
{ {
this->setAttribute(Qt::WA_DeleteOnClose);
this->ui->setupUi(this); this->ui->setupUi(this);
this->project = project; this->project = project;
this->initShortcuts(); this->initShortcuts();

View file

@ -20,6 +20,7 @@ TilesetEditor::TilesetEditor(Project *project, Map *map, QWidget *parent) :
map(map), map(map),
hasUnsavedChanges(false) hasUnsavedChanges(false)
{ {
this->setAttribute(Qt::WA_DeleteOnClose);
this->setTilesets(this->map->layout->tileset_primary_label, this->map->layout->tileset_secondary_label); this->setTilesets(this->map->layout->tileset_primary_label, this->map->layout->tileset_secondary_label);
this->initUi(); this->initUi();
} }