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] 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