From 5ae95b88a94eee92e4581f96c96741db63a52055 Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de>
Date: Mon, 4 Mar 2024 13:11:56 +0100
Subject: [PATCH 01/18] Cloned GUI/View/Manager/ProjectManager ->
 GUI/Support/Data/Dirs

---
 GUI/Support/Data/Dirs.cpp | 451 ++++++++++++++++++++++++++++++++++++++
 GUI/Support/Data/Dirs.h   |  96 ++++++++
 2 files changed, 547 insertions(+)
 create mode 100644 GUI/Support/Data/Dirs.cpp
 create mode 100644 GUI/Support/Data/Dirs.h

diff --git a/GUI/Support/Data/Dirs.cpp b/GUI/Support/Data/Dirs.cpp
new file mode 100644
index 00000000000..ce26507323a
--- /dev/null
+++ b/GUI/Support/Data/Dirs.cpp
@@ -0,0 +1,451 @@
+//  ************************************************************************************************
+//
+//  BornAgain: simulate and fit reflection and scattering
+//
+//! @file      GUI/Support/Data/Dirs.cpp
+//! @brief     Implements class ProjectManager.
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2018
+//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
+//
+//  ************************************************************************************************
+
+#include "GUI/View/Manager/ProjectManager.h"
+#include "Base/Util/Assert.h"
+#include "GUI/Model/Project/ProjectUtil.h"
+#include "GUI/Support/Util/MessageService.h"
+#include "GUI/View/Info/MessageBox.h"
+#include "GUI/View/Layout/ApplicationSettings.h"
+#include "GUI/View/Layout/mainwindow_constants.h"
+#include "GUI/View/Manager/AutosaveController.h"
+#include "GUI/View/Manager/NewProjectDialog.h"
+#include "GUI/View/Manager/ProjectLoadProblemDialog.h"
+#include "GUI/View/Tool/Globals.h"
+#include <QApplication>
+#include <QDateTime>
+#include <QFileDialog>
+#include <QMessageBox>
+#include <QSettings>
+#include <memory>
+
+namespace {
+
+const QString S_PROJECTMANAGER = "ProjectManager";
+const QString S_AUTOSAVE = "EnableAutosave";
+const QString S_DEFAULTPROJECTPATH = "DefaultProjectPath";
+const QString S_RECENTPROJECTS = "RecentProjects";
+const QString S_LASTUSEDIMPORTDIR = "LastUsedImportDir";
+const QString S_LASTUSEDIMPORFILTER1D = "LastUsedImportFilter1D";
+const QString S_LASTUSEDIMPORFILTER2D = "LastUsedImportFilter2D";
+
+} // namespace
+
+
+ProjectManager* ProjectManager::s_instance = nullptr;
+
+ProjectManager::ProjectManager(QObject* parent)
+    : QObject(parent)
+{
+    ASSERT(!s_instance); // it's a singleton
+    s_instance = this;
+}
+
+ProjectManager::~ProjectManager()
+{
+    s_instance = nullptr;
+    gDoc.release();
+}
+
+ProjectManager* ProjectManager::instance()
+{
+    ASSERT(s_instance);
+    return s_instance;
+}
+
+//! Reads settings of ProjectManager from global settings.
+
+void ProjectManager::readSettings()
+{
+    QSettings settings;
+    m_working_directory = QDir::homePath();
+    if (settings.childGroups().contains(S_PROJECTMANAGER)) {
+        settings.beginGroup(S_PROJECTMANAGER);
+
+        if (!settings.contains(S_AUTOSAVE))
+            settings.setValue(S_AUTOSAVE, true);
+
+        m_working_directory = settings.value(S_DEFAULTPROJECTPATH).toString();
+        m_recent_projects = settings.value(S_RECENTPROJECTS).toStringList();
+
+        if (settings.contains(S_LASTUSEDIMPORTDIR))
+            m_import_directory = settings.value(S_LASTUSEDIMPORTDIR, QString()).toString();
+
+        m_import_filter1D = settings.value(S_LASTUSEDIMPORFILTER1D, m_import_filter1D).toString();
+        m_import_filter2D = settings.value(S_LASTUSEDIMPORFILTER2D, m_import_filter2D).toString();
+
+        setAutosaveEnabled(settings.value(S_AUTOSAVE).toBool());
+
+        settings.endGroup();
+    }
+}
+
+//! Saves settings of ProjectManager in global settings.
+
+void ProjectManager::writeSettings()
+{
+    QSettings settings;
+    settings.beginGroup(S_PROJECTMANAGER);
+    settings.setValue(S_DEFAULTPROJECTPATH, m_working_directory);
+    settings.setValue(S_RECENTPROJECTS, m_recent_projects);
+
+    if (!m_import_directory.isEmpty())
+        settings.setValue(S_LASTUSEDIMPORTDIR, m_import_directory);
+    settings.setValue(S_LASTUSEDIMPORFILTER1D, m_import_filter1D);
+    settings.setValue(S_LASTUSEDIMPORFILTER2D, m_import_filter2D);
+
+    settings.endGroup();
+}
+
+//! Returns list of recent projects, validates if projects still exists on disk.
+
+QStringList ProjectManager::recentProjects()
+{
+    QStringList updatedList;
+    for (const QString& fname : m_recent_projects)
+        if (QFile fin(fname); fin.exists())
+            updatedList.append(fname);
+    m_recent_projects = updatedList;
+    return m_recent_projects;
+}
+
+//! Returns name of the current project directory.
+
+QString ProjectManager::projectDir() const
+{
+    if (gDoc)
+        return gDoc->validProjectDir();
+    return "";
+}
+
+//! Returns directory name which was used by the user to import files.
+
+QString ProjectManager::userImportDir() const
+{
+    if (m_import_directory.isEmpty()) {
+        if (gDoc)
+            return gDoc->userExportDir();
+        return "";
+    }
+    return m_import_directory;
+} //! Sets user import directory in system settings.
+
+void ProjectManager::setImportDir(const QString& dirname)
+{
+    m_import_directory = dirname;
+}
+
+//! Sets user import directory in system settings.
+
+void ProjectManager::setImportDirFromFilePath(const QString& filePath)
+{
+    m_import_directory = QFileInfo(filePath).absolutePath();
+}
+
+void ProjectManager::setRecentlyUsedImportFilter1D(const QString& filter)
+{
+    m_import_filter1D = filter;
+}
+
+void ProjectManager::setRecentlyUsedImportFilter2D(const QString& filter)
+{
+    m_import_filter2D = filter;
+}
+
+bool ProjectManager::isAutosaveEnabled() const
+{
+    return static_cast<bool>(m_autosave);
+}
+
+AutosaveController* ProjectManager::autosaveController() const
+{
+    return m_autosave.get();
+}
+
+void ProjectManager::setAutosaveEnabled(bool value)
+{
+    if (value)
+        m_autosave = std::make_unique<AutosaveController>();
+    else
+        m_autosave.reset();
+
+    QSettings settings;
+    settings.setValue(S_PROJECTMANAGER + "/" + S_AUTOSAVE, value);
+}
+
+//! Clears list of recent projects.
+
+void ProjectManager::clearRecentProjects()
+{
+    m_recent_projects.clear();
+    emit recentListModified();
+}
+
+//! Processes new project request (close old project, rise dialog for project name, create project).
+
+ProjectDocument* ProjectManager::newProject()
+{
+    if (!closeCurrentProject())
+        return nullptr;
+    createNewProject();
+    emit documentOpenedOrClosed(true);
+    return gDoc.get();
+}
+
+//! Processes close current project request. Call save/discard/cancel dialog, if necessary.
+//! Returns false if saving was canceled.
+
+bool ProjectManager::closeCurrentProject()
+{
+    if (!gDoc)
+        return true;
+
+    if (gDoc->isModified()) {
+        QMessageBox msgBox;
+        msgBox.setText("The project has been modified.");
+        msgBox.setInformativeText("Do you want to save your changes?");
+        msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
+        msgBox.setDefaultButton(QMessageBox::Save);
+
+        switch (msgBox.exec()) {
+        case QMessageBox::Save:
+            if (!saveProject())
+                return false;
+            break;
+        case QMessageBox::Discard:
+            break;
+        case QMessageBox::Cancel:
+            return false;
+        default:
+            break;
+        }
+    }
+
+    deleteCurrentProject();
+    emit documentOpenedOrClosed(false);
+    return true;
+}
+
+//! Processes save project request.
+
+bool ProjectManager::saveProject(QString projectPullPath)
+{
+    if (projectPullPath.isEmpty()) {
+        if (gDoc->hasValidNameAndPath())
+            projectPullPath = gDoc->projectFullPath();
+        else
+            projectPullPath = acquireProjectPullPath();
+    }
+
+    if (projectPullPath.isEmpty())
+        return false;
+
+    gDoc->setProjectName(GUI::Util::Project::projectName(projectPullPath));
+    gDoc->setProjectDir(GUI::Util::Project::projectDir(projectPullPath));
+
+    try {
+        gDoc->saveProjectFileWithData(projectPullPath);
+    } catch (const std::exception& ex) {
+        QString message = QString("Failed to save project under '%1'. \n\n").arg(projectPullPath);
+        message.append("Exception was thrown.\n\n");
+        message.append(ex.what());
+
+        QMessageBox::warning(GUI::Global::mainWindow, "Error while saving project", message);
+        return false;
+    }
+    addToRecentProjects();
+    return true;
+}
+
+//! Processes 'save project as' request.
+
+bool ProjectManager::saveProjectAs()
+{
+    QString projectFileName = acquireProjectPullPath();
+
+    if (projectFileName.isEmpty())
+        return false;
+
+    return saveProject(projectFileName);
+}
+
+//! Opens existing project. If fname is empty, will popup file selection dialog.
+
+void ProjectManager::openProject(QString projectPullPath)
+{
+    if (!closeCurrentProject())
+        return;
+
+    if (projectPullPath.isEmpty()) {
+        const QString ext = QString(GUI::Util::Project::projectFileExtension);
+        projectPullPath = QFileDialog::getOpenFileName(
+            GUI::Global::mainWindow, "Open project file", workingDirectory(),
+            "BornAgain project Files (*" + ext + ")", nullptr,
+            appSettings->useNativeFileDialog() ? QFileDialog::Options()
+                                               : QFileDialog::DontUseNativeDialog);
+        if (projectPullPath.isEmpty())
+            return;
+    }
+
+    createNewProject();
+    MessageService messageService;
+    const auto readResult = loadProject(projectPullPath, messageService);
+
+    if (readResult == ProjectDocument::ReadResult::ok)
+        addToRecentProjects();
+    else if (readResult == ProjectDocument::ReadResult::error) {
+        riseProjectLoadFailedDialog(messageService);
+        deleteCurrentProject();
+    } else if (readResult == ProjectDocument::ReadResult::warning) {
+        riseProjectLoadProblemDialog(messageService);
+        addToRecentProjects();
+    }
+    if (gDoc)
+        emit documentOpenedOrClosed(true);
+}
+
+//! Calls dialog window to define project path and name.
+
+void ProjectManager::createNewProject()
+{
+    if (gDoc)
+        throw std::runtime_error("ProjectManager::createNewProject -> Project already exists");
+
+    gDoc.reset(new ProjectDocument);
+
+    if (m_autosave)
+        m_autosave->setDocument(gDoc.get());
+
+    gDoc->setProjectName("Untitled");
+
+    connect(gDoc.get(), &ProjectDocument::modifiedStateChanged, this,
+            &ProjectManager::documentModified);
+}
+
+void ProjectManager::deleteCurrentProject()
+{
+    emit aboutToCloseDocument();
+    if (m_autosave)
+        m_autosave->removeAutosaveDir();
+    gDoc.release();
+}
+
+//! Load project data from file name. If autosave info exists, opens dialog for project restore.
+
+ProjectDocument::ReadResult ProjectManager::loadProject(const QString& fullPathAndName,
+                                                        MessageService& messageService)
+{
+    auto readResult = ProjectDocument::ReadResult::ok;
+
+    const bool useAutosave = GUI::Util::Project::hasAutosavedData(fullPathAndName);
+    const QString autosaveFullPath = GUI::Util::Project::autosaveFullPath(fullPathAndName);
+    if (qApp)
+        QApplication::setOverrideCursor(Qt::WaitCursor);
+    if (useAutosave && restoreProjectDialog(fullPathAndName, autosaveFullPath)) {
+        readResult = gDoc->loadProjectFileWithData(autosaveFullPath, messageService);
+        gDoc->setProjectFullPath(fullPathAndName);
+        // restored project should be marked by '*'
+        gDoc->setModified();
+    } else {
+        readResult = gDoc->loadProjectFileWithData(fullPathAndName, messageService);
+    }
+    if (qApp)
+        QApplication::restoreOverrideCursor();
+    return readResult;
+}
+
+//! Returns project file name from dialog. Returns empty string if dialog was canceled.
+
+QString ProjectManager::acquireProjectPullPath()
+{
+    NewProjectDialog dialog(GUI::Global::mainWindow, workingDirectory(), untitledProjectName());
+
+    if (dialog.exec() != QDialog::Accepted)
+        return "";
+
+    m_working_directory = dialog.getWorkingDirectory();
+
+    return dialog.getProjectFileName();
+}
+
+//! Add name of the current project to the name of recent projects
+
+void ProjectManager::addToRecentProjects()
+{
+    QString fname = gDoc->projectFullPath();
+    m_recent_projects.removeAll(fname);
+    m_recent_projects.prepend(fname);
+    while (m_recent_projects.size() > GUI::Style::MAX_RECENT_PROJECTS)
+        m_recent_projects.removeLast();
+
+    emit recentListModified();
+}
+
+//! Returns default project path.
+//! Will return 'Untitled' if the directory with such name doesn't exist in project
+//! path. Otherwise will return Untitled1, Untitled2 etc.
+
+QString ProjectManager::untitledProjectName()
+{
+    QString result = "Untitled";
+    QDir projectDir = workingDirectory() + "/" + result;
+    if (projectDir.exists()) {
+        for (size_t i = 1; i < 99; ++i) {
+            result = QString("Untitled") + QString::number(i);
+            projectDir.setPath(workingDirectory() + "/" + result);
+            if (!projectDir.exists())
+                break;
+        }
+    }
+    return result;
+}
+
+void ProjectManager::riseProjectLoadFailedDialog(const MessageService& messageService)
+{
+    QString message = QString("Failed to load the project '%1' \n\n").arg(gDoc->projectFullPath());
+
+    for (const auto& details : messageService.errors())
+        message.append(details + "\n");
+
+    QMessageBox::warning(GUI::Global::mainWindow, "Error while opening project file", message);
+}
+
+void ProjectManager::riseProjectLoadProblemDialog(const MessageService& messageService)
+{
+    auto* problemDialog = new ProjectLoadProblemDialog(messageService.warnings(true));
+    problemDialog->show();
+    problemDialog->raise();
+}
+
+//! Rises dialog if the project should be restored from autosave. Returns true, if yes.
+
+bool ProjectManager::restoreProjectDialog(const QString& projectFileName,
+                                          const QString autosaveName)
+{
+    const QString title("Recover project");
+    const QString lmProject =
+        QFileInfo(projectFileName).lastModified().toString("hh:mm:ss, MMMM d, yyyy");
+    const QString lmAutoSave =
+        QFileInfo(autosaveName).lastModified().toString("hh:mm:ss, MMMM d, yyyy");
+
+    QString message = QString("Project '%1' contains autosaved data.\n\n"
+                              "Project saved at %2\nAutosave from %3")
+                          .arg(GUI::Util::Project::projectName(projectFileName))
+                          .arg(lmProject)
+                          .arg(lmAutoSave);
+
+    return GUI::Message::question(GUI::Global::mainWindow, title, message,
+                                  "\nDo you want to restore from autosave?\n",
+                                  "Yes, please restore.", "No, keep loading original");
+}
diff --git a/GUI/Support/Data/Dirs.h b/GUI/Support/Data/Dirs.h
new file mode 100644
index 00000000000..cafc4739299
--- /dev/null
+++ b/GUI/Support/Data/Dirs.h
@@ -0,0 +1,96 @@
+//  ************************************************************************************************
+//
+//  BornAgain: simulate and fit reflection and scattering
+//
+//! @file      GUI/Support/Data/Dirs.h
+//! @brief     Defines class ProjectManager.
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2018
+//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
+//
+//  ************************************************************************************************
+
+#ifndef BORNAGAIN_GUI_SUPPORT_DATA_DIRS_H
+#define BORNAGAIN_GUI_SUPPORT_DATA_DIRS_H
+
+#include "GUI/Model/Project/ProjectDocument.h"
+
+class AutosaveController;
+
+//! Handles activity related to opening/save projects.
+
+class ProjectManager : public QObject {
+    Q_OBJECT
+public:
+    ProjectManager(QObject* parent);
+    ~ProjectManager() override;
+
+    static ProjectManager* instance();
+
+    void readSettings();
+    void writeSettings();
+
+    QStringList recentProjects();
+    QString projectDir() const;
+    QString userImportDir() const;
+    QString recentlyUsedImportFilter1D() const { return m_import_filter1D; }
+    QString recentlyUsedImportFilter2D() const { return m_import_filter2D; }
+    void setImportDir(const QString& dirname);
+    void setImportDirFromFilePath(const QString& filePath);
+    void setRecentlyUsedImportFilter1D(const QString& filter);
+    void setRecentlyUsedImportFilter2D(const QString& filter);
+
+    bool isAutosaveEnabled() const;
+    AutosaveController* autosaveController() const;
+
+signals:
+    void aboutToCloseDocument();
+    void documentOpenedOrClosed(bool opened);
+    void documentModified();
+    void recentListModified();
+
+public slots:
+    void setAutosaveEnabled(bool value);
+    void clearRecentProjects();
+    ProjectDocument* newProject();
+    bool closeCurrentProject();
+    bool saveProject(QString projectPullPath = "");
+    bool saveProjectAs();
+    void openProject(QString projectPullPath = "");
+
+private:
+    void createNewProject();
+    void deleteCurrentProject();
+    ProjectDocument::ReadResult loadProject(const QString& fullPathAndName,
+                                            MessageService& messageService);
+    QString acquireProjectPullPath();
+    void addToRecentProjects();
+
+    QString workingDirectory() { return m_working_directory; }
+    QString untitledProjectName();
+
+    void riseProjectLoadFailedDialog(const MessageService& messageService);
+    void riseProjectLoadProblemDialog(const MessageService& messageService);
+    bool restoreProjectDialog(const QString& projectFileName, QString autosaveName);
+
+    //!< Name of directory where project directory was created.
+    QString m_working_directory;
+
+    //!< Name of directory from there user prefer to import files
+    QString m_import_directory;
+
+    //! Recently used import filter for 1D files
+    QString m_import_filter1D;
+
+    //! Recently used import filter for 2D files
+    QString m_import_filter2D;
+
+    QStringList m_recent_projects;
+    std::unique_ptr<AutosaveController> m_autosave;
+
+    static ProjectManager* s_instance;
+};
+
+#endif // BORNAGAIN_GUI_SUPPORT_DATA_DIRS_H
-- 
GitLab


From fcc543c69c1c4bd678a177bc9233d940fa75bdcd Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de>
Date: Mon, 4 Mar 2024 13:33:39 +0100
Subject: [PATCH 02/18] src pair Dirs.* extracted from ProjectManager

---
 App/main.cpp              |   6 +
 GUI/Support/Data/Dirs.cpp | 392 ++------------------------------------
 GUI/Support/Data/Dirs.h   |  57 ++----
 3 files changed, 38 insertions(+), 417 deletions(-)

diff --git a/App/main.cpp b/App/main.cpp
index c35b994c080..5505eab5b38 100644
--- a/App/main.cpp
+++ b/App/main.cpp
@@ -14,6 +14,7 @@
 
 #include "App/AppOptions.h"
 #include "Base/Util/Assert.h"
+#include "GUI/Support/Data/Dirs.h"
 #include "GUI/Support/Util/Path.h"
 #include "GUI/View/Layout/ApplicationSettings.h"
 #include "GUI/View/Main/MainWindow.h"
@@ -28,6 +29,9 @@
 #include <QtGlobal>
 #include <iostream>
 
+// Global variables
+BA_GUI_API_ std::unique_ptr<Dirs> gDirs;
+
 void custom_terminate_handler()
 {
     try {
@@ -74,6 +78,8 @@ int main(int argc, char* argv[])
     if (!QDir().exists(dir))
         QDir().mkpath(dir);
 
+    gDirs = std::make_unique<Dirs>();
+
     MainWindow win;
     GUI::Global::mainWindow = &win;
 
diff --git a/GUI/Support/Data/Dirs.cpp b/GUI/Support/Data/Dirs.cpp
index ce26507323a..44eb199b2aa 100644
--- a/GUI/Support/Data/Dirs.cpp
+++ b/GUI/Support/Data/Dirs.cpp
@@ -3,7 +3,7 @@
 //  BornAgain: simulate and fit reflection and scattering
 //
 //! @file      GUI/Support/Data/Dirs.cpp
-//! @brief     Implements class ProjectManager.
+//! @brief     Implements class Dirs.
 //!
 //! @homepage  http://www.bornagainproject.org
 //! @license   GNU General Public License v3 or higher (see COPYING)
@@ -12,30 +12,16 @@
 //
 //  ************************************************************************************************
 
-#include "GUI/View/Manager/ProjectManager.h"
+#include "GUI/Support/Data/Dirs.h"
 #include "Base/Util/Assert.h"
-#include "GUI/Model/Project/ProjectUtil.h"
-#include "GUI/Support/Util/MessageService.h"
-#include "GUI/View/Info/MessageBox.h"
-#include "GUI/View/Layout/ApplicationSettings.h"
-#include "GUI/View/Layout/mainwindow_constants.h"
-#include "GUI/View/Manager/AutosaveController.h"
-#include "GUI/View/Manager/NewProjectDialog.h"
-#include "GUI/View/Manager/ProjectLoadProblemDialog.h"
-#include "GUI/View/Tool/Globals.h"
-#include <QApplication>
-#include <QDateTime>
-#include <QFileDialog>
-#include <QMessageBox>
+#include <QDir>
+#include <QFileInfo>
 #include <QSettings>
-#include <memory>
 
 namespace {
 
-const QString S_PROJECTMANAGER = "ProjectManager";
-const QString S_AUTOSAVE = "EnableAutosave";
+const QString S_DIRS = "Dirs";
 const QString S_DEFAULTPROJECTPATH = "DefaultProjectPath";
-const QString S_RECENTPROJECTS = "RecentProjects";
 const QString S_LASTUSEDIMPORTDIR = "LastUsedImportDir";
 const QString S_LASTUSEDIMPORFILTER1D = "LastUsedImportFilter1D";
 const QString S_LASTUSEDIMPORFILTER2D = "LastUsedImportFilter2D";
@@ -43,41 +29,26 @@ const QString S_LASTUSEDIMPORFILTER2D = "LastUsedImportFilter2D";
 } // namespace
 
 
-ProjectManager* ProjectManager::s_instance = nullptr;
-
-ProjectManager::ProjectManager(QObject* parent)
-    : QObject(parent)
-{
-    ASSERT(!s_instance); // it's a singleton
-    s_instance = this;
-}
-
-ProjectManager::~ProjectManager()
+Dirs::Dirs()
 {
-    s_instance = nullptr;
-    gDoc.release();
+    readSettings();
 }
 
-ProjectManager* ProjectManager::instance()
+Dirs::~Dirs()
 {
-    ASSERT(s_instance);
-    return s_instance;
+    writeSettings();
 }
 
-//! Reads settings of ProjectManager from global settings.
+//! Reads settings of Dirs from global settings.
 
-void ProjectManager::readSettings()
+void Dirs::readSettings()
 {
     QSettings settings;
     m_working_directory = QDir::homePath();
-    if (settings.childGroups().contains(S_PROJECTMANAGER)) {
-        settings.beginGroup(S_PROJECTMANAGER);
-
-        if (!settings.contains(S_AUTOSAVE))
-            settings.setValue(S_AUTOSAVE, true);
+    if (settings.childGroups().contains(S_DIRS)) {
+        settings.beginGroup(S_DIRS);
 
         m_working_directory = settings.value(S_DEFAULTPROJECTPATH).toString();
-        m_recent_projects = settings.value(S_RECENTPROJECTS).toStringList();
 
         if (settings.contains(S_LASTUSEDIMPORTDIR))
             m_import_directory = settings.value(S_LASTUSEDIMPORTDIR, QString()).toString();
@@ -85,20 +56,17 @@ void ProjectManager::readSettings()
         m_import_filter1D = settings.value(S_LASTUSEDIMPORFILTER1D, m_import_filter1D).toString();
         m_import_filter2D = settings.value(S_LASTUSEDIMPORFILTER2D, m_import_filter2D).toString();
 
-        setAutosaveEnabled(settings.value(S_AUTOSAVE).toBool());
-
         settings.endGroup();
     }
 }
 
-//! Saves settings of ProjectManager in global settings.
+//! Saves settings of Dirs in global settings.
 
-void ProjectManager::writeSettings()
+void Dirs::writeSettings()
 {
     QSettings settings;
-    settings.beginGroup(S_PROJECTMANAGER);
+    settings.beginGroup(S_DIRS);
     settings.setValue(S_DEFAULTPROJECTPATH, m_working_directory);
-    settings.setValue(S_RECENTPROJECTS, m_recent_projects);
 
     if (!m_import_directory.isEmpty())
         settings.setValue(S_LASTUSEDIMPORTDIR, m_import_directory);
@@ -108,344 +76,24 @@ void ProjectManager::writeSettings()
     settings.endGroup();
 }
 
-//! Returns list of recent projects, validates if projects still exists on disk.
-
-QStringList ProjectManager::recentProjects()
-{
-    QStringList updatedList;
-    for (const QString& fname : m_recent_projects)
-        if (QFile fin(fname); fin.exists())
-            updatedList.append(fname);
-    m_recent_projects = updatedList;
-    return m_recent_projects;
-}
-
-//! Returns name of the current project directory.
-
-QString ProjectManager::projectDir() const
-{
-    if (gDoc)
-        return gDoc->validProjectDir();
-    return "";
-}
-
-//! Returns directory name which was used by the user to import files.
-
-QString ProjectManager::userImportDir() const
-{
-    if (m_import_directory.isEmpty()) {
-        if (gDoc)
-            return gDoc->userExportDir();
-        return "";
-    }
-    return m_import_directory;
-} //! Sets user import directory in system settings.
-
-void ProjectManager::setImportDir(const QString& dirname)
+void Dirs::setImportDir(const QString& dirname)
 {
     m_import_directory = dirname;
 }
 
 //! Sets user import directory in system settings.
 
-void ProjectManager::setImportDirFromFilePath(const QString& filePath)
+void Dirs::setImportDirFromFilePath(const QString& filePath)
 {
     m_import_directory = QFileInfo(filePath).absolutePath();
 }
 
-void ProjectManager::setRecentlyUsedImportFilter1D(const QString& filter)
+void Dirs::setRecentlyUsedImportFilter1D(const QString& filter)
 {
     m_import_filter1D = filter;
 }
 
-void ProjectManager::setRecentlyUsedImportFilter2D(const QString& filter)
+void Dirs::setRecentlyUsedImportFilter2D(const QString& filter)
 {
     m_import_filter2D = filter;
 }
-
-bool ProjectManager::isAutosaveEnabled() const
-{
-    return static_cast<bool>(m_autosave);
-}
-
-AutosaveController* ProjectManager::autosaveController() const
-{
-    return m_autosave.get();
-}
-
-void ProjectManager::setAutosaveEnabled(bool value)
-{
-    if (value)
-        m_autosave = std::make_unique<AutosaveController>();
-    else
-        m_autosave.reset();
-
-    QSettings settings;
-    settings.setValue(S_PROJECTMANAGER + "/" + S_AUTOSAVE, value);
-}
-
-//! Clears list of recent projects.
-
-void ProjectManager::clearRecentProjects()
-{
-    m_recent_projects.clear();
-    emit recentListModified();
-}
-
-//! Processes new project request (close old project, rise dialog for project name, create project).
-
-ProjectDocument* ProjectManager::newProject()
-{
-    if (!closeCurrentProject())
-        return nullptr;
-    createNewProject();
-    emit documentOpenedOrClosed(true);
-    return gDoc.get();
-}
-
-//! Processes close current project request. Call save/discard/cancel dialog, if necessary.
-//! Returns false if saving was canceled.
-
-bool ProjectManager::closeCurrentProject()
-{
-    if (!gDoc)
-        return true;
-
-    if (gDoc->isModified()) {
-        QMessageBox msgBox;
-        msgBox.setText("The project has been modified.");
-        msgBox.setInformativeText("Do you want to save your changes?");
-        msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
-        msgBox.setDefaultButton(QMessageBox::Save);
-
-        switch (msgBox.exec()) {
-        case QMessageBox::Save:
-            if (!saveProject())
-                return false;
-            break;
-        case QMessageBox::Discard:
-            break;
-        case QMessageBox::Cancel:
-            return false;
-        default:
-            break;
-        }
-    }
-
-    deleteCurrentProject();
-    emit documentOpenedOrClosed(false);
-    return true;
-}
-
-//! Processes save project request.
-
-bool ProjectManager::saveProject(QString projectPullPath)
-{
-    if (projectPullPath.isEmpty()) {
-        if (gDoc->hasValidNameAndPath())
-            projectPullPath = gDoc->projectFullPath();
-        else
-            projectPullPath = acquireProjectPullPath();
-    }
-
-    if (projectPullPath.isEmpty())
-        return false;
-
-    gDoc->setProjectName(GUI::Util::Project::projectName(projectPullPath));
-    gDoc->setProjectDir(GUI::Util::Project::projectDir(projectPullPath));
-
-    try {
-        gDoc->saveProjectFileWithData(projectPullPath);
-    } catch (const std::exception& ex) {
-        QString message = QString("Failed to save project under '%1'. \n\n").arg(projectPullPath);
-        message.append("Exception was thrown.\n\n");
-        message.append(ex.what());
-
-        QMessageBox::warning(GUI::Global::mainWindow, "Error while saving project", message);
-        return false;
-    }
-    addToRecentProjects();
-    return true;
-}
-
-//! Processes 'save project as' request.
-
-bool ProjectManager::saveProjectAs()
-{
-    QString projectFileName = acquireProjectPullPath();
-
-    if (projectFileName.isEmpty())
-        return false;
-
-    return saveProject(projectFileName);
-}
-
-//! Opens existing project. If fname is empty, will popup file selection dialog.
-
-void ProjectManager::openProject(QString projectPullPath)
-{
-    if (!closeCurrentProject())
-        return;
-
-    if (projectPullPath.isEmpty()) {
-        const QString ext = QString(GUI::Util::Project::projectFileExtension);
-        projectPullPath = QFileDialog::getOpenFileName(
-            GUI::Global::mainWindow, "Open project file", workingDirectory(),
-            "BornAgain project Files (*" + ext + ")", nullptr,
-            appSettings->useNativeFileDialog() ? QFileDialog::Options()
-                                               : QFileDialog::DontUseNativeDialog);
-        if (projectPullPath.isEmpty())
-            return;
-    }
-
-    createNewProject();
-    MessageService messageService;
-    const auto readResult = loadProject(projectPullPath, messageService);
-
-    if (readResult == ProjectDocument::ReadResult::ok)
-        addToRecentProjects();
-    else if (readResult == ProjectDocument::ReadResult::error) {
-        riseProjectLoadFailedDialog(messageService);
-        deleteCurrentProject();
-    } else if (readResult == ProjectDocument::ReadResult::warning) {
-        riseProjectLoadProblemDialog(messageService);
-        addToRecentProjects();
-    }
-    if (gDoc)
-        emit documentOpenedOrClosed(true);
-}
-
-//! Calls dialog window to define project path and name.
-
-void ProjectManager::createNewProject()
-{
-    if (gDoc)
-        throw std::runtime_error("ProjectManager::createNewProject -> Project already exists");
-
-    gDoc.reset(new ProjectDocument);
-
-    if (m_autosave)
-        m_autosave->setDocument(gDoc.get());
-
-    gDoc->setProjectName("Untitled");
-
-    connect(gDoc.get(), &ProjectDocument::modifiedStateChanged, this,
-            &ProjectManager::documentModified);
-}
-
-void ProjectManager::deleteCurrentProject()
-{
-    emit aboutToCloseDocument();
-    if (m_autosave)
-        m_autosave->removeAutosaveDir();
-    gDoc.release();
-}
-
-//! Load project data from file name. If autosave info exists, opens dialog for project restore.
-
-ProjectDocument::ReadResult ProjectManager::loadProject(const QString& fullPathAndName,
-                                                        MessageService& messageService)
-{
-    auto readResult = ProjectDocument::ReadResult::ok;
-
-    const bool useAutosave = GUI::Util::Project::hasAutosavedData(fullPathAndName);
-    const QString autosaveFullPath = GUI::Util::Project::autosaveFullPath(fullPathAndName);
-    if (qApp)
-        QApplication::setOverrideCursor(Qt::WaitCursor);
-    if (useAutosave && restoreProjectDialog(fullPathAndName, autosaveFullPath)) {
-        readResult = gDoc->loadProjectFileWithData(autosaveFullPath, messageService);
-        gDoc->setProjectFullPath(fullPathAndName);
-        // restored project should be marked by '*'
-        gDoc->setModified();
-    } else {
-        readResult = gDoc->loadProjectFileWithData(fullPathAndName, messageService);
-    }
-    if (qApp)
-        QApplication::restoreOverrideCursor();
-    return readResult;
-}
-
-//! Returns project file name from dialog. Returns empty string if dialog was canceled.
-
-QString ProjectManager::acquireProjectPullPath()
-{
-    NewProjectDialog dialog(GUI::Global::mainWindow, workingDirectory(), untitledProjectName());
-
-    if (dialog.exec() != QDialog::Accepted)
-        return "";
-
-    m_working_directory = dialog.getWorkingDirectory();
-
-    return dialog.getProjectFileName();
-}
-
-//! Add name of the current project to the name of recent projects
-
-void ProjectManager::addToRecentProjects()
-{
-    QString fname = gDoc->projectFullPath();
-    m_recent_projects.removeAll(fname);
-    m_recent_projects.prepend(fname);
-    while (m_recent_projects.size() > GUI::Style::MAX_RECENT_PROJECTS)
-        m_recent_projects.removeLast();
-
-    emit recentListModified();
-}
-
-//! Returns default project path.
-//! Will return 'Untitled' if the directory with such name doesn't exist in project
-//! path. Otherwise will return Untitled1, Untitled2 etc.
-
-QString ProjectManager::untitledProjectName()
-{
-    QString result = "Untitled";
-    QDir projectDir = workingDirectory() + "/" + result;
-    if (projectDir.exists()) {
-        for (size_t i = 1; i < 99; ++i) {
-            result = QString("Untitled") + QString::number(i);
-            projectDir.setPath(workingDirectory() + "/" + result);
-            if (!projectDir.exists())
-                break;
-        }
-    }
-    return result;
-}
-
-void ProjectManager::riseProjectLoadFailedDialog(const MessageService& messageService)
-{
-    QString message = QString("Failed to load the project '%1' \n\n").arg(gDoc->projectFullPath());
-
-    for (const auto& details : messageService.errors())
-        message.append(details + "\n");
-
-    QMessageBox::warning(GUI::Global::mainWindow, "Error while opening project file", message);
-}
-
-void ProjectManager::riseProjectLoadProblemDialog(const MessageService& messageService)
-{
-    auto* problemDialog = new ProjectLoadProblemDialog(messageService.warnings(true));
-    problemDialog->show();
-    problemDialog->raise();
-}
-
-//! Rises dialog if the project should be restored from autosave. Returns true, if yes.
-
-bool ProjectManager::restoreProjectDialog(const QString& projectFileName,
-                                          const QString autosaveName)
-{
-    const QString title("Recover project");
-    const QString lmProject =
-        QFileInfo(projectFileName).lastModified().toString("hh:mm:ss, MMMM d, yyyy");
-    const QString lmAutoSave =
-        QFileInfo(autosaveName).lastModified().toString("hh:mm:ss, MMMM d, yyyy");
-
-    QString message = QString("Project '%1' contains autosaved data.\n\n"
-                              "Project saved at %2\nAutosave from %3")
-                          .arg(GUI::Util::Project::projectName(projectFileName))
-                          .arg(lmProject)
-                          .arg(lmAutoSave);
-
-    return GUI::Message::question(GUI::Global::mainWindow, title, message,
-                                  "\nDo you want to restore from autosave?\n",
-                                  "Yes, please restore.", "No, keep loading original");
-}
diff --git a/GUI/Support/Data/Dirs.h b/GUI/Support/Data/Dirs.h
index cafc4739299..884f11c2f90 100644
--- a/GUI/Support/Data/Dirs.h
+++ b/GUI/Support/Data/Dirs.h
@@ -3,7 +3,7 @@
 //  BornAgain: simulate and fit reflection and scattering
 //
 //! @file      GUI/Support/Data/Dirs.h
-//! @brief     Defines class ProjectManager.
+//! @brief     Defines class Dirs.
 //!
 //! @homepage  http://www.bornagainproject.org
 //! @license   GNU General Public License v3 or higher (see COPYING)
@@ -15,26 +15,19 @@
 #ifndef BORNAGAIN_GUI_SUPPORT_DATA_DIRS_H
 #define BORNAGAIN_GUI_SUPPORT_DATA_DIRS_H
 
-#include "GUI/Model/Project/ProjectDocument.h"
-
-class AutosaveController;
+#include "Wrap/WinDllMacros.h"
+#include <QStringList>
 
 //! Handles activity related to opening/save projects.
 
-class ProjectManager : public QObject {
-    Q_OBJECT
+class Dirs {
 public:
-    ProjectManager(QObject* parent);
-    ~ProjectManager() override;
+    Dirs();
+    ~Dirs();
 
-    static ProjectManager* instance();
+    static Dirs* instance();
 
-    void readSettings();
-    void writeSettings();
 
-    QStringList recentProjects();
-    QString projectDir() const;
-    QString userImportDir() const;
     QString recentlyUsedImportFilter1D() const { return m_import_filter1D; }
     QString recentlyUsedImportFilter2D() const { return m_import_filter2D; }
     void setImportDir(const QString& dirname);
@@ -42,38 +35,11 @@ public:
     void setRecentlyUsedImportFilter1D(const QString& filter);
     void setRecentlyUsedImportFilter2D(const QString& filter);
 
-    bool isAutosaveEnabled() const;
-    AutosaveController* autosaveController() const;
-
-signals:
-    void aboutToCloseDocument();
-    void documentOpenedOrClosed(bool opened);
-    void documentModified();
-    void recentListModified();
-
-public slots:
-    void setAutosaveEnabled(bool value);
-    void clearRecentProjects();
-    ProjectDocument* newProject();
-    bool closeCurrentProject();
-    bool saveProject(QString projectPullPath = "");
-    bool saveProjectAs();
-    void openProject(QString projectPullPath = "");
-
 private:
-    void createNewProject();
-    void deleteCurrentProject();
-    ProjectDocument::ReadResult loadProject(const QString& fullPathAndName,
-                                            MessageService& messageService);
-    QString acquireProjectPullPath();
-    void addToRecentProjects();
+    void readSettings();
+    void writeSettings();
 
     QString workingDirectory() { return m_working_directory; }
-    QString untitledProjectName();
-
-    void riseProjectLoadFailedDialog(const MessageService& messageService);
-    void riseProjectLoadProblemDialog(const MessageService& messageService);
-    bool restoreProjectDialog(const QString& projectFileName, QString autosaveName);
 
     //!< Name of directory where project directory was created.
     QString m_working_directory;
@@ -88,9 +54,10 @@ private:
     QString m_import_filter2D;
 
     QStringList m_recent_projects;
-    std::unique_ptr<AutosaveController> m_autosave;
 
-    static ProjectManager* s_instance;
+    static Dirs* s_instance;
 };
 
+BA_GUI_API_ extern std::unique_ptr<Dirs> gDirs;
+
 #endif // BORNAGAIN_GUI_SUPPORT_DATA_DIRS_H
-- 
GitLab


From 32d05181397539f33b5e29beddddaae01b7e0b4e Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de>
Date: Mon, 4 Mar 2024 14:21:57 +0100
Subject: [PATCH 03/18] ...

---
 App/main.cpp                           |  3 --
 GUI/Support/Data/Dirs.cpp              | 20 +++++++--
 GUI/Support/Data/Dirs.h                | 10 +----
 GUI/View/Loader/DataLoader.cpp         | 17 ++++----
 GUI/View/Manager/ProjectManager.cpp    | 58 +++-----------------------
 GUI/View/Manager/ProjectManager.h      | 19 ---------
 GUI/View/Manager/PyImportAssistant.cpp |  6 +--
 7 files changed, 36 insertions(+), 97 deletions(-)

diff --git a/App/main.cpp b/App/main.cpp
index 5505eab5b38..0a7aabb5f72 100644
--- a/App/main.cpp
+++ b/App/main.cpp
@@ -29,9 +29,6 @@
 #include <QtGlobal>
 #include <iostream>
 
-// Global variables
-BA_GUI_API_ std::unique_ptr<Dirs> gDirs;
-
 void custom_terminate_handler()
 {
     try {
diff --git a/GUI/Support/Data/Dirs.cpp b/GUI/Support/Data/Dirs.cpp
index 44eb199b2aa..bcef548b9ce 100644
--- a/GUI/Support/Data/Dirs.cpp
+++ b/GUI/Support/Data/Dirs.cpp
@@ -28,6 +28,7 @@ const QString S_LASTUSEDIMPORFILTER2D = "LastUsedImportFilter2D";
 
 } // namespace
 
+BA_GUI_API_ std::unique_ptr<Dirs> gDirs;
 
 Dirs::Dirs()
 {
@@ -44,12 +45,9 @@ Dirs::~Dirs()
 void Dirs::readSettings()
 {
     QSettings settings;
-    m_working_directory = QDir::homePath();
     if (settings.childGroups().contains(S_DIRS)) {
         settings.beginGroup(S_DIRS);
 
-        m_working_directory = settings.value(S_DEFAULTPROJECTPATH).toString();
-
         if (settings.contains(S_LASTUSEDIMPORTDIR))
             m_import_directory = settings.value(S_LASTUSEDIMPORTDIR, QString()).toString();
 
@@ -66,7 +64,6 @@ void Dirs::writeSettings()
 {
     QSettings settings;
     settings.beginGroup(S_DIRS);
-    settings.setValue(S_DEFAULTPROJECTPATH, m_working_directory);
 
     if (!m_import_directory.isEmpty())
         settings.setValue(S_LASTUSEDIMPORTDIR, m_import_directory);
@@ -76,6 +73,21 @@ void Dirs::writeSettings()
     settings.endGroup();
 }
 
+//! Returns directory name which was used by the user to import files.
+
+QString Dirs::userImportDir() const
+{
+    /*
+    if (m_import_directory.isEmpty()) {
+        if (gDoc)
+            return gDoc->userExportDir();
+        return "";
+    }
+    */
+    return m_import_directory;
+} //! Sets user import directory in system settings.
+
+
 void Dirs::setImportDir(const QString& dirname)
 {
     m_import_directory = dirname;
diff --git a/GUI/Support/Data/Dirs.h b/GUI/Support/Data/Dirs.h
index 884f11c2f90..fa03176c1ca 100644
--- a/GUI/Support/Data/Dirs.h
+++ b/GUI/Support/Data/Dirs.h
@@ -25,11 +25,10 @@ public:
     Dirs();
     ~Dirs();
 
-    static Dirs* instance();
-
-
+    QString userImportDir() const;
     QString recentlyUsedImportFilter1D() const { return m_import_filter1D; }
     QString recentlyUsedImportFilter2D() const { return m_import_filter2D; }
+
     void setImportDir(const QString& dirname);
     void setImportDirFromFilePath(const QString& filePath);
     void setRecentlyUsedImportFilter1D(const QString& filter);
@@ -39,11 +38,6 @@ private:
     void readSettings();
     void writeSettings();
 
-    QString workingDirectory() { return m_working_directory; }
-
-    //!< Name of directory where project directory was created.
-    QString m_working_directory;
-
     //!< Name of directory from there user prefer to import files
     QString m_import_directory;
 
diff --git a/GUI/View/Loader/DataLoader.cpp b/GUI/View/Loader/DataLoader.cpp
index 95c64abb680..146e7c0f1cc 100644
--- a/GUI/View/Loader/DataLoader.cpp
+++ b/GUI/View/Loader/DataLoader.cpp
@@ -19,6 +19,7 @@
 #include "Device/IO/ZipUtil.h"
 #include "GUI/Model/Data/DataItem.h"
 #include "GUI/Model/Device/DatafileItem.h"
+#include "GUI/Support/Data/Dirs.h"
 #include "GUI/View/Info/MessageBox.h"
 #include "GUI/View/Layout/ApplicationSettings.h"
 #include "GUI/View/Loader/ImportDialogs.h"
@@ -64,8 +65,8 @@ std::vector<DatafileItem*> RW::importData1D()
 
     static const QString filters = ::join_filterkeys(filters1D, ";;");
 
-    QString selectedFilter = ProjectManager::instance()->recentlyUsedImportFilter1D();
-    const QString dirname = ProjectManager::instance()->userImportDir();
+    QString selectedFilter = gDirs->recentlyUsedImportFilter1D();
+    const QString dirname = gDirs->userImportDir();
 
     const QStringList fnames = QFileDialog::getOpenFileNames(
         Q_NULLPTR, "Open Intensity Files", dirname, filters, &selectedFilter,
@@ -74,8 +75,8 @@ std::vector<DatafileItem*> RW::importData1D()
     if (fnames.isEmpty())
         return {};
 
-    ProjectManager::instance()->setImportDirFromFilePath(fnames[0]);
-    ProjectManager::instance()->setRecentlyUsedImportFilter1D(selectedFilter);
+    gDirs->setImportDirFromFilePath(fnames[0]);
+    gDirs->setRecentlyUsedImportFilter1D(selectedFilter);
 
     const IO::Filetype1D global_ftype = ::filterkey2type(filters1D, selectedFilter);
 
@@ -125,8 +126,8 @@ std::vector<DatafileItem*> RW::importData2D()
 
     static const QString filters = ::join_filterkeys(filters2D, ";;");
 
-    QString selectedFilter = ProjectManager::instance()->recentlyUsedImportFilter2D();
-    const QString dirname = ProjectManager::instance()->userImportDir();
+    QString selectedFilter = gDirs->recentlyUsedImportFilter2D();
+    const QString dirname = gDirs->userImportDir();
 
     const QStringList fnames = QFileDialog::getOpenFileNames(
         Q_NULLPTR, "Open Intensity Files", dirname, filters, &selectedFilter,
@@ -135,8 +136,8 @@ std::vector<DatafileItem*> RW::importData2D()
     if (fnames.isEmpty())
         return {};
 
-    ProjectManager::instance()->setImportDirFromFilePath(fnames[0]);
-    ProjectManager::instance()->setRecentlyUsedImportFilter2D(selectedFilter);
+    gDirs->setImportDirFromFilePath(fnames[0]);
+    gDirs->setRecentlyUsedImportFilter2D(selectedFilter);
 
     const IO::Filetype2D global_ftype = ::filterkey2type(filters2D, selectedFilter);
 
diff --git a/GUI/View/Manager/ProjectManager.cpp b/GUI/View/Manager/ProjectManager.cpp
index 3e4506c2573..eef6eec561c 100644
--- a/GUI/View/Manager/ProjectManager.cpp
+++ b/GUI/View/Manager/ProjectManager.cpp
@@ -37,8 +37,6 @@ const QString S_AUTOSAVE = "EnableAutosave";
 const QString S_DEFAULTPROJECTPATH = "DefaultProjectPath";
 const QString S_RECENTPROJECTS = "RecentProjects";
 const QString S_LASTUSEDIMPORTDIR = "LastUsedImportDir";
-const QString S_LASTUSEDIMPORFILTER1D = "LastUsedImportFilter1D";
-const QString S_LASTUSEDIMPORFILTER2D = "LastUsedImportFilter2D";
 
 } // namespace
 
@@ -73,18 +71,13 @@ void ProjectManager::readSettings()
     if (settings.childGroups().contains(S_PROJECTMANAGER)) {
         settings.beginGroup(S_PROJECTMANAGER);
 
+        m_working_directory = settings.value(S_DEFAULTPROJECTPATH).toString();
+
         if (!settings.contains(S_AUTOSAVE))
             settings.setValue(S_AUTOSAVE, true);
 
-        m_working_directory = settings.value(S_DEFAULTPROJECTPATH).toString();
         m_recent_projects = settings.value(S_RECENTPROJECTS).toStringList();
 
-        if (settings.contains(S_LASTUSEDIMPORTDIR))
-            m_import_directory = settings.value(S_LASTUSEDIMPORTDIR, QString()).toString();
-
-        m_import_filter1D = settings.value(S_LASTUSEDIMPORFILTER1D, m_import_filter1D).toString();
-        m_import_filter2D = settings.value(S_LASTUSEDIMPORFILTER2D, m_import_filter2D).toString();
-
         setAutosaveEnabled(settings.value(S_AUTOSAVE).toBool());
 
         settings.endGroup();
@@ -100,11 +93,6 @@ void ProjectManager::writeSettings()
     settings.setValue(S_DEFAULTPROJECTPATH, m_working_directory);
     settings.setValue(S_RECENTPROJECTS, m_recent_projects);
 
-    if (!m_import_directory.isEmpty())
-        settings.setValue(S_LASTUSEDIMPORTDIR, m_import_directory);
-    settings.setValue(S_LASTUSEDIMPORFILTER1D, m_import_filter1D);
-    settings.setValue(S_LASTUSEDIMPORFILTER2D, m_import_filter2D);
-
     settings.endGroup();
 }
 
@@ -129,40 +117,6 @@ QString ProjectManager::projectDir() const
     return "";
 }
 
-//! Returns directory name which was used by the user to import files.
-
-QString ProjectManager::userImportDir() const
-{
-    if (m_import_directory.isEmpty()) {
-        if (gDoc)
-            return gDoc->userExportDir();
-        return "";
-    }
-    return m_import_directory;
-} //! Sets user import directory in system settings.
-
-void ProjectManager::setImportDir(const QString& dirname)
-{
-    m_import_directory = dirname;
-}
-
-//! Sets user import directory in system settings.
-
-void ProjectManager::setImportDirFromFilePath(const QString& filePath)
-{
-    m_import_directory = QFileInfo(filePath).absolutePath();
-}
-
-void ProjectManager::setRecentlyUsedImportFilter1D(const QString& filter)
-{
-    m_import_filter1D = filter;
-}
-
-void ProjectManager::setRecentlyUsedImportFilter2D(const QString& filter)
-{
-    m_import_filter2D = filter;
-}
-
 bool ProjectManager::isAutosaveEnabled() const
 {
     return static_cast<bool>(m_autosave);
@@ -290,7 +244,7 @@ void ProjectManager::openProject(QString projectPullPath)
     if (projectPullPath.isEmpty()) {
         const QString ext = QString(GUI::Util::Project::projectFileExtension);
         projectPullPath = QFileDialog::getOpenFileName(
-            GUI::Global::mainWindow, "Open project file", workingDirectory(),
+            GUI::Global::mainWindow, "Open project file", m_working_directory,
             "BornAgain project Files (*" + ext + ")", nullptr,
             appSettings->useNativeFileDialog() ? QFileDialog::Options()
                                                : QFileDialog::DontUseNativeDialog);
@@ -369,7 +323,7 @@ ProjectDocument::ReadResult ProjectManager::loadProject(const QString& fullPathA
 
 QString ProjectManager::acquireProjectPullPath()
 {
-    NewProjectDialog dialog(GUI::Global::mainWindow, workingDirectory(), untitledProjectName());
+    NewProjectDialog dialog(GUI::Global::mainWindow, m_working_directory, untitledProjectName());
 
     if (dialog.exec() != QDialog::Accepted)
         return "";
@@ -399,11 +353,11 @@ void ProjectManager::addToRecentProjects()
 QString ProjectManager::untitledProjectName()
 {
     QString result = "Untitled";
-    QDir projectDir = workingDirectory() + "/" + result;
+    QDir projectDir = m_working_directory + "/" + result;
     if (projectDir.exists()) {
         for (size_t i = 1; i < 99; ++i) {
             result = QString("Untitled") + QString::number(i);
-            projectDir.setPath(workingDirectory() + "/" + result);
+            projectDir.setPath(m_working_directory + "/" + result);
             if (!projectDir.exists())
                 break;
         }
diff --git a/GUI/View/Manager/ProjectManager.h b/GUI/View/Manager/ProjectManager.h
index 4857dc137df..38a2a540c33 100644
--- a/GUI/View/Manager/ProjectManager.h
+++ b/GUI/View/Manager/ProjectManager.h
@@ -34,13 +34,6 @@ public:
 
     QStringList recentProjects();
     QString projectDir() const;
-    QString userImportDir() const;
-    QString recentlyUsedImportFilter1D() const { return m_import_filter1D; }
-    QString recentlyUsedImportFilter2D() const { return m_import_filter2D; }
-    void setImportDir(const QString& dirname);
-    void setImportDirFromFilePath(const QString& filePath);
-    void setRecentlyUsedImportFilter1D(const QString& filter);
-    void setRecentlyUsedImportFilter2D(const QString& filter);
 
     bool isAutosaveEnabled() const;
     AutosaveController* autosaveController() const;
@@ -68,25 +61,13 @@ private:
     QString acquireProjectPullPath();
     void addToRecentProjects();
 
-    QString workingDirectory() { return m_working_directory; }
     QString untitledProjectName();
 
     void riseProjectLoadFailedDialog(const MessageService& messageService);
     void riseProjectLoadProblemDialog(const MessageService& messageService);
     bool restoreProjectDialog(const QString& projectFileName, QString autosaveName);
 
-    //!< Name of directory where project directory was created.
     QString m_working_directory;
-
-    //!< Name of directory from there user prefer to import files
-    QString m_import_directory;
-
-    //! Recently used import filter for 1D files
-    QString m_import_filter1D;
-
-    //! Recently used import filter for 2D files
-    QString m_import_filter2D;
-
     QStringList m_recent_projects;
     std::unique_ptr<AutosaveController> m_autosave;
 
diff --git a/GUI/View/Manager/PyImportAssistant.cpp b/GUI/View/Manager/PyImportAssistant.cpp
index bb321792d3a..05144ce83b6 100644
--- a/GUI/View/Manager/PyImportAssistant.cpp
+++ b/GUI/View/Manager/PyImportAssistant.cpp
@@ -21,13 +21,13 @@
 #include "GUI/Model/FromCore/ItemizeSample.h"
 #include "GUI/Model/FromCore/ItemizeSimulation.h"
 #include "GUI/Model/Project/ProjectUtil.h"
+#include "GUI/Support/Data/Dirs.h"
 #include "GUI/Support/Util/Path.h"
 #include "GUI/Support/Util/String.h"
 #include "GUI/View/Info/ComboSelectorDialog.h"
 #include "GUI/View/Info/DetailedMessageBox.h"
 #include "GUI/View/Info/MessageBox.h"
 #include "GUI/View/Layout/ApplicationSettings.h"
-#include "GUI/View/Manager/ProjectManager.h"
 #include "GUI/View/Tool/Globals.h"
 #include "PyCore/Embed/PyInterpreter.h"     // listOfFunctions
 #include "PyCore/Sample/ImportMultiLayer.h" // createMultiLayerFromPython
@@ -69,7 +69,7 @@ QString getCandidate(const QStringList& funcNames)
 
 QString fnameToOpen()
 {
-    QString dirname = ProjectManager::instance()->userImportDir();
+    QString dirname = gDirs->userImportDir();
 
     QString result = QFileDialog::getOpenFileName(
         GUI::Global::mainWindow, "Open python script", dirname, "Python scripts (*.py)", nullptr,
@@ -77,7 +77,7 @@ QString fnameToOpen()
                                            : QFileDialog::DontUseNativeDialog);
 
     if (!result.isEmpty())
-        ProjectManager::instance()->setImportDir(GUI::Path::fileDir(result));
+        gDirs->setImportDir(GUI::Path::fileDir(result));
 
     return result;
 }
-- 
GitLab


From 7c0f2db3b511cd1781846e42c3bcce7fc8051131 Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de>
Date: Mon, 4 Mar 2024 14:30:14 +0100
Subject: [PATCH 04/18] Dirs -> public variables

---
 GUI/Support/Data/Dirs.cpp      | 18 ++++--------------
 GUI/Support/Data/Dirs.h        | 13 +++----------
 GUI/View/Loader/DataLoader.cpp | 12 ++++--------
 3 files changed, 11 insertions(+), 32 deletions(-)

diff --git a/GUI/Support/Data/Dirs.cpp b/GUI/Support/Data/Dirs.cpp
index bcef548b9ce..7748eacf4b7 100644
--- a/GUI/Support/Data/Dirs.cpp
+++ b/GUI/Support/Data/Dirs.cpp
@@ -51,8 +51,8 @@ void Dirs::readSettings()
         if (settings.contains(S_LASTUSEDIMPORTDIR))
             m_import_directory = settings.value(S_LASTUSEDIMPORTDIR, QString()).toString();
 
-        m_import_filter1D = settings.value(S_LASTUSEDIMPORFILTER1D, m_import_filter1D).toString();
-        m_import_filter2D = settings.value(S_LASTUSEDIMPORFILTER2D, m_import_filter2D).toString();
+        import_filter_1D = settings.value(S_LASTUSEDIMPORFILTER1D, import_filter_1D).toString();
+        import_filter_2D = settings.value(S_LASTUSEDIMPORFILTER2D, import_filter_2D).toString();
 
         settings.endGroup();
     }
@@ -67,8 +67,8 @@ void Dirs::writeSettings()
 
     if (!m_import_directory.isEmpty())
         settings.setValue(S_LASTUSEDIMPORTDIR, m_import_directory);
-    settings.setValue(S_LASTUSEDIMPORFILTER1D, m_import_filter1D);
-    settings.setValue(S_LASTUSEDIMPORFILTER2D, m_import_filter2D);
+    settings.setValue(S_LASTUSEDIMPORFILTER1D, import_filter_1D);
+    settings.setValue(S_LASTUSEDIMPORFILTER2D, import_filter_2D);
 
     settings.endGroup();
 }
@@ -99,13 +99,3 @@ void Dirs::setImportDirFromFilePath(const QString& filePath)
 {
     m_import_directory = QFileInfo(filePath).absolutePath();
 }
-
-void Dirs::setRecentlyUsedImportFilter1D(const QString& filter)
-{
-    m_import_filter1D = filter;
-}
-
-void Dirs::setRecentlyUsedImportFilter2D(const QString& filter)
-{
-    m_import_filter2D = filter;
-}
diff --git a/GUI/Support/Data/Dirs.h b/GUI/Support/Data/Dirs.h
index fa03176c1ca..cfeeed91983 100644
--- a/GUI/Support/Data/Dirs.h
+++ b/GUI/Support/Data/Dirs.h
@@ -25,14 +25,13 @@ public:
     Dirs();
     ~Dirs();
 
+    QString import_filter_1D; //!< Last used import filter for 1D files
+    QString import_filter_2D; //!< Last used import filter for 2D files
+
     QString userImportDir() const;
-    QString recentlyUsedImportFilter1D() const { return m_import_filter1D; }
-    QString recentlyUsedImportFilter2D() const { return m_import_filter2D; }
 
     void setImportDir(const QString& dirname);
     void setImportDirFromFilePath(const QString& filePath);
-    void setRecentlyUsedImportFilter1D(const QString& filter);
-    void setRecentlyUsedImportFilter2D(const QString& filter);
 
 private:
     void readSettings();
@@ -41,12 +40,6 @@ private:
     //!< Name of directory from there user prefer to import files
     QString m_import_directory;
 
-    //! Recently used import filter for 1D files
-    QString m_import_filter1D;
-
-    //! Recently used import filter for 2D files
-    QString m_import_filter2D;
-
     QStringList m_recent_projects;
 
     static Dirs* s_instance;
diff --git a/GUI/View/Loader/DataLoader.cpp b/GUI/View/Loader/DataLoader.cpp
index 146e7c0f1cc..3a206f1bdbc 100644
--- a/GUI/View/Loader/DataLoader.cpp
+++ b/GUI/View/Loader/DataLoader.cpp
@@ -65,20 +65,18 @@ std::vector<DatafileItem*> RW::importData1D()
 
     static const QString filters = ::join_filterkeys(filters1D, ";;");
 
-    QString selectedFilter = gDirs->recentlyUsedImportFilter1D();
     const QString dirname = gDirs->userImportDir();
 
     const QStringList fnames = QFileDialog::getOpenFileNames(
-        Q_NULLPTR, "Open Intensity Files", dirname, filters, &selectedFilter,
+        Q_NULLPTR, "Open Intensity Files", dirname, filters, &gDirs->import_filter_1D,
         appSettings->useNativeFileDialog() ? QFileDialog::Options()
                                            : QFileDialog::DontUseNativeDialog);
     if (fnames.isEmpty())
         return {};
 
     gDirs->setImportDirFromFilePath(fnames[0]);
-    gDirs->setRecentlyUsedImportFilter1D(selectedFilter);
 
-    const IO::Filetype1D global_ftype = ::filterkey2type(filters1D, selectedFilter);
+    const IO::Filetype1D global_ftype = ::filterkey2type(filters1D, gDirs->import_filter_1D);
 
     std::vector<DatafileItem*> result;
     for (const QString& fname : fnames) {
@@ -126,20 +124,18 @@ std::vector<DatafileItem*> RW::importData2D()
 
     static const QString filters = ::join_filterkeys(filters2D, ";;");
 
-    QString selectedFilter = gDirs->recentlyUsedImportFilter2D();
     const QString dirname = gDirs->userImportDir();
 
     const QStringList fnames = QFileDialog::getOpenFileNames(
-        Q_NULLPTR, "Open Intensity Files", dirname, filters, &selectedFilter,
+        Q_NULLPTR, "Open Intensity Files", dirname, filters, &gDirs->import_filter_2D,
         appSettings->useNativeFileDialog() ? QFileDialog::Options()
                                            : QFileDialog::DontUseNativeDialog);
     if (fnames.isEmpty())
         return {};
 
     gDirs->setImportDirFromFilePath(fnames[0]);
-    gDirs->setRecentlyUsedImportFilter2D(selectedFilter);
 
-    const IO::Filetype2D global_ftype = ::filterkey2type(filters2D, selectedFilter);
+    const IO::Filetype2D global_ftype = ::filterkey2type(filters2D, gDirs->import_filter_2D);
 
     std::vector<DatafileItem*> result;
     for (const QString& fname : fnames) {
-- 
GitLab


From 3059e3d53e251311b8977d5cc24df4fc36a776f5 Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de>
Date: Mon, 4 Mar 2024 14:31:06 +0100
Subject: [PATCH 05/18] rm duplicate member

---
 GUI/Support/Data/Dirs.h | 2 --
 1 file changed, 2 deletions(-)

diff --git a/GUI/Support/Data/Dirs.h b/GUI/Support/Data/Dirs.h
index cfeeed91983..860f0072c0c 100644
--- a/GUI/Support/Data/Dirs.h
+++ b/GUI/Support/Data/Dirs.h
@@ -40,8 +40,6 @@ private:
     //!< Name of directory from there user prefer to import files
     QString m_import_directory;
 
-    QStringList m_recent_projects;
-
     static Dirs* s_instance;
 };
 
-- 
GitLab


From acdefa285b2cd000ba5111edb389bc62aa6a2299 Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de>
Date: Mon, 4 Mar 2024 14:33:25 +0100
Subject: [PATCH 06/18] rm unused

---
 GUI/Support/Data/Dirs.h | 2 --
 1 file changed, 2 deletions(-)

diff --git a/GUI/Support/Data/Dirs.h b/GUI/Support/Data/Dirs.h
index 860f0072c0c..a7b8652f2fb 100644
--- a/GUI/Support/Data/Dirs.h
+++ b/GUI/Support/Data/Dirs.h
@@ -39,8 +39,6 @@ private:
 
     //!< Name of directory from there user prefer to import files
     QString m_import_directory;
-
-    static Dirs* s_instance;
 };
 
 BA_GUI_API_ extern std::unique_ptr<Dirs> gDirs;
-- 
GitLab


From 1e29efdabeeed1f00de5db3d285a9585bc80bf68 Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de>
Date: Mon, 4 Mar 2024 14:35:23 +0100
Subject: [PATCH 07/18] rm include

---
 GUI/View/Loader/DataLoader.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/GUI/View/Loader/DataLoader.cpp b/GUI/View/Loader/DataLoader.cpp
index 3a206f1bdbc..35bbf2cc1f5 100644
--- a/GUI/View/Loader/DataLoader.cpp
+++ b/GUI/View/Loader/DataLoader.cpp
@@ -23,7 +23,6 @@
 #include "GUI/View/Info/MessageBox.h"
 #include "GUI/View/Layout/ApplicationSettings.h"
 #include "GUI/View/Loader/ImportDialogs.h"
-#include "GUI/View/Manager/ProjectManager.h"
 #include <QFileDialog>
 #include <QFileInfo>
 
-- 
GitLab


From a8b989b1884966e45aade503ea61a364cd35f854 Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de>
Date: Mon, 4 Mar 2024 14:54:11 +0100
Subject: [PATCH 08/18] rm Houston

---
 GUI/View/Info/CautionSignWidget.cpp    | 2 +-
 GUI/View/Realspace/RealspaceWidget.cpp | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/GUI/View/Info/CautionSignWidget.cpp b/GUI/View/Info/CautionSignWidget.cpp
index 612f6f5df9c..c857e0223ff 100644
--- a/GUI/View/Info/CautionSignWidget.cpp
+++ b/GUI/View/Info/CautionSignWidget.cpp
@@ -19,7 +19,7 @@
 CautionSignWidget::CautionSignWidget(QWidget* parent)
     : QWidget(parent)
     , m_pixmap(":/images/warning@2x.png")
-    , m_caution_header("Houston, we have a problem.")
+    , m_caution_header("BornAgain warning")
 {
     setAttribute(Qt::WA_NoSystemBackground);
     setToolTip(m_caution_header + "\nClick to see details.");
diff --git a/GUI/View/Realspace/RealspaceWidget.cpp b/GUI/View/Realspace/RealspaceWidget.cpp
index 389aa0a6dc1..a97fad24f36 100644
--- a/GUI/View/Realspace/RealspaceWidget.cpp
+++ b/GUI/View/Realspace/RealspaceWidget.cpp
@@ -100,7 +100,7 @@ void RealspaceWidget::savePicture()
         message.append(nameToSave);
         message.append("' has failed with following error message\n\n");
         message.append(QString::fromStdString(ex.what()));
-        QMessageBox::warning(nullptr, "Houston, we have a problem.", message);
+        QMessageBox::warning(nullptr, "Cannot save", message);
     }
 }
 
-- 
GitLab


From 16ea5979b9c161b4189ba27ba06947c3b4572c52 Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de>
Date: Mon, 4 Mar 2024 15:16:46 +0100
Subject: [PATCH 09/18] RealspaceWidget::savePicture simplify, standardize

---
 GUI/Support/Data/Dirs.cpp              |  1 +
 GUI/Support/Data/Dirs.h                |  1 +
 GUI/View/Realspace/RealspaceWidget.cpp | 34 +++++++++-----------------
 3 files changed, 14 insertions(+), 22 deletions(-)

diff --git a/GUI/Support/Data/Dirs.cpp b/GUI/Support/Data/Dirs.cpp
index 7748eacf4b7..e980006076c 100644
--- a/GUI/Support/Data/Dirs.cpp
+++ b/GUI/Support/Data/Dirs.cpp
@@ -32,6 +32,7 @@ BA_GUI_API_ std::unique_ptr<Dirs> gDirs;
 
 Dirs::Dirs()
 {
+    artifacts_export_dir = QDir::homePath();
     readSettings();
 }
 
diff --git a/GUI/Support/Data/Dirs.h b/GUI/Support/Data/Dirs.h
index a7b8652f2fb..fdd60268f3f 100644
--- a/GUI/Support/Data/Dirs.h
+++ b/GUI/Support/Data/Dirs.h
@@ -28,6 +28,7 @@ public:
     QString import_filter_1D; //!< Last used import filter for 1D files
     QString import_filter_2D; //!< Last used import filter for 2D files
 
+    QString artifacts_export_dir; //!< Last used directory to save image, script, ...
     QString userImportDir() const;
 
     void setImportDir(const QString& dirname);
diff --git a/GUI/View/Realspace/RealspaceWidget.cpp b/GUI/View/Realspace/RealspaceWidget.cpp
index a97fad24f36..b3413ae1b6b 100644
--- a/GUI/View/Realspace/RealspaceWidget.cpp
+++ b/GUI/View/Realspace/RealspaceWidget.cpp
@@ -15,15 +15,15 @@
 #include "GUI/View/Realspace/RealspaceWidget.h"
 #include "Base/Util/Assert.h"
 #include "GUI/Model/Material/MaterialItem.h"
-#include "GUI/Model/Project/ProjectDocument.h"
 #include "GUI/Model/Sample/SampleItem.h"
+#include "GUI/Support/Data/Dirs.h"
 #include "GUI/View/Info/CautionSign.h"
 #include "GUI/View/Layout/ApplicationSettings.h"
 #include "GUI/View/Realspace/RealspaceBuilder.h"
+#include "GUI/View/Widget/FileDialog.h"
 #include "Img3D/Model/Model.h"
 #include "Img3D/View/Canvas.h"
 #include <QApplication>
-#include <QFileDialog>
 #include <QMessageBox>
 #include <QVBoxLayout>
 
@@ -78,30 +78,20 @@ void RealspaceWidget::showEvent(QShowEvent*)
 
 void RealspaceWidget::savePicture()
 {
-    ASSERT(gDoc);
-    QString dirname = gDoc->userExportDir();
-    QString defaultExtension = ".png";
-    QString selectedFilter("*" + defaultExtension);
-    QString defaultName = dirname + "/untitled";
-    QString fname = QFileDialog::getSaveFileName(
-        nullptr, "Save 3D real space view", defaultName, selectedFilter, nullptr,
-        appSettings->useNativeFileDialog() ? QFileDialog::Options()
-                                           : QFileDialog::DontUseNativeDialog);
-    QString nameToSave = fname.endsWith(defaultExtension) ? fname : fname + defaultExtension;
-    if (nameToSave.isEmpty())
+    static const QString defaultExtension = ".png";
+    QString fname = GUI::Dialog::fileSaveDialog("Save 3D real space view",
+						gDirs->artifacts_export_dir,
+						"*" + defaultExtension);
+    if (fname.isEmpty())
         return;
+    if (!fname.endsWith(defaultExtension))
+	fname += defaultExtension;
 
     QPixmap pixmap(this->size());
     render(&pixmap, QPoint(), childrenRegion());
-    try {
-        pixmap.save(nameToSave);
-    } catch (const std::exception& ex) {
-        QString message = "Attempt to save file with the name '";
-        message.append(nameToSave);
-        message.append("' has failed with following error message\n\n");
-        message.append(QString::fromStdString(ex.what()));
-        QMessageBox::warning(nullptr, "Cannot save", message);
-    }
+    bool ok = pixmap.save(fname);
+    if (!ok)
+        QMessageBox::warning(nullptr, "Cannot save", "Cannot save picture in file " + fname);
 }
 
 void RealspaceWidget::updateScene()
-- 
GitLab


From ba8e85b916eb4722ed0c5d8f6740ecffd3720603 Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de>
Date: Mon, 4 Mar 2024 15:20:51 +0100
Subject: [PATCH 10/18] Settings + r/w artifact_export_dir

---
 GUI/Support/Data/Dirs.cpp              | 15 +++++++++------
 GUI/Support/Data/Dirs.h                |  2 +-
 GUI/View/Realspace/RealspaceWidget.cpp |  7 +++----
 3 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/GUI/Support/Data/Dirs.cpp b/GUI/Support/Data/Dirs.cpp
index e980006076c..3a9539a6c78 100644
--- a/GUI/Support/Data/Dirs.cpp
+++ b/GUI/Support/Data/Dirs.cpp
@@ -22,6 +22,7 @@ namespace {
 
 const QString S_DIRS = "Dirs";
 const QString S_DEFAULTPROJECTPATH = "DefaultProjectPath";
+const QString S_ARTIFACTEXPORTDIR = "ArtifactExportDir";
 const QString S_LASTUSEDIMPORTDIR = "LastUsedImportDir";
 const QString S_LASTUSEDIMPORFILTER1D = "LastUsedImportFilter1D";
 const QString S_LASTUSEDIMPORFILTER2D = "LastUsedImportFilter2D";
@@ -32,7 +33,7 @@ BA_GUI_API_ std::unique_ptr<Dirs> gDirs;
 
 Dirs::Dirs()
 {
-    artifacts_export_dir = QDir::homePath();
+    artifact_export_dir = QDir::homePath();
     readSettings();
 }
 
@@ -49,11 +50,13 @@ void Dirs::readSettings()
     if (settings.childGroups().contains(S_DIRS)) {
         settings.beginGroup(S_DIRS);
 
+        artifact_export_dir =
+            settings.value(S_LASTUSEDIMPORFILTER1D, artifact_export_dir).toString();
         if (settings.contains(S_LASTUSEDIMPORTDIR))
-            m_import_directory = settings.value(S_LASTUSEDIMPORTDIR, QString()).toString();
+            m_import_directory = settings.value(S_LASTUSEDIMPORTDIR, "").toString();
 
-        import_filter_1D = settings.value(S_LASTUSEDIMPORFILTER1D, import_filter_1D).toString();
-        import_filter_2D = settings.value(S_LASTUSEDIMPORFILTER2D, import_filter_2D).toString();
+        import_filter_1D = settings.value(S_LASTUSEDIMPORFILTER1D, "").toString();
+        import_filter_2D = settings.value(S_LASTUSEDIMPORFILTER2D, "").toString();
 
         settings.endGroup();
     }
@@ -66,8 +69,8 @@ void Dirs::writeSettings()
     QSettings settings;
     settings.beginGroup(S_DIRS);
 
-    if (!m_import_directory.isEmpty())
-        settings.setValue(S_LASTUSEDIMPORTDIR, m_import_directory);
+    settings.setValue(S_ARTIFACTEXPORTDIR, artifact_export_dir);
+    settings.setValue(S_LASTUSEDIMPORTDIR, m_import_directory);
     settings.setValue(S_LASTUSEDIMPORFILTER1D, import_filter_1D);
     settings.setValue(S_LASTUSEDIMPORFILTER2D, import_filter_2D);
 
diff --git a/GUI/Support/Data/Dirs.h b/GUI/Support/Data/Dirs.h
index fdd60268f3f..98817ab4e9f 100644
--- a/GUI/Support/Data/Dirs.h
+++ b/GUI/Support/Data/Dirs.h
@@ -28,7 +28,7 @@ public:
     QString import_filter_1D; //!< Last used import filter for 1D files
     QString import_filter_2D; //!< Last used import filter for 2D files
 
-    QString artifacts_export_dir; //!< Last used directory to save image, script, ...
+    QString artifact_export_dir; //!< Last used directory to save image, script, ...
     QString userImportDir() const;
 
     void setImportDir(const QString& dirname);
diff --git a/GUI/View/Realspace/RealspaceWidget.cpp b/GUI/View/Realspace/RealspaceWidget.cpp
index b3413ae1b6b..e6011a1143a 100644
--- a/GUI/View/Realspace/RealspaceWidget.cpp
+++ b/GUI/View/Realspace/RealspaceWidget.cpp
@@ -79,13 +79,12 @@ void RealspaceWidget::showEvent(QShowEvent*)
 void RealspaceWidget::savePicture()
 {
     static const QString defaultExtension = ".png";
-    QString fname = GUI::Dialog::fileSaveDialog("Save 3D real space view",
-						gDirs->artifacts_export_dir,
-						"*" + defaultExtension);
+    QString fname = GUI::Dialog::fileSaveDialog(
+        "Save 3D real space view", gDirs->artifact_export_dir, "*" + defaultExtension);
     if (fname.isEmpty())
         return;
     if (!fname.endsWith(defaultExtension))
-	fname += defaultExtension;
+        fname += defaultExtension;
 
     QPixmap pixmap(this->size());
     render(&pixmap, QPoint(), childrenRegion());
-- 
GitLab


From a3eadd80c4261504675932f12a723b93d9303a20 Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de>
Date: Mon, 4 Mar 2024 15:24:30 +0100
Subject: [PATCH 11/18] ProjectionsSaver std file dialog

---
 GUI/View/Loader/ProjectionsSaver.cpp | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/GUI/View/Loader/ProjectionsSaver.cpp b/GUI/View/Loader/ProjectionsSaver.cpp
index 07dfa942252..f764acfa314 100644
--- a/GUI/View/Loader/ProjectionsSaver.cpp
+++ b/GUI/View/Loader/ProjectionsSaver.cpp
@@ -19,8 +19,10 @@
 #include "GUI/Model/Data/Data2DItem.h"
 #include "GUI/Model/Mask/MasksSet.h"
 #include "GUI/Model/Project/ProjectDocument.h"
+#include "GUI/Support/Data/Dirs.h"
 #include "GUI/View/Layout/ApplicationSettings.h"
-#include <QFileDialog>
+#include "GUI/View/Widget/FileDialog.h"
+#include <QFile>
 #include <QString>
 #include <QTextStream>
 #include <QVector>
@@ -149,14 +151,9 @@ void GUI::IO::saveProjections(const Data2DItem* data_item)
 {
     if (!data_item)
         return;
-    ASSERT(gDoc);
-
-    QString defaultName = gDoc->userExportDir() + "/untitled.txt";
-    QString fname = QFileDialog::getSaveFileName(
-        nullptr, "Save projections data", defaultName, "", nullptr,
-        appSettings->useNativeFileDialog() ? QFileDialog::Options()
-                                           : QFileDialog::DontUseNativeDialog);
 
+    QString fname = GUI::Dialog::fileSaveDialog(
+        "Save projections data", gDirs->artifact_export_dir, "");
     if (fname.isEmpty())
         return;
 
-- 
GitLab


From d8cf220728d7092ce38bcf79a69b123bd56ffc74 Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de>
Date: Mon, 4 Mar 2024 15:33:27 +0100
Subject: [PATCH 12/18] std dialog in SavePlotAssistant; rm
 ProjectDocument::userExportDir

---
 GUI/Model/Project/ProjectDocument.cpp  |  9 --------
 GUI/Model/Project/ProjectDocument.h    |  1 -
 GUI/View/Canvas/MaskEditorCanvas.cpp   |  4 +---
 GUI/View/Canvas/SavePlotAssistant.cpp  | 29 ++++++++++++--------------
 GUI/View/Canvas/SavePlotAssistant.h    |  2 +-
 GUI/View/Canvas/SpecularDataCanvas.cpp |  4 +---
 6 files changed, 16 insertions(+), 33 deletions(-)

diff --git a/GUI/Model/Project/ProjectDocument.cpp b/GUI/Model/Project/ProjectDocument.cpp
index d2d37622d56..e40c55fe12c 100644
--- a/GUI/Model/Project/ProjectDocument.cpp
+++ b/GUI/Model/Project/ProjectDocument.cpp
@@ -89,15 +89,6 @@ void ProjectDocument::setProjectDir(const QString& text)
     m_project_dir = text;
 }
 
-//! Returns directory name suitable for saving plots.
-
-QString ProjectDocument::userExportDir() const
-{
-    if (QString dir = validProjectDir(); !dir.isEmpty())
-        return dir;
-    return QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
-}
-
 QString ProjectDocument::projectFullPath() const
 {
     if (!projectName().isEmpty())
diff --git a/GUI/Model/Project/ProjectDocument.h b/GUI/Model/Project/ProjectDocument.h
index af3ef835041..3ceb64892ea 100644
--- a/GUI/Model/Project/ProjectDocument.h
+++ b/GUI/Model/Project/ProjectDocument.h
@@ -62,7 +62,6 @@ public:
     QString projectName() const { return m_project_name; }
 
     QString validProjectDir() const;
-    QString userExportDir() const;
     QString projectFullPath() const;
     bool hasValidNameAndPath() const;
 
diff --git a/GUI/View/Canvas/MaskEditorCanvas.cpp b/GUI/View/Canvas/MaskEditorCanvas.cpp
index a241c7c5fa1..1b465aa6b19 100644
--- a/GUI/View/Canvas/MaskEditorCanvas.cpp
+++ b/GUI/View/Canvas/MaskEditorCanvas.cpp
@@ -126,9 +126,7 @@ void MaskEditorCanvas::onPresentationChange(bool pixelized)
 
 void MaskEditorCanvas::onSavePlotRequest()
 {
-    ASSERT(gDoc);
-    QString dirname = gDoc->userExportDir();
-    GUI::Plot::savePlot(dirname, m_scene->colorMap()->customPlot(), m_data_item->c_field());
+    GUI::Plot::savePlot(m_scene->colorMap()->customPlot(), m_data_item->c_field());
 }
 
 void MaskEditorCanvas::onPositionChanged(double x, double y)
diff --git a/GUI/View/Canvas/SavePlotAssistant.cpp b/GUI/View/Canvas/SavePlotAssistant.cpp
index b37c9f93fd0..7a38859fb87 100644
--- a/GUI/View/Canvas/SavePlotAssistant.cpp
+++ b/GUI/View/Canvas/SavePlotAssistant.cpp
@@ -15,9 +15,11 @@
 #include "GUI/View/Canvas/SavePlotAssistant.h"
 #include "Base/Util/Assert.h"
 #include "Device/IO/IOFactory.h"
+#include "GUI/Support/Data/Dirs.h"
 #include "GUI/View/Layout/ApplicationSettings.h"
 #include "GUI/View/Plotter/ColorMap.h"
-#include <QFileDialog>
+#include "GUI/View/Widget/FileDialog.h"
+#include <QFile>
 #include <QMessageBox>
 #include <QVector>
 #include <qcustomplot.h>
@@ -89,6 +91,7 @@ void saveToFile(const QString& fname, QCustomPlot* plot, const Datafield* output
     }
 }
 
+/*
 //! Returns string contraining all defined filters in the format suitable for QFileDialog
 QString getFilterString()
 {
@@ -126,29 +129,23 @@ QString composeFileName(const QString& fname, const QString& filterName)
         return fname;
     return fname + getExtensionFromFilterName(filterName);
 }
-
+*/
 } // namespace
 
 
-void GUI::Plot::savePlot(const QString& dirname, QCustomPlot* plot, const Datafield* output_data)
+void GUI::Plot::savePlot(QCustomPlot* plot, const Datafield* output_data)
 {
-    static QString selectedFilter = "*.png";
-    QString defaultName = dirname + "/untitled";
-    QString fname = QFileDialog::getSaveFileName(
-        nullptr, "Save Plot", defaultName, getFilterString(), &selectedFilter,
-        appSettings->useNativeFileDialog() ? QFileDialog::Options()
-                                           : QFileDialog::DontUseNativeDialog);
+    static const QString defaultExtension = ".png";
+    QString fname = GUI::Dialog::fileSaveDialog(
+        "Save Plot", gDirs->artifact_export_dir, "*" + defaultExtension);
     if (fname.isEmpty())
         return;
+    if (!fname.endsWith(defaultExtension))
+        fname += defaultExtension;
 
-    QString nameToSave = composeFileName(fname, selectedFilter);
     try {
-        ::saveToFile(nameToSave, plot, output_data);
+        ::saveToFile(fname, plot, output_data);
     } catch (const std::exception& ex) {
-        QString message = "Attempt to save file with the name '";
-        message.append(nameToSave);
-        message.append("' has failed with following error message\n\n");
-        message.append(QString::fromStdString(ex.what()));
-        QMessageBox::warning(nullptr, "Could not save", message);
+        QMessageBox::warning(nullptr, "Cannot save", "Cannot save picture in file " + fname);
     }
 }
diff --git a/GUI/View/Canvas/SavePlotAssistant.h b/GUI/View/Canvas/SavePlotAssistant.h
index 76d1914957b..476e34e3756 100644
--- a/GUI/View/Canvas/SavePlotAssistant.h
+++ b/GUI/View/Canvas/SavePlotAssistant.h
@@ -22,7 +22,7 @@ class QCustomPlot;
 
 namespace GUI::Plot {
 
-void savePlot(const QString& dirname, QCustomPlot* plot, const Datafield* output_data);
+void savePlot(QCustomPlot* plot, const Datafield* output_data);
 
 };
 
diff --git a/GUI/View/Canvas/SpecularDataCanvas.cpp b/GUI/View/Canvas/SpecularDataCanvas.cpp
index 7bee5abc149..89fa9148e62 100644
--- a/GUI/View/Canvas/SpecularDataCanvas.cpp
+++ b/GUI/View/Canvas/SpecularDataCanvas.cpp
@@ -75,9 +75,7 @@ void SpecularDataCanvas::onResetViewAction()
 
 void SpecularDataCanvas::onSavePlotAction()
 {
-    ASSERT(gDoc);
-    QString dirname = gDoc->userExportDir();
-    GUI::Plot::savePlot(dirname, m_plot_canvas->customPlot(), m_data_item->c_field());
+    GUI::Plot::savePlot(m_plot_canvas->customPlot(), m_data_item->c_field());
 }
 
 void SpecularDataCanvas::onMousePress(QMouseEvent* event)
-- 
GitLab


From 6f33bbf007d9c9dd71e29809ceb80ac7c37d5b1f Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de>
Date: Mon, 4 Mar 2024 15:55:21 +0100
Subject: [PATCH 13/18] gDIrs + script|data_import_dir

---
 GUI/Support/Data/Dirs.cpp              | 44 ++++++--------------------
 GUI/Support/Data/Dirs.h                | 11 ++-----
 GUI/View/Canvas/SavePlotAssistant.cpp  |  4 +--
 GUI/View/Loader/DataLoader.cpp         | 14 +++-----
 GUI/View/Loader/ProjectionsSaver.cpp   |  4 +--
 GUI/View/Manager/PyImportAssistant.cpp |  8 ++---
 GUI/View/Realspace/RealspaceWidget.cpp |  4 +--
 7 files changed, 24 insertions(+), 65 deletions(-)

diff --git a/GUI/Support/Data/Dirs.cpp b/GUI/Support/Data/Dirs.cpp
index 3a9539a6c78..ec29e3174c5 100644
--- a/GUI/Support/Data/Dirs.cpp
+++ b/GUI/Support/Data/Dirs.cpp
@@ -13,9 +13,7 @@
 //  ************************************************************************************************
 
 #include "GUI/Support/Data/Dirs.h"
-#include "Base/Util/Assert.h"
 #include <QDir>
-#include <QFileInfo>
 #include <QSettings>
 
 namespace {
@@ -23,7 +21,8 @@ namespace {
 const QString S_DIRS = "Dirs";
 const QString S_DEFAULTPROJECTPATH = "DefaultProjectPath";
 const QString S_ARTIFACTEXPORTDIR = "ArtifactExportDir";
-const QString S_LASTUSEDIMPORTDIR = "LastUsedImportDir";
+const QString S_DATAIMPORTDIR = "DataImportDir";
+const QString S_SCRIPTIMPORTDIR = "ScriptImportDir";
 const QString S_LASTUSEDIMPORFILTER1D = "LastUsedImportFilter1D";
 const QString S_LASTUSEDIMPORFILTER2D = "LastUsedImportFilter2D";
 
@@ -34,6 +33,8 @@ BA_GUI_API_ std::unique_ptr<Dirs> gDirs;
 Dirs::Dirs()
 {
     artifact_export_dir = QDir::homePath();
+    data_import_dir = QDir::homePath();
+    script_import_dir = QDir::homePath();
     readSettings();
 }
 
@@ -50,10 +51,9 @@ void Dirs::readSettings()
     if (settings.childGroups().contains(S_DIRS)) {
         settings.beginGroup(S_DIRS);
 
-        artifact_export_dir =
-            settings.value(S_LASTUSEDIMPORFILTER1D, artifact_export_dir).toString();
-        if (settings.contains(S_LASTUSEDIMPORTDIR))
-            m_import_directory = settings.value(S_LASTUSEDIMPORTDIR, "").toString();
+        artifact_export_dir = settings.value(S_ARTIFACTEXPORTDIR, artifact_export_dir).toString();
+        data_import_dir = settings.value(S_DATAIMPORTDIR, data_import_dir).toString();
+        script_import_dir = settings.value(S_SCRIPTIMPORTDIR, script_import_dir).toString();
 
         import_filter_1D = settings.value(S_LASTUSEDIMPORFILTER1D, "").toString();
         import_filter_2D = settings.value(S_LASTUSEDIMPORFILTER2D, "").toString();
@@ -70,36 +70,10 @@ void Dirs::writeSettings()
     settings.beginGroup(S_DIRS);
 
     settings.setValue(S_ARTIFACTEXPORTDIR, artifact_export_dir);
-    settings.setValue(S_LASTUSEDIMPORTDIR, m_import_directory);
+    settings.setValue(S_DATAIMPORTDIR, data_import_dir);
+    settings.setValue(S_SCRIPTIMPORTDIR, script_import_dir);
     settings.setValue(S_LASTUSEDIMPORFILTER1D, import_filter_1D);
     settings.setValue(S_LASTUSEDIMPORFILTER2D, import_filter_2D);
 
     settings.endGroup();
 }
-
-//! Returns directory name which was used by the user to import files.
-
-QString Dirs::userImportDir() const
-{
-    /*
-    if (m_import_directory.isEmpty()) {
-        if (gDoc)
-            return gDoc->userExportDir();
-        return "";
-    }
-    */
-    return m_import_directory;
-} //! Sets user import directory in system settings.
-
-
-void Dirs::setImportDir(const QString& dirname)
-{
-    m_import_directory = dirname;
-}
-
-//! Sets user import directory in system settings.
-
-void Dirs::setImportDirFromFilePath(const QString& filePath)
-{
-    m_import_directory = QFileInfo(filePath).absolutePath();
-}
diff --git a/GUI/Support/Data/Dirs.h b/GUI/Support/Data/Dirs.h
index 98817ab4e9f..cf2e016d023 100644
--- a/GUI/Support/Data/Dirs.h
+++ b/GUI/Support/Data/Dirs.h
@@ -16,7 +16,7 @@
 #define BORNAGAIN_GUI_SUPPORT_DATA_DIRS_H
 
 #include "Wrap/WinDllMacros.h"
-#include <QStringList>
+#include <QString>
 
 //! Handles activity related to opening/save projects.
 
@@ -29,17 +29,12 @@ public:
     QString import_filter_2D; //!< Last used import filter for 2D files
 
     QString artifact_export_dir; //!< Last used directory to save image, script, ...
-    QString userImportDir() const;
-
-    void setImportDir(const QString& dirname);
-    void setImportDirFromFilePath(const QString& filePath);
+    QString data_import_dir;     //!< Last data were imported from this directory
+    QString script_import_dir;   //!< Last script was imported from this directory
 
 private:
     void readSettings();
     void writeSettings();
-
-    //!< Name of directory from there user prefer to import files
-    QString m_import_directory;
 };
 
 BA_GUI_API_ extern std::unique_ptr<Dirs> gDirs;
diff --git a/GUI/View/Canvas/SavePlotAssistant.cpp b/GUI/View/Canvas/SavePlotAssistant.cpp
index 7a38859fb87..774b6a0e783 100644
--- a/GUI/View/Canvas/SavePlotAssistant.cpp
+++ b/GUI/View/Canvas/SavePlotAssistant.cpp
@@ -136,8 +136,8 @@ QString composeFileName(const QString& fname, const QString& filterName)
 void GUI::Plot::savePlot(QCustomPlot* plot, const Datafield* output_data)
 {
     static const QString defaultExtension = ".png";
-    QString fname = GUI::Dialog::fileSaveDialog(
-        "Save Plot", gDirs->artifact_export_dir, "*" + defaultExtension);
+    QString fname = GUI::Dialog::fileSaveDialog("Save Plot", gDirs->artifact_export_dir,
+                                                "*" + defaultExtension);
     if (fname.isEmpty())
         return;
     if (!fname.endsWith(defaultExtension))
diff --git a/GUI/View/Loader/DataLoader.cpp b/GUI/View/Loader/DataLoader.cpp
index 35bbf2cc1f5..a9c75e1ed53 100644
--- a/GUI/View/Loader/DataLoader.cpp
+++ b/GUI/View/Loader/DataLoader.cpp
@@ -64,17 +64,14 @@ std::vector<DatafileItem*> RW::importData1D()
 
     static const QString filters = ::join_filterkeys(filters1D, ";;");
 
-    const QString dirname = gDirs->userImportDir();
-
     const QStringList fnames = QFileDialog::getOpenFileNames(
-        Q_NULLPTR, "Open Intensity Files", dirname, filters, &gDirs->import_filter_1D,
+        Q_NULLPTR, "Open Intensity Files", gDirs->data_import_dir, filters,
+        &gDirs->import_filter_1D,
         appSettings->useNativeFileDialog() ? QFileDialog::Options()
                                            : QFileDialog::DontUseNativeDialog);
     if (fnames.isEmpty())
         return {};
 
-    gDirs->setImportDirFromFilePath(fnames[0]);
-
     const IO::Filetype1D global_ftype = ::filterkey2type(filters1D, gDirs->import_filter_1D);
 
     std::vector<DatafileItem*> result;
@@ -123,17 +120,14 @@ std::vector<DatafileItem*> RW::importData2D()
 
     static const QString filters = ::join_filterkeys(filters2D, ";;");
 
-    const QString dirname = gDirs->userImportDir();
-
     const QStringList fnames = QFileDialog::getOpenFileNames(
-        Q_NULLPTR, "Open Intensity Files", dirname, filters, &gDirs->import_filter_2D,
+        Q_NULLPTR, "Open Intensity Files", gDirs->data_import_dir, filters,
+        &gDirs->import_filter_2D,
         appSettings->useNativeFileDialog() ? QFileDialog::Options()
                                            : QFileDialog::DontUseNativeDialog);
     if (fnames.isEmpty())
         return {};
 
-    gDirs->setImportDirFromFilePath(fnames[0]);
-
     const IO::Filetype2D global_ftype = ::filterkey2type(filters2D, gDirs->import_filter_2D);
 
     std::vector<DatafileItem*> result;
diff --git a/GUI/View/Loader/ProjectionsSaver.cpp b/GUI/View/Loader/ProjectionsSaver.cpp
index f764acfa314..219987bd007 100644
--- a/GUI/View/Loader/ProjectionsSaver.cpp
+++ b/GUI/View/Loader/ProjectionsSaver.cpp
@@ -152,8 +152,8 @@ void GUI::IO::saveProjections(const Data2DItem* data_item)
     if (!data_item)
         return;
 
-    QString fname = GUI::Dialog::fileSaveDialog(
-        "Save projections data", gDirs->artifact_export_dir, "");
+    QString fname =
+        GUI::Dialog::fileSaveDialog("Save projections data", gDirs->artifact_export_dir, "");
     if (fname.isEmpty())
         return;
 
diff --git a/GUI/View/Manager/PyImportAssistant.cpp b/GUI/View/Manager/PyImportAssistant.cpp
index 05144ce83b6..54ab7632b4d 100644
--- a/GUI/View/Manager/PyImportAssistant.cpp
+++ b/GUI/View/Manager/PyImportAssistant.cpp
@@ -69,16 +69,12 @@ QString getCandidate(const QStringList& funcNames)
 
 QString fnameToOpen()
 {
-    QString dirname = gDirs->userImportDir();
-
     QString result = QFileDialog::getOpenFileName(
-        GUI::Global::mainWindow, "Open python script", dirname, "Python scripts (*.py)", nullptr,
+        GUI::Global::mainWindow, "Open python script", gDirs->script_import_dir,
+        "Python scripts (*.py)", nullptr,
         appSettings->useNativeFileDialog() ? QFileDialog::Options()
                                            : QFileDialog::DontUseNativeDialog);
 
-    if (!result.isEmpty())
-        gDirs->setImportDir(GUI::Path::fileDir(result));
-
     return result;
 }
 
diff --git a/GUI/View/Realspace/RealspaceWidget.cpp b/GUI/View/Realspace/RealspaceWidget.cpp
index e6011a1143a..f6e02bdcdbc 100644
--- a/GUI/View/Realspace/RealspaceWidget.cpp
+++ b/GUI/View/Realspace/RealspaceWidget.cpp
@@ -79,8 +79,8 @@ void RealspaceWidget::showEvent(QShowEvent*)
 void RealspaceWidget::savePicture()
 {
     static const QString defaultExtension = ".png";
-    QString fname = GUI::Dialog::fileSaveDialog(
-        "Save 3D real space view", gDirs->artifact_export_dir, "*" + defaultExtension);
+    QString fname = GUI::Dialog::fileSaveDialog("Save 3D real space view",
+                                                gDirs->artifact_export_dir, "*" + defaultExtension);
     if (fname.isEmpty())
         return;
     if (!fname.endsWith(defaultExtension))
-- 
GitLab


From a8d48154ce8bcb6efe2da917279edcc42995b5ca Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de>
Date: Mon, 4 Mar 2024 16:45:03 +0100
Subject: [PATCH 14/18] expand 'auto'

---
 GUI/Model/Job/JobsSet.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/GUI/Model/Job/JobsSet.cpp b/GUI/Model/Job/JobsSet.cpp
index d398071c616..a4726937137 100644
--- a/GUI/Model/Job/JobsSet.cpp
+++ b/GUI/Model/Job/JobsSet.cpp
@@ -88,7 +88,7 @@ void JobsSet::readFrom(QXmlStreamReader* r)
 
 void JobsSet::saveAllDatafields(const QString& projectDir) const
 {
-    for (const auto* job : *this)
+    for (const JobItem* job : *this)
         job->saveDatafields(projectDir);
 
     dataFilesCleaner.cleanOldFiles(projectDir, dataItems());
@@ -96,7 +96,7 @@ void JobsSet::saveAllDatafields(const QString& projectDir) const
 
 void JobsSet::loadAllDatafields(const QString& projectDir, MessageService* messageService)
 {
-    for (auto* job : *this)
+    for (JobItem* job : *this)
         job->loadDatafields(projectDir, messageService);
 
     dataFilesCleaner.recollectDataNames(dataItems());
-- 
GitLab


From be74faaf14e7502f2a67012868668cec228aa73d Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de>
Date: Mon, 4 Mar 2024 16:58:46 +0100
Subject: [PATCH 15/18] rm warnings mechanism from load datafiles

---
 GUI/Model/Data/DataItem.cpp           | 40 ++++++++++++---------------
 GUI/Model/Data/DataItem.h             |  3 +-
 GUI/Model/Device/DatafileItem.cpp     | 10 ++-----
 GUI/Model/Device/DatafileItem.h       |  3 +-
 GUI/Model/Files/DatafilesSet.cpp      |  4 +--
 GUI/Model/Files/DatafilesSet.h        |  3 +-
 GUI/Model/Job/JobItem.cpp             | 33 ++--------------------
 GUI/Model/Job/JobItem.h               |  2 +-
 GUI/Model/Job/JobsSet.cpp             |  4 +--
 GUI/Model/Job/JobsSet.h               |  3 +-
 GUI/Model/Project/ProjectDocument.cpp |  5 ++--
 11 files changed, 34 insertions(+), 76 deletions(-)

diff --git a/GUI/Model/Data/DataItem.cpp b/GUI/Model/Data/DataItem.cpp
index f22692525e0..5976cb1a050 100644
--- a/GUI/Model/Data/DataItem.cpp
+++ b/GUI/Model/Data/DataItem.cpp
@@ -19,7 +19,6 @@
 #include "Device/IO/IOFactory.h"
 #include "GUI/Model/Axis/AmplitudeAxisItem.h"
 #include "GUI/Model/Axis/BasicAxisItem.h"
-#include "GUI/Support/Util/MessageService.h"
 #include "GUI/Support/XML/UtilXML.h"
 #include <QFile>
 #include <utility>
@@ -83,31 +82,26 @@ void DataItem::setFileName(const QString& filename)
     emit fnameChanged(filename);
 }
 
-QString DataItem::loadDatafield(MessageService* messageService, const QString& projectDir, int rank)
+void DataItem::loadDatafield(const QString& projectDir, int rank)
 {
     if (!QFile::exists(projectDir))
-        return {};
-
-    ASSERT(messageService);
+        throw std::runtime_error("Cannot load datafield: project directory "
+				 + projectDir.toStdString() + " does not exist");
     const auto file = dataFullPath(projectDir);
-    try {
-        std::unique_ptr<Datafield> data;
-        if (rank == 1)
-            data = std::make_unique<Datafield>(
-                IO::readData1D(file.toStdString(), IO::Filetype1D::bornagain1D));
-        else if (rank == 2)
-            data = std::make_unique<Datafield>(
-                IO::readData2D(file.toStdString(), IO::Filetype2D::bornagain2D));
-        else
-            ASSERT_NEVER;
-        ASSERT(data);
-        setDatafield(*data);
-        m_last_saved = m_last_modified;
-    } catch (const std::exception& ex) {
-        messageService->addWarning(this, QString(ex.what()));
-        return ex.what();
-    }
-    return {};
+
+    std::unique_ptr<Datafield> data;
+    if (rank == 1)
+	data = std::make_unique<Datafield>(
+	    IO::readData1D(file.toStdString(), IO::Filetype1D::bornagain1D));
+    else if (rank == 2)
+	data = std::make_unique<Datafield>(
+	    IO::readData2D(file.toStdString(), IO::Filetype2D::bornagain2D));
+    else
+	ASSERT_NEVER;
+
+    ASSERT(data);
+    setDatafield(*data);
+    m_last_saved = m_last_modified;
 }
 
 void DataItem::saveDatafield(const QString& projectDir) const
diff --git a/GUI/Model/Data/DataItem.h b/GUI/Model/Data/DataItem.h
index d9d80557ebd..b0d8d97bfe3 100644
--- a/GUI/Model/Data/DataItem.h
+++ b/GUI/Model/Data/DataItem.h
@@ -24,7 +24,6 @@ class AmplitudeAxisItem;
 class BasicAxisItem;
 class Datafield;
 class Frame;
-class MessageService;
 
 //! Abstract base class for Data2DItem and Data1DItem.
 //! Owns one simulated data set of type Datafield.
@@ -59,7 +58,7 @@ public:
     QDateTime lastModified() const { return m_last_modified; }
     void setLastModified(const QDateTime& dtime);
 
-    QString loadDatafield(MessageService* messageService, const QString& projectDir, int rank);
+    void loadDatafield(const QString& projectDir, int rank);
     void saveDatafield(const QString& projectDir) const;
 
     // Number of bins in data
diff --git a/GUI/Model/Device/DatafileItem.cpp b/GUI/Model/Device/DatafileItem.cpp
index 36fa1f2f77e..4630ae4678b 100644
--- a/GUI/Model/Device/DatafileItem.cpp
+++ b/GUI/Model/Device/DatafileItem.cpp
@@ -201,14 +201,10 @@ void DatafileItem::saveDatafield(const QString& projectDir) const
         m_data_item->saveDatafield(projectDir);
 }
 
-QString DatafileItem::loadDatafield(const QString& projectDir, MessageService* messageService)
+void DatafileItem::loadDatafield(const QString& projectDir)
 {
-    if (m_data_item) {
-        QString dataError = m_data_item->loadDatafield(messageService, projectDir, rank());
-        if (!dataError.isEmpty())
-            return dataError;
-    }
-    return {};
+    if (m_data_item)
+        m_data_item->loadDatafield(projectDir, rank());
 }
 
 std::vector<int> DatafileItem::axdims() const
diff --git a/GUI/Model/Device/DatafileItem.h b/GUI/Model/Device/DatafileItem.h
index e2c4e8fed35..b54b5500466 100644
--- a/GUI/Model/Device/DatafileItem.h
+++ b/GUI/Model/Device/DatafileItem.h
@@ -24,7 +24,6 @@ class Data1DItem;
 class Data2DItem;
 class DataItem;
 class Datafield;
-class MessageService;
 
 //! Provides access to experimental data, for display and fitting.
 
@@ -59,7 +58,7 @@ public:
     void readFrom(QXmlStreamReader* r);
 
     void saveDatafield(const QString& projectDir) const;
-    QString loadDatafield(const QString& projectDir, MessageService* messageService);
+    void loadDatafield(const QString& projectDir);
 
     //... Other
 
diff --git a/GUI/Model/Files/DatafilesSet.cpp b/GUI/Model/Files/DatafilesSet.cpp
index 5dedd6ffe2b..18b7a3106b8 100644
--- a/GUI/Model/Files/DatafilesSet.cpp
+++ b/GUI/Model/Files/DatafilesSet.cpp
@@ -86,10 +86,10 @@ void DatafilesSet::writeDatafiles(const QString& projectDir) const
     dataFilesCleaner.cleanOldFiles(projectDir, dataItems());
 }
 
-void DatafilesSet::readDatafiles(const QString& projectDir, MessageService* messageService)
+void DatafilesSet::readDatafiles(const QString& projectDir)
 {
     for (auto* dfi : *this)
-        dfi->loadDatafield(projectDir, messageService);
+        dfi->loadDatafield(projectDir);
 
     dataFilesCleaner.recollectDataNames(dataItems());
 }
diff --git a/GUI/Model/Files/DatafilesSet.h b/GUI/Model/Files/DatafilesSet.h
index dc334989cad..ae012b6a3b9 100644
--- a/GUI/Model/Files/DatafilesSet.h
+++ b/GUI/Model/Files/DatafilesSet.h
@@ -21,7 +21,6 @@
 #include <QXmlStreamWriter>
 
 class DataItem;
-class MessageService;
 
 //! The DatafilesSet class is a model to store all imported DatafileItem's.
 class DatafilesSet : public SetWithModel<DatafileItem> {
@@ -30,7 +29,7 @@ public:
     virtual ~DatafilesSet();
 
     void readFrom(QXmlStreamReader* r);
-    void readDatafiles(const QString& projectDir, MessageService* messageService);
+    void readDatafiles(const QString& projectDir);
 
     void writeTo(QXmlStreamWriter* w) const;
     void writeDatafiles(const QString& projectDir) const;
diff --git a/GUI/Model/Job/JobItem.cpp b/GUI/Model/Job/JobItem.cpp
index 751988bdbe0..4036e21e0b7 100644
--- a/GUI/Model/Job/JobItem.cpp
+++ b/GUI/Model/Job/JobItem.cpp
@@ -371,40 +371,13 @@ void JobItem::saveDatafields(const QString& projectDir) const
         m_simulated_data_item->saveDatafield(projectDir);
 }
 
-void JobItem::loadDatafields(const QString& projectDir, MessageService* messageService)
+void JobItem::loadDatafields(const QString& projectDir)
 {
-    QString realError, simError, errorMessage;
-
     if (m_dfile_item)
-        realError = m_dfile_item->loadDatafield(projectDir, messageService);
+        m_dfile_item->loadDatafield(projectDir);
 
     if (m_simulated_data_item)
-        simError = m_simulated_data_item->loadDatafield(messageService, projectDir, rank());
-
-    // Handling corrupted file on disk
-    if (!realError.isEmpty() || !simError.isEmpty()) {
-        errorMessage = QString("Load of the data from disk failed with:\n");
-
-        if (!realError.isEmpty() && simError.isEmpty())
-            errorMessage += QString("'%1'").arg(realError);
-        else if (realError.isEmpty() && !simError.isEmpty())
-            errorMessage += QString("'%1'").arg(simError);
-        else
-            errorMessage += QString("'%1',\n'%2'").arg(realError, simError);
-    }
-
-    // Handling previous crash of GUI during job run
-    if (isRunning(batchInfo()->status())) {
-        if (errorMessage.isEmpty())
-            errorMessage = "Possible GUI crash while job was running";
-        else
-            errorMessage += "\n. Also possibly GUI crashed while job was running";
-    }
-
-    if (!errorMessage.isEmpty()) {
-        batchInfo()->setComments(errorMessage);
-        setFailed();
-    }
+        m_simulated_data_item->loadDatafield(projectDir, rank());
 }
 
 //! Updates the name of file to store intensity data.
diff --git a/GUI/Model/Job/JobItem.h b/GUI/Model/Job/JobItem.h
index 7a90adb39af..e4746f2549d 100644
--- a/GUI/Model/Job/JobItem.h
+++ b/GUI/Model/Job/JobItem.h
@@ -108,7 +108,7 @@ public:
     void readFrom(QXmlStreamReader* r);
 
     void saveDatafields(const QString& projectDir) const;
-    void loadDatafields(const QString& projectDir, MessageService* messageService);
+    void loadDatafields(const QString& projectDir);
 
 signals:
     void jobSelected(JobItem* item);
diff --git a/GUI/Model/Job/JobsSet.cpp b/GUI/Model/Job/JobsSet.cpp
index a4726937137..bff24ca4f7d 100644
--- a/GUI/Model/Job/JobsSet.cpp
+++ b/GUI/Model/Job/JobsSet.cpp
@@ -94,10 +94,10 @@ void JobsSet::saveAllDatafields(const QString& projectDir) const
     dataFilesCleaner.cleanOldFiles(projectDir, dataItems());
 }
 
-void JobsSet::loadAllDatafields(const QString& projectDir, MessageService* messageService)
+void JobsSet::loadAllDatafields(const QString& projectDir)
 {
     for (JobItem* job : *this)
-        job->loadDatafields(projectDir, messageService);
+        job->loadDatafields(projectDir);
 
     dataFilesCleaner.recollectDataNames(dataItems());
 }
diff --git a/GUI/Model/Job/JobsSet.h b/GUI/Model/Job/JobsSet.h
index 6ebec87b4e0..7eff8a0928b 100644
--- a/GUI/Model/Job/JobsSet.h
+++ b/GUI/Model/Job/JobsSet.h
@@ -24,7 +24,6 @@
 class DataItem;
 class ISimulation;
 class JobItem;
-class MessageService;
 
 class JobsSet : public QObject, public VectorWC<JobItem> {
     Q_OBJECT
@@ -36,7 +35,7 @@ public:
     void readFrom(QXmlStreamReader* r);
 
     void saveAllDatafields(const QString& projectDir) const;
-    void loadAllDatafields(const QString& projectDir, MessageService* messageService);
+    void loadAllDatafields(const QString& projectDir);
 
     JobItem* createJobItem();
     void addJobItem(JobItem* job_item);
diff --git a/GUI/Model/Project/ProjectDocument.cpp b/GUI/Model/Project/ProjectDocument.cpp
index e40c55fe12c..fc7bec1c11c 100644
--- a/GUI/Model/Project/ProjectDocument.cpp
+++ b/GUI/Model/Project/ProjectDocument.cpp
@@ -141,9 +141,8 @@ ProjectDocument::ReadResult ProjectDocument::loadProjectFileWithData(const QStri
         if (result == ReadResult::error)
             return result;
 
-        m_jobs->loadAllDatafields(GUI::Util::Project::projectDir(projectPullPath), &messageService);
-        m_datafiles->readDatafiles(GUI::Util::Project::projectDir(projectPullPath),
-                                   &messageService);
+        m_jobs->loadAllDatafields(GUI::Util::Project::projectDir(projectPullPath));
+        m_datafiles->readDatafiles(GUI::Util::Project::projectDir(projectPullPath));
 
         if (!messageService.warnings().empty())
             result = ReadResult::warning;
-- 
GitLab


From fd71e7d96c134360b80f9ec1f73ea4b1675591b1 Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de>
Date: Mon, 4 Mar 2024 17:10:36 +0100
Subject: [PATCH 16/18] rm class ReadResult

---
 GUI/Model/Data/DataItem.cpp               |  12 +-
 GUI/Model/Project/ProjectDocument.cpp     | 158 ++++++++--------------
 GUI/Model/Project/ProjectDocument.h       |   8 +-
 GUI/View/Main/ActionManager.cpp           |   1 +
 GUI/View/Main/MainWindow.cpp              |   1 +
 GUI/View/Manager/ProjectManager.cpp       |  41 +-----
 GUI/View/Manager/ProjectManager.h         |  12 +-
 Tests/Unit/GUI/TestAutosaveController.cpp |   1 +
 8 files changed, 83 insertions(+), 151 deletions(-)

diff --git a/GUI/Model/Data/DataItem.cpp b/GUI/Model/Data/DataItem.cpp
index 5976cb1a050..fabee74077b 100644
--- a/GUI/Model/Data/DataItem.cpp
+++ b/GUI/Model/Data/DataItem.cpp
@@ -86,18 +86,18 @@ void DataItem::loadDatafield(const QString& projectDir, int rank)
 {
     if (!QFile::exists(projectDir))
         throw std::runtime_error("Cannot load datafield: project directory "
-				 + projectDir.toStdString() + " does not exist");
+                                 + projectDir.toStdString() + " does not exist");
     const auto file = dataFullPath(projectDir);
 
     std::unique_ptr<Datafield> data;
     if (rank == 1)
-	data = std::make_unique<Datafield>(
-	    IO::readData1D(file.toStdString(), IO::Filetype1D::bornagain1D));
+        data = std::make_unique<Datafield>(
+            IO::readData1D(file.toStdString(), IO::Filetype1D::bornagain1D));
     else if (rank == 2)
-	data = std::make_unique<Datafield>(
-	    IO::readData2D(file.toStdString(), IO::Filetype2D::bornagain2D));
+        data = std::make_unique<Datafield>(
+            IO::readData2D(file.toStdString(), IO::Filetype2D::bornagain2D));
     else
-	ASSERT_NEVER;
+        ASSERT_NEVER;
 
     ASSERT(data);
     setDatafield(*data);
diff --git a/GUI/Model/Project/ProjectDocument.cpp b/GUI/Model/Project/ProjectDocument.cpp
index fc7bec1c11c..96a64f90d84 100644
--- a/GUI/Model/Project/ProjectDocument.cpp
+++ b/GUI/Model/Project/ProjectDocument.cpp
@@ -24,7 +24,6 @@
 #include "GUI/Model/Sample/SamplesSet.h"
 #include "GUI/Support/Data/ID.h"
 #include "GUI/Support/Data/SimulationOptionsItem.h"
-#include "GUI/Support/Util/MessageService.h"
 #include "GUI/Support/Util/Path.h"
 #include "GUI/Support/XML/DeserializationException.h"
 #include "GUI/Support/XML/UtilXML.h"
@@ -123,35 +122,19 @@ void ProjectDocument::saveProjectFileWithData(const QString& projectPullPath)
     emit projectSaved();
 }
 
-ProjectDocument::ReadResult ProjectDocument::loadProjectFileWithData(const QString& projectPullPath,
-                                                                     MessageService& messageService)
+void ProjectDocument::loadProjectFileWithData(const QString& projectPullPath)
 {
     setProjectFullPath(projectPullPath);
 
     QFile file(projectFullPath());
-    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
-        QString message = QString("Open file error '%1'").arg(file.errorString());
-        messageService.addError(this, message);
-        return ReadResult::error;
-    }
+    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
+        throw std::runtime_error("Cannot open project file " + projectPullPath.toStdString());
 
-    try {
-        auto result = readProject(&file, messageService);
-        file.close();
-        if (result == ReadResult::error)
-            return result;
-
-        m_jobs->loadAllDatafields(GUI::Util::Project::projectDir(projectPullPath));
-        m_datafiles->readDatafiles(GUI::Util::Project::projectDir(projectPullPath));
-
-        if (!messageService.warnings().empty())
-            result = ReadResult::warning;
-        return result;
-    } catch (const std::exception& ex) {
-        QString message = QString("Exception thrown '%1'").arg(QString(ex.what()));
-        messageService.addError(this, message);
-        return ReadResult::error;
-    }
+    readProject(&file);
+    file.close();
+
+    m_jobs->loadAllDatafields(GUI::Util::Project::projectDir(projectPullPath));
+    m_datafiles->readDatafiles(GUI::Util::Project::projectDir(projectPullPath));
 }
 
 bool ProjectDocument::hasValidNameAndPath() const
@@ -232,85 +215,64 @@ void ProjectDocument::writeProject(QIODevice* device)
     w.writeEndDocument();
 }
 
-ProjectDocument::ReadResult ProjectDocument::readProject(QIODevice* device,
-                                                         MessageService& messageService)
+void ProjectDocument::readProject(QIODevice* device)
 {
-    const int warningsBefore = messageService.warnings().size();
-
     QXmlStreamReader r(device);
-    try {
-        while (!r.atEnd()) {
-            r.readNext();
-            if (r.isStartElement()) {
-                if (r.name() == Tag::BornAgain) {
-                    const uint version = XML::readUIntAttribute(&r, XML::Attrib::version);
-                    Q_UNUSED(version)
-                    m_current_version = r.attributes().value(XML::Attrib::BA_Version).toString();
-
-                    if (!GUI::Path::isVersionMatchMinimal(m_current_version,
-                                                          minimal_supported_version)) {
-                        QString message = QString("Cannot open document version '%1', "
-                                                  "minimal supported version '%2'")
-                                              .arg(m_current_version)
-                                              .arg(minimal_supported_version);
-                        messageService.addError(this, message);
-                        return ReadResult::error;
-                    }
-
-                    while (r.readNextStartElement()) {
-                        QString tag = r.name().toString();
-
-                        // simulation options
-                        if (tag == Tag::SimulationOptions) {
-                            m_options->readFrom(&r);
-                            XML::gotoEndElementOfTag(&r, tag);
-
-                            // instruments
-                        } else if (tag == Tag::InstrumentsSet) {
-                            m_instruments->readFrom(&r);
-                            XML::gotoEndElementOfTag(&r, tag);
-
-                            // samples
-                        } else if (tag == Tag::SamplesSet) {
-                            m_samples->readFrom(&r);
-                            XML::gotoEndElementOfTag(&r, tag);
-
-                            // real model
-                        } else if (tag == Tag::RealModel) {
-                            // 'm_instruments' should be read before
-                            m_datafiles->readFrom(&r);
-                            XML::gotoEndElementOfTag(&r, tag);
-
-                            // job model
-                        } else if (tag == Tag::JobsSet) {
-                            m_jobs->readFrom(&r);
-                            XML::gotoEndElementOfTag(&r, tag);
-
-                            // active view
-                        } else if (tag == Tag::ActiveView) {
-                            XML::readAttribute(&r, XML::Attrib::value, &m_last_view_active);
-                            XML::gotoEndElementOfTag(&r, tag);
-
-                        } else
-                            r.skipCurrentElement();
-                    }
+    while (!r.atEnd()) {
+        r.readNext();
+        if (r.isStartElement()) {
+            if (r.name() == Tag::BornAgain) {
+                const uint version = XML::readUIntAttribute(&r, XML::Attrib::version);
+                Q_UNUSED(version)
+                m_current_version = r.attributes().value(XML::Attrib::BA_Version).toString();
+
+                if (!GUI::Path::isVersionMatchMinimal(m_current_version, minimal_supported_version))
+                    throw std::runtime_error(QString("Cannot open document version '%1', "
+                                                     "minimal supported version is '%2'")
+                                                 .arg(m_current_version)
+                                                 .arg(minimal_supported_version)
+                                                 .toStdString());
+
+                while (r.readNextStartElement()) {
+                    QString tag = r.name().toString();
+
+                    // simulation options
+                    if (tag == Tag::SimulationOptions) {
+                        m_options->readFrom(&r);
+                        XML::gotoEndElementOfTag(&r, tag);
+
+                        // instruments
+                    } else if (tag == Tag::InstrumentsSet) {
+                        m_instruments->readFrom(&r);
+                        XML::gotoEndElementOfTag(&r, tag);
+
+                        // samples
+                    } else if (tag == Tag::SamplesSet) {
+                        m_samples->readFrom(&r);
+                        XML::gotoEndElementOfTag(&r, tag);
+
+                        // real model
+                    } else if (tag == Tag::RealModel) {
+                        // 'm_instruments' should be read before
+                        m_datafiles->readFrom(&r);
+                        XML::gotoEndElementOfTag(&r, tag);
+
+                        // job model
+                    } else if (tag == Tag::JobsSet) {
+                        m_jobs->readFrom(&r);
+                        XML::gotoEndElementOfTag(&r, tag);
+
+                        // active view
+                    } else if (tag == Tag::ActiveView) {
+                        XML::readAttribute(&r, XML::Attrib::value, &m_last_view_active);
+                        XML::gotoEndElementOfTag(&r, tag);
+
+                    } else
+                        r.skipCurrentElement();
                 }
             }
         }
-
-    } catch (DeserializationException& ex) {
-        r.raiseError(ex.text());
-    }
-
-    if (r.hasError()) {
-        QString message = QString("Format error '%1'").arg(r.errorString());
-        messageService.addError(this, message);
-        return ReadResult::error;
     }
-
-    // return "ReadResult::warning" only if warnings have been issued _in here_
-    return warningsBefore != messageService.warnings().size() ? ReadResult::warning
-                                                              : ReadResult::ok;
 }
 
 void ProjectDocument::setViewId(int id)
diff --git a/GUI/Model/Project/ProjectDocument.h b/GUI/Model/Project/ProjectDocument.h
index 3ceb64892ea..01327d0616b 100644
--- a/GUI/Model/Project/ProjectDocument.h
+++ b/GUI/Model/Project/ProjectDocument.h
@@ -21,7 +21,6 @@
 class DatafilesSet;
 class InstrumentsSet;
 class JobsSet;
-class MessageService;
 class ProjectDocument;
 class QIODevice;
 class SamplesSet;
@@ -41,8 +40,6 @@ BA_GUI_API_ extern std::unique_ptr<ProjectDocument> gDoc;
 class ProjectDocument : public QObject {
     Q_OBJECT
 public:
-    enum class ReadResult { ok, warning, error };
-
     ProjectDocument();
     ~ProjectDocument();
 
@@ -50,8 +47,7 @@ public:
     void setProjectName(const QString& text);
     void setProjectFullPath(const QString& fullPath);
     void saveProjectFileWithData(const QString& projectPullPath);
-    ReadResult loadProjectFileWithData(const QString& projectPullPath,
-                                       MessageService& messageService);
+    void loadProjectFileWithData(const QString& projectPullPath);
 
     void setModified();
     void clearModified();
@@ -87,7 +83,7 @@ signals:
 
 private:
     void writeProject(QIODevice* device);
-    ReadResult readProject(QIODevice* device, MessageService& messageService);
+    void readProject(QIODevice* device);
 
     void onModelChanged();
 
diff --git a/GUI/View/Main/ActionManager.cpp b/GUI/View/Main/ActionManager.cpp
index f8d736c3d5b..28bbe73fe50 100644
--- a/GUI/View/Main/ActionManager.cpp
+++ b/GUI/View/Main/ActionManager.cpp
@@ -15,6 +15,7 @@
 #include "GUI/View/Main/ActionManager.h"
 #include "Base/Util/Assert.h"
 #include "Base/Util/SysUtil.h"
+#include "GUI/Model/Project/ProjectDocument.h"
 #include "GUI/Support/Util/Path.h"
 #include "GUI/View/Layout/ApplicationSettings.h"
 #include "GUI/View/Layout/mainwindow_constants.h"
diff --git a/GUI/View/Main/MainWindow.cpp b/GUI/View/Main/MainWindow.cpp
index 8417a6e8bac..cc94e303d01 100644
--- a/GUI/View/Main/MainWindow.cpp
+++ b/GUI/View/Main/MainWindow.cpp
@@ -14,6 +14,7 @@
 
 #include "GUI/View/Main/MainWindow.h"
 #include "GUI/Model/Job/JobsSet.h"
+#include "GUI/Model/Project/ProjectDocument.h"
 #include "GUI/Support/Util/Path.h"
 #include "GUI/View/Layout/ApplicationSettings.h"
 #include "GUI/View/Layout/mainwindow_constants.h"
diff --git a/GUI/View/Manager/ProjectManager.cpp b/GUI/View/Manager/ProjectManager.cpp
index eef6eec561c..338fc2b81e7 100644
--- a/GUI/View/Manager/ProjectManager.cpp
+++ b/GUI/View/Manager/ProjectManager.cpp
@@ -14,6 +14,7 @@
 
 #include "GUI/View/Manager/ProjectManager.h"
 #include "Base/Util/Assert.h"
+#include "GUI/Model/Project/ProjectDocument.h"
 #include "GUI/Model/Project/ProjectUtil.h"
 #include "GUI/Support/Util/MessageService.h"
 #include "GUI/View/Info/MessageBox.h"
@@ -253,18 +254,7 @@ void ProjectManager::openProject(QString projectPullPath)
     }
 
     createNewProject();
-    MessageService messageService;
-    const auto readResult = loadProject(projectPullPath, messageService);
-
-    if (readResult == ProjectDocument::ReadResult::ok)
-        addToRecentProjects();
-    else if (readResult == ProjectDocument::ReadResult::error) {
-        riseProjectLoadFailedDialog(messageService);
-        deleteCurrentProject();
-    } else if (readResult == ProjectDocument::ReadResult::warning) {
-        riseProjectLoadProblemDialog(messageService);
-        addToRecentProjects();
-    }
+    loadProject(projectPullPath);
     if (gDoc)
         emit documentOpenedOrClosed(true);
 }
@@ -297,26 +287,22 @@ void ProjectManager::deleteCurrentProject()
 
 //! Load project data from file name. If autosave info exists, opens dialog for project restore.
 
-ProjectDocument::ReadResult ProjectManager::loadProject(const QString& fullPathAndName,
-                                                        MessageService& messageService)
+void ProjectManager::loadProject(const QString& fullPathAndName)
 {
-    auto readResult = ProjectDocument::ReadResult::ok;
-
     const bool useAutosave = GUI::Util::Project::hasAutosavedData(fullPathAndName);
     const QString autosaveFullPath = GUI::Util::Project::autosaveFullPath(fullPathAndName);
     if (qApp)
         QApplication::setOverrideCursor(Qt::WaitCursor);
     if (useAutosave && restoreProjectDialog(fullPathAndName, autosaveFullPath)) {
-        readResult = gDoc->loadProjectFileWithData(autosaveFullPath, messageService);
+        gDoc->loadProjectFileWithData(autosaveFullPath);
         gDoc->setProjectFullPath(fullPathAndName);
         // restored project should be marked by '*'
         gDoc->setModified();
     } else {
-        readResult = gDoc->loadProjectFileWithData(fullPathAndName, messageService);
+        gDoc->loadProjectFileWithData(fullPathAndName);
     }
     if (qApp)
         QApplication::restoreOverrideCursor();
-    return readResult;
 }
 
 //! Returns project file name from dialog. Returns empty string if dialog was canceled.
@@ -365,23 +351,6 @@ QString ProjectManager::untitledProjectName()
     return result;
 }
 
-void ProjectManager::riseProjectLoadFailedDialog(const MessageService& messageService)
-{
-    QString message = QString("Failed to load the project '%1' \n\n").arg(gDoc->projectFullPath());
-
-    for (const auto& details : messageService.errors())
-        message.append(details + "\n");
-
-    QMessageBox::warning(GUI::Global::mainWindow, "Error while opening project file", message);
-}
-
-void ProjectManager::riseProjectLoadProblemDialog(const MessageService& messageService)
-{
-    auto* problemDialog = new ProjectLoadProblemDialog(messageService.warnings(true));
-    problemDialog->show();
-    problemDialog->raise();
-}
-
 //! Rises dialog if the project should be restored from autosave. Returns true, if yes.
 
 bool ProjectManager::restoreProjectDialog(const QString& projectFileName,
diff --git a/GUI/View/Manager/ProjectManager.h b/GUI/View/Manager/ProjectManager.h
index 38a2a540c33..8a1c1f15276 100644
--- a/GUI/View/Manager/ProjectManager.h
+++ b/GUI/View/Manager/ProjectManager.h
@@ -15,7 +15,11 @@
 #ifndef BORNAGAIN_GUI_VIEW_MANAGER_PROJECTMANAGER_H
 #define BORNAGAIN_GUI_VIEW_MANAGER_PROJECTMANAGER_H
 
-#include "GUI/Model/Project/ProjectDocument.h"
+#include <QObject>
+#include <QStringList>
+
+class AutosaveController;
+class ProjectDocument;
 
 class AutosaveController;
 
@@ -56,15 +60,13 @@ public slots:
 private:
     void createNewProject();
     void deleteCurrentProject();
-    ProjectDocument::ReadResult loadProject(const QString& fullPathAndName,
-                                            MessageService& messageService);
+    void loadProject(const QString& fullPathAndName);
+
     QString acquireProjectPullPath();
     void addToRecentProjects();
 
     QString untitledProjectName();
 
-    void riseProjectLoadFailedDialog(const MessageService& messageService);
-    void riseProjectLoadProblemDialog(const MessageService& messageService);
     bool restoreProjectDialog(const QString& projectFileName, QString autosaveName);
 
     QString m_working_directory;
diff --git a/Tests/Unit/GUI/TestAutosaveController.cpp b/Tests/Unit/GUI/TestAutosaveController.cpp
index e05dcef0247..f2405d61f9b 100644
--- a/Tests/Unit/GUI/TestAutosaveController.cpp
+++ b/Tests/Unit/GUI/TestAutosaveController.cpp
@@ -4,6 +4,7 @@
 #include "GUI/Model/Device/DatafileItem.h"
 #include "GUI/Model/Device/InstrumentItems.h"
 #include "GUI/Model/Device/InstrumentsSet.h"
+#include "GUI/Model/Project/ProjectDocument.h"
 #include "GUI/Model/Project/ProjectUtil.h"
 #include "GUI/Support/Util/Path.h"
 #include "GUI/View/Manager/AutosaveController.h"
-- 
GitLab


From 229e994e62d08ffd4c6ba7ca0ba8074d96284dcc Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de>
Date: Mon, 4 Mar 2024 17:12:58 +0100
Subject: [PATCH 17/18] rm MessageService

---
 GUI/Model/Job/JobItem.h               |  1 -
 GUI/Model/Mask/MasksSet.cpp           |  2 +-
 GUI/Model/Mask/MasksSet.h             |  3 +-
 GUI/Support/Util/MessageService.cpp   | 48 ---------------------------
 GUI/Support/Util/MessageService.h     | 42 -----------------------
 GUI/View/Manager/ProjectManager.cpp   |  1 -
 Tests/Unit/GUI/TestMessageService.cpp | 37 ---------------------
 7 files changed, 2 insertions(+), 132 deletions(-)
 delete mode 100644 GUI/Support/Util/MessageService.cpp
 delete mode 100644 GUI/Support/Util/MessageService.h
 delete mode 100644 Tests/Unit/GUI/TestMessageService.cpp

diff --git a/GUI/Model/Job/JobItem.h b/GUI/Model/Job/JobItem.h
index e4746f2549d..7de72d254d9 100644
--- a/GUI/Model/Job/JobItem.h
+++ b/GUI/Model/Job/JobItem.h
@@ -27,7 +27,6 @@ class DatafileItem;
 class FitSuiteItem;
 class InstrumentItem;
 class JobWorker;
-class MessageService;
 class ParameterContainerItem;
 class ParameterTreeItems;
 class SampleItem;
diff --git a/GUI/Model/Mask/MasksSet.cpp b/GUI/Model/Mask/MasksSet.cpp
index 47117ddf3e3..74e4d93ffbb 100644
--- a/GUI/Model/Mask/MasksSet.cpp
+++ b/GUI/Model/Mask/MasksSet.cpp
@@ -70,7 +70,7 @@ void MasksSet::writeTo(QXmlStreamWriter* w) const
     }
 }
 
-void MasksSet::readFrom(QXmlStreamReader* r, MessageService*)
+void MasksSet::readFrom(QXmlStreamReader* r)
 {
     clear();
 
diff --git a/GUI/Model/Mask/MasksSet.h b/GUI/Model/Mask/MasksSet.h
index 9b88835090b..90698e08293 100644
--- a/GUI/Model/Mask/MasksSet.h
+++ b/GUI/Model/Mask/MasksSet.h
@@ -20,7 +20,6 @@
 #include <QModelIndex>
 #include <QXmlStreamWriter>
 
-class MessageService;
 class RegionOfInterestItem;
 
 //! Container holding various masks as children
@@ -35,7 +34,7 @@ public:
     RegionOfInterestItem* regionOfInterestItem() const;
 
     void writeTo(QXmlStreamWriter* w) const;
-    void readFrom(QXmlStreamReader* r, MessageService* messageService = nullptr);
+    void readFrom(QXmlStreamReader* r);
 
     void updateMaskNames();
 
diff --git a/GUI/Support/Util/MessageService.cpp b/GUI/Support/Util/MessageService.cpp
deleted file mode 100644
index 472189d5b5f..00000000000
--- a/GUI/Support/Util/MessageService.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-//  ************************************************************************************************
-//
-//  BornAgain: simulate and fit reflection and scattering
-//
-//! @file      GUI/Support/Util/MessageService.cpp
-//! @brief     Implements class MessageService.
-//!
-//! @homepage  http://www.bornagainproject.org
-//! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2018
-//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
-//
-//  ************************************************************************************************
-
-#include "GUI/Support/Util/MessageService.h"
-
-QStringList MessageService::descriptions(const Messages& messages, bool includeSenders) const
-{
-    QStringList result;
-
-    for (const auto& message : messages)
-        if (includeSenders)
-            result.push_back(message.first + ": " + message.second);
-        else
-            result.push_back(message.second);
-
-    return result;
-}
-
-void MessageService::addError(QObject* sender, const QString& description)
-{
-    m_errors.append(qMakePair(sender->objectName(), description));
-}
-
-void MessageService::addWarning(QObject* sender, const QString& description)
-{
-    m_warnings.append(qMakePair(sender->objectName(), description));
-}
-
-QStringList MessageService::errors(bool includeSenders /*= false*/) const
-{
-    return descriptions(m_errors, includeSenders);
-}
-
-QStringList MessageService::warnings(bool includeSenders /*= false*/) const
-{
-    return descriptions(m_warnings, includeSenders);
-}
diff --git a/GUI/Support/Util/MessageService.h b/GUI/Support/Util/MessageService.h
deleted file mode 100644
index e4037266728..00000000000
--- a/GUI/Support/Util/MessageService.h
+++ /dev/null
@@ -1,42 +0,0 @@
-//  ************************************************************************************************
-//
-//  BornAgain: simulate and fit reflection and scattering
-//
-//! @file      GUI/Support/Util/MessageService.h
-//! @brief     Defines class MessageService.
-//!
-//! @homepage  http://www.bornagainproject.org
-//! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2018
-//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
-//
-//  ************************************************************************************************
-
-#ifndef BORNAGAIN_GUI_SUPPORT_UTIL_MESSAGESERVICE_H
-#define BORNAGAIN_GUI_SUPPORT_UTIL_MESSAGESERVICE_H
-
-#include <QObject>
-#include <QString>
-#include <QVector>
-#include <utility>
-
-//! The service to collect messages from different senders.
-
-class MessageService {
-public:
-    void addError(QObject* sender, const QString& description);
-    void addWarning(QObject* sender, const QString& description);
-
-    QStringList errors(bool includeSenders = false) const;
-    QStringList warnings(bool includeSenders = false) const;
-
-private:
-    using Messages = QVector<std::pair<QString, QString>>; // pair of sender & description
-
-    QStringList descriptions(const Messages& messages, bool includeSenders) const;
-
-    Messages m_warnings;
-    Messages m_errors;
-};
-
-#endif // BORNAGAIN_GUI_SUPPORT_UTIL_MESSAGESERVICE_H
diff --git a/GUI/View/Manager/ProjectManager.cpp b/GUI/View/Manager/ProjectManager.cpp
index 338fc2b81e7..73a93fa4a06 100644
--- a/GUI/View/Manager/ProjectManager.cpp
+++ b/GUI/View/Manager/ProjectManager.cpp
@@ -16,7 +16,6 @@
 #include "Base/Util/Assert.h"
 #include "GUI/Model/Project/ProjectDocument.h"
 #include "GUI/Model/Project/ProjectUtil.h"
-#include "GUI/Support/Util/MessageService.h"
 #include "GUI/View/Info/MessageBox.h"
 #include "GUI/View/Layout/ApplicationSettings.h"
 #include "GUI/View/Layout/mainwindow_constants.h"
diff --git a/Tests/Unit/GUI/TestMessageService.cpp b/Tests/Unit/GUI/TestMessageService.cpp
deleted file mode 100644
index 0f95f9bcaf3..00000000000
--- a/Tests/Unit/GUI/TestMessageService.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-#include "GUI/Support/Util/MessageService.h"
-
-#include "Tests/GTestWrapper/google_test.h"
-#include <QObject>
-#include <QString>
-
-class TestMessageService : public ::testing::Test {
-public:
-    class Sender : public QObject {
-    public:
-        explicit Sender(const QString& name) { setObjectName(name); }
-    };
-};
-
-TEST_F(TestMessageService, warningAndErrorCount)
-{
-    const QString senderName1("senderName1");
-    const QString senderName2("senderName2");
-
-    const QString description1("description1");
-    const QString description2("description2");
-    const QString description3("description3");
-
-    MessageService svc;
-    Sender sender1(senderName1);
-    Sender sender2(senderName2);
-
-    // sending messages
-    svc.addWarning(&sender1, description1);
-    svc.addWarning(&sender1, description2);
-    svc.addError(&sender1, description1);
-    svc.addError(&sender2, description2);
-    svc.addWarning(&sender1, description3);
-
-    EXPECT_EQ(svc.warnings().size(), 3);
-    EXPECT_EQ(svc.errors().size(), 2);
-}
-- 
GitLab


From 6111aad9cb15115d1f0da48da8ae5b11e111d426 Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de>
Date: Mon, 4 Mar 2024 17:19:57 +0100
Subject: [PATCH 18/18] rm DeserializationException

---
 GUI/Model/Device/DatafileItem.cpp            |  1 -
 GUI/Model/Device/InstrumentXML.cpp           |  1 -
 GUI/Model/Material/MaterialItem.cpp          |  1 -
 GUI/Model/Project/ProjectDocument.cpp        |  2 --
 GUI/Support/Data/SimulationOptionsItem.cpp   |  1 -
 GUI/Support/XML/DeserializationException.cpp | 36 --------------------
 GUI/Support/XML/DeserializationException.h   | 35 -------------------
 GUI/Support/XML/UtilXML.cpp                  | 15 +++-----
 8 files changed, 5 insertions(+), 87 deletions(-)
 delete mode 100644 GUI/Support/XML/DeserializationException.cpp
 delete mode 100644 GUI/Support/XML/DeserializationException.h

diff --git a/GUI/Model/Device/DatafileItem.cpp b/GUI/Model/Device/DatafileItem.cpp
index 4630ae4678b..4d44a31f967 100644
--- a/GUI/Model/Device/DatafileItem.cpp
+++ b/GUI/Model/Device/DatafileItem.cpp
@@ -22,7 +22,6 @@
 #include "GUI/Model/Data/Data2DItem.h"
 #include "GUI/Support/Util/Path.h"
 #include "GUI/Support/XML/Backup.h"
-#include "GUI/Support/XML/DeserializationException.h"
 #include "GUI/Support/XML/UtilXML.h"
 
 namespace {
diff --git a/GUI/Model/Device/InstrumentXML.cpp b/GUI/Model/Device/InstrumentXML.cpp
index 318f52484cc..93e6c3e2c04 100644
--- a/GUI/Model/Device/InstrumentXML.cpp
+++ b/GUI/Model/Device/InstrumentXML.cpp
@@ -17,7 +17,6 @@
 #include "GUI/Model/Descriptor/PolyItem.h"
 #include "GUI/Model/Device/InstrumentItems.h"
 #include "GUI/Model/Device/InstrumentsCatalog.h"
-#include "GUI/Support/XML/DeserializationException.h"
 #include "GUI/Support/XML/UtilXML.h"
 #include <QFile>
 
diff --git a/GUI/Model/Material/MaterialItem.cpp b/GUI/Model/Material/MaterialItem.cpp
index 7adcef85a10..a5996d227a5 100644
--- a/GUI/Model/Material/MaterialItem.cpp
+++ b/GUI/Model/Material/MaterialItem.cpp
@@ -14,7 +14,6 @@
 
 #include "GUI/Model/Material/MaterialItem.h"
 #include "Base/Util/Assert.h"
-#include "GUI/Support/XML/DeserializationException.h"
 #include "GUI/Support/XML/UtilXML.h"
 #include "Sample/Material/MaterialFactoryFuncs.h"
 #include <QUuid>
diff --git a/GUI/Model/Project/ProjectDocument.cpp b/GUI/Model/Project/ProjectDocument.cpp
index 96a64f90d84..dacaab1b9b0 100644
--- a/GUI/Model/Project/ProjectDocument.cpp
+++ b/GUI/Model/Project/ProjectDocument.cpp
@@ -25,10 +25,8 @@
 #include "GUI/Support/Data/ID.h"
 #include "GUI/Support/Data/SimulationOptionsItem.h"
 #include "GUI/Support/Util/Path.h"
-#include "GUI/Support/XML/DeserializationException.h"
 #include "GUI/Support/XML/UtilXML.h"
 #include <QFile>
-#include <QStandardPaths>
 
 BA_GUI_API_ std::unique_ptr<ProjectDocument> gDoc;
 
diff --git a/GUI/Support/Data/SimulationOptionsItem.cpp b/GUI/Support/Data/SimulationOptionsItem.cpp
index d6db12507e9..daca3268262 100644
--- a/GUI/Support/Data/SimulationOptionsItem.cpp
+++ b/GUI/Support/Data/SimulationOptionsItem.cpp
@@ -13,7 +13,6 @@
 //  ************************************************************************************************
 
 #include "GUI/Support/Data/SimulationOptionsItem.h"
-#include "GUI/Support/XML/DeserializationException.h"
 #include "GUI/Support/XML/UtilXML.h"
 #include <thread>
 
diff --git a/GUI/Support/XML/DeserializationException.cpp b/GUI/Support/XML/DeserializationException.cpp
deleted file mode 100644
index 90b31d01a7d..00000000000
--- a/GUI/Support/XML/DeserializationException.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-//  ************************************************************************************************
-//
-//  BornAgain: simulate and fit reflection and scattering
-//
-//! @file      GUI/Support/XML/DeserializationException.cpp
-//! @brief     Implements class DeserializationException.
-//!
-//! @homepage  http://www.bornagainproject.org
-//! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2021
-//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
-//
-//  ************************************************************************************************
-
-#include "GUI/Support/XML/DeserializationException.h"
-#include <utility>
-
-DeserializationException::DeserializationException(QString t)
-    : m_text(std::move(t))
-{
-}
-
-DeserializationException DeserializationException::tooOld()
-{
-    return DeserializationException("The found file is too old.");
-}
-
-DeserializationException DeserializationException::tooNew()
-{
-    return DeserializationException("The found file is too new.");
-}
-
-DeserializationException DeserializationException::streamError()
-{
-    return DeserializationException("The data seems to be corrupted.");
-}
diff --git a/GUI/Support/XML/DeserializationException.h b/GUI/Support/XML/DeserializationException.h
deleted file mode 100644
index 6daed29978e..00000000000
--- a/GUI/Support/XML/DeserializationException.h
+++ /dev/null
@@ -1,35 +0,0 @@
-//  ************************************************************************************************
-//
-//  BornAgain: simulate and fit reflection and scattering
-//
-//! @file      GUI/Support/XML/DeserializationException.h
-//! @brief     Defines class DeserializationException.
-//!
-//! @homepage  http://www.bornagainproject.org
-//! @license   GNU General Public License v3 or higher (see COPYING)
-//! @copyright Forschungszentrum Jülich GmbH 2021
-//! @authors   Scientific Computing Group at MLZ (see CITATION, AUTHORS)
-//
-//  ************************************************************************************************
-
-#ifndef BORNAGAIN_GUI_SUPPORT_XML_DESERIALIZATIONEXCEPTION_H
-#define BORNAGAIN_GUI_SUPPORT_XML_DESERIALIZATIONEXCEPTION_H
-
-#include <QString>
-
-class DeserializationException {
-private:
-    DeserializationException(QString t);
-
-public:
-    static DeserializationException tooOld();
-    static DeserializationException tooNew();
-    static DeserializationException streamError();
-
-    QString text() const { return m_text; }
-
-private:
-    QString m_text;
-};
-
-#endif // BORNAGAIN_GUI_SUPPORT_XML_DESERIALIZATIONEXCEPTION_H
diff --git a/GUI/Support/XML/UtilXML.cpp b/GUI/Support/XML/UtilXML.cpp
index 41c0bdbbdfb..140cafc5a92 100644
--- a/GUI/Support/XML/UtilXML.cpp
+++ b/GUI/Support/XML/UtilXML.cpp
@@ -14,7 +14,6 @@
 
 #include "GUI/Support/XML/UtilXML.h"
 #include "Base/Util/Assert.h"
-#include "GUI/Support/XML/DeserializationException.h"
 #include <QColor>
 #include <QUuid>
 
@@ -23,20 +22,16 @@ namespace {
 void assertCurrentTag(QXmlStreamReader* reader, const QString& expectedTag)
 {
 
-    if (reader->name() != expectedTag) {
-#ifdef _DEBUG
-        // to simplify debugging: what is the current tag
-        QString foundTag = reader->name().toString();
-        Q_UNUSED(foundTag);
-#endif
-        throw DeserializationException::streamError();
-    }
+    if (reader->name() != expectedTag)
+        throw std::runtime_error("Found tag '" + reader->name().toString().toStdString()
+                                 + "' instead of expected expected tag '"
+                                 + expectedTag.toStdString() + "'");
 }
 
 void assertCurrentToken(QXmlStreamReader* reader, QXmlStreamReader::TokenType token)
 {
     if (reader->tokenType() != token)
-        throw DeserializationException::streamError();
+        throw std::runtime_error("Found unexpected token type");
 }
 
 } // namespace
-- 
GitLab