From a928fee10890f964e02d290ae428af0810dcb0ad Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 15 May 2023 16:09:56 +0200 Subject: Separate session loading from project manager Move the generic parts to session manager and let the project manager load its parts separately. Change-Id: I14ee3311ab0c0f40444674b82cee1e4bb0fb9daf Reviewed-by: Qt CI Bot Reviewed-by: Christian Kandeler --- .../clangtoolspreconfiguredsessiontests.cpp | 2 +- src/plugins/projectexplorer/projectexplorer.cpp | 2 +- src/plugins/projectexplorer/projectmanager.cpp | 211 +++++---------------- src/plugins/projectexplorer/projectmanager.h | 2 - src/plugins/projectexplorer/session.cpp | 129 ++++++++++++- src/plugins/projectexplorer/session.h | 3 + src/plugins/projectexplorer/sessionmodel.cpp | 2 +- 7 files changed, 180 insertions(+), 171 deletions(-) diff --git a/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp b/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp index 4d4b34c1ef..1a87580efc 100644 --- a/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp +++ b/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp @@ -91,7 +91,7 @@ void PreconfiguredSessionTests::initTestCase() // Load session const FilePaths projects = ProjectManager::projectsForSessionName(preconfiguredSessionName); WaitForParsedProjects waitForParsedProjects(projects); - QVERIFY(ProjectManager::loadSession(preconfiguredSessionName)); + QVERIFY(SessionManager::loadSession(preconfiguredSessionName)); QVERIFY(waitForParsedProjects.wait()); } diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index ca7c40a073..1244dbd1ba 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -4013,7 +4013,7 @@ void ProjectExplorerPluginPrivate::updateSessionMenu() void ProjectExplorerPluginPrivate::setSession(QAction *action) { - ProjectManager::loadSession(action->data().toString()); + SessionManager::loadSession(action->data().toString()); } void ProjectExplorerPlugin::setProjectExplorerSettings(const ProjectExplorerSettings &pes) diff --git a/src/plugins/projectexplorer/projectmanager.cpp b/src/plugins/projectexplorer/projectmanager.cpp index 81824c7c7a..ccfa95a289 100644 --- a/src/plugins/projectexplorer/projectmanager.cpp +++ b/src/plugins/projectexplorer/projectmanager.cpp @@ -49,11 +49,10 @@ using namespace ProjectExplorer::Internal; namespace ProjectExplorer { -const char DEFAULT_SESSION[] = "default"; - class ProjectManagerPrivate { public: + void loadSession(); void restoreDependencies(); void restoreStartupProject(); void restoreProjects(const FilePaths &fileList); @@ -106,6 +105,10 @@ ProjectManager::ProjectManager() EditorManager::setWindowTitleAdditionHandler(&ProjectManagerPrivate::windowTitleAddition); EditorManager::setSessionTitleHandler(&ProjectManagerPrivate::sessionTitle); + + connect(SessionManager::instance(), &SessionManager::aboutToLoadSession, this, [] { + d->loadSession(); + }); } ProjectManager::~ProjectManager() @@ -693,172 +696,52 @@ void ProjectManagerPrivate::restoreProjects(const FilePaths &fileList) } } -/* - * ========== Notes on storing and loading the default session ========== - * The default session comes in two flavors: implicit and explicit. The implicit one, - * also referred to as "default virgin" in the code base, is the one that is active - * at start-up, if no session has been explicitly loaded due to command-line arguments - * or the "restore last session" setting in the session manager. - * The implicit default session silently turns into the explicit default session - * by loading a project or a file or changing settings in the Dependencies panel. The explicit - * default session can also be loaded by the user via the Welcome Screen. - * This mechanism somewhat complicates the handling of session-specific settings such as - * the ones in the task pane: Users expect that changes they make there become persistent, even - * when they are in the implicit default session. However, we can't just blindly store - * the implicit default session, because then we'd overwrite the project list of the explicit - * default session. Therefore, we use the following logic: - * - Upon start-up, if no session is to be explicitly loaded, we restore the parts of the - * explicit default session that are not related to projects, editors etc; the - * "general settings" of the session, so to speak. - * - When storing the implicit default session, we overwrite only these "general settings" - * of the explicit default session and keep the others as they are. - * - When switching from the implicit to the explicit default session, we keep the - * "general settings" and load everything else from the session file. - * This guarantees that user changes are properly transferred and nothing gets lost from - * either the implicit or the explicit default session. - * - */ -bool ProjectManager::loadSession(const QString &session, bool initial) +void ProjectManagerPrivate::loadSession() { - const bool loadImplicitDefault = session.isEmpty(); - const bool switchFromImplicitToExplicitDefault = session == DEFAULT_SESSION - && sb_d->m_sessionName == DEFAULT_SESSION && !initial; - - // Do nothing if we have that session already loaded, - // exception if the session is the default virgin session - // we still want to be able to load the default session - if (session == sb_d->m_sessionName && !SessionManager::isDefaultVirgin()) - return true; - - if (!loadImplicitDefault && !SessionManager::sessions().contains(session)) - return false; - - // Try loading the file - FilePath fileName = SessionManager::sessionNameToFileName(loadImplicitDefault ? DEFAULT_SESSION : session); - PersistentSettingsReader reader; - if (fileName.exists()) { - if (!reader.load(fileName)) { - QMessageBox::warning(ICore::dialogParent(), Tr::tr("Error while restoring session"), - Tr::tr("Could not restore session %1").arg(fileName.toUserOutput())); - - return false; - } - - if (loadImplicitDefault) { - sb_d->restoreValues(reader); - emit SessionManager::instance()->sessionLoaded(DEFAULT_SESSION); - return true; - } - } else if (loadImplicitDefault) { - return true; - } - - sb_d->m_loadingSession = true; - - // Allow everyone to set something in the session and before saving - emit SessionManager::instance()->aboutToUnloadSession(sb_d->m_sessionName); - - if (!save()) { - sb_d->m_loadingSession = false; - return false; - } - - // Clean up - if (!EditorManager::closeAllEditors()) { - sb_d->m_loadingSession = false; - return false; - } - d->m_failedProjects.clear(); d->m_depMap.clear(); - if (!switchFromImplicitToExplicitDefault) - sb_d->m_values.clear(); - sb_d->m_sessionValues.clear(); d->m_casadeSetActive = false; - sb_d->m_sessionName = session; - delete sb_d->m_writer; - sb_d->m_writer = nullptr; - EditorManager::updateWindowTitles(); - - if (fileName.exists()) { - sb_d->m_virginSession = false; - - ProgressManager::addTask(sb_d->m_future.future(), Tr::tr("Loading Session"), - "ProjectExplorer.SessionFile.Load"); - - sb_d->m_future.setProgressRange(0, 1 /*initialization*/ + 1 /*editors*/); - sb_d->m_future.setProgressValue(0); - - if (!switchFromImplicitToExplicitDefault) - sb_d->restoreValues(reader); - sb_d->restoreSessionValues(reader); - - // retrieve all values before the following code could change them again - Id modeId = Id::fromSetting(SessionManager::value(QLatin1String("ActiveMode"))); - if (!modeId.isValid()) - modeId = Id(Core::Constants::MODE_EDIT); - - QColor c = QColor(SessionManager::sessionValue("Color").toString()); - if (c.isValid()) - StyleHelper::setBaseColor(c); - - SessionManager::sessionLoadingProgress(); - - sb_d->restoreEditors(); - - // let other code restore the session - emit SessionManager::instance()->aboutToLoadSession(session); - - // find a list of projects to close later - const FilePaths fileList = FileUtils::toFilePathList( - SessionManager::sessionValue("ProjectList").toStringList()); - const QList projectsToRemove - = Utils::filtered(projects(), [&fileList](Project *p) { - return !fileList.contains(p->projectFilePath()); - }); - const QList openProjects = projects(); - const FilePaths projectPathsToLoad - = Utils::filtered(fileList, [&openProjects](const FilePath &path) { - return !Utils::contains(openProjects, [&path](Project *p) { - return p->projectFilePath() == path; - }); - }); - - SessionManager::addSessionLoadingSteps(projectPathsToLoad.count()); - - d->restoreProjects(projectPathsToLoad); - SessionManager::sessionLoadingProgress(); - d->restoreDependencies(); - d->restoreStartupProject(); - - removeProjects(projectsToRemove); // only remove old projects now that the startup project is set! - - // Fall back to Project mode if the startup project is unconfigured and - // use the mode saved in the session otherwise - if (d->m_startupProject && d->m_startupProject->needsConfiguration()) - modeId = Id(Constants::MODE_SESSION); - - ModeManager::activateMode(modeId); - ModeManager::setFocusToCurrentMode(); - } else { - removeProjects(projects()); - ModeManager::activateMode(Id(Core::Constants::MODE_EDIT)); - ModeManager::setFocusToCurrentMode(); - } + // not ideal that this is in ProjectManager + Id modeId = Id::fromSetting(SessionManager::value(QLatin1String("ActiveMode"))); + if (!modeId.isValid()) + modeId = Id(Core::Constants::MODE_EDIT); + + // find a list of projects to close later + const FilePaths fileList = FileUtils::toFilePathList( + SessionManager::sessionValue("ProjectList").toStringList()); + const QList projectsToRemove + = Utils::filtered(ProjectManager::projects(), [&fileList](Project *p) { + return !fileList.contains(p->projectFilePath()); + }); + const QList openProjects = ProjectManager::projects(); + const FilePaths projectPathsToLoad + = Utils::filtered(fileList, [&openProjects](const FilePath &path) { + return !Utils::contains(openProjects, + [&path](Project *p) { return p->projectFilePath() == path; }); + }); + + SessionManager::addSessionLoadingSteps(projectPathsToLoad.count()); + + d->restoreProjects(projectPathsToLoad); + d->restoreDependencies(); + d->restoreStartupProject(); + + // only remove old projects now that the startup project is set! + ProjectManager::removeProjects(projectsToRemove); + + // Fall back to Project mode if the startup project is unconfigured and + // use the mode saved in the session otherwise + if (d->m_startupProject && d->m_startupProject->needsConfiguration()) + modeId = Id(Constants::MODE_SESSION); + + ModeManager::activateMode(modeId); + ModeManager::setFocusToCurrentMode(); d->m_casadeSetActive = SessionManager::sessionValue("CascadeSetActive", false).toBool(); - sb_d->m_lastActiveTimes.insert(session, QDateTime::currentDateTime()); - - sb_d->m_future.reportFinished(); - sb_d->m_future = QFutureInterface(); - - emit SessionManager::instance()->sessionLoaded(session); // Starts a event loop, better do that at the very end - d->askUserAboutFailedProjects(); - sb_d->m_loadingSession = false; - return true; + QMetaObject::invokeMethod(m_instance, [this] { askUserAboutFailedProjects(); }); } FilePaths ProjectManager::projectsForSessionName(const QString &session) @@ -901,7 +784,7 @@ void ProjectExplorerPlugin::testSessionSwitch() QVERIFY(sessionSpec.projectFile.open()); sessionSpec.projectFile.write(proFileContents); sessionSpec.projectFile.close(); - QVERIFY(ProjectManager::loadSession(sessionSpec.name)); + QVERIFY(SessionManager::loadSession(sessionSpec.name)); const OpenProjectResult openResult = ProjectExplorerPlugin::openProject( FilePath::fromString(sessionSpec.projectFile.fileName())); @@ -913,16 +796,16 @@ void ProjectExplorerPlugin::testSessionSwitch() QCOMPARE(ProjectManager::projects().count(), 1); } for (int i = 0; i < 30; ++i) { - QVERIFY(ProjectManager::loadSession("session1")); + QVERIFY(SessionManager::loadSession("session1")); QCOMPARE(SessionManager::activeSession(), "session1"); QCOMPARE(ProjectManager::projects().count(), 1); - QVERIFY(ProjectManager::loadSession("session2")); + QVERIFY(SessionManager::loadSession("session2")); QCOMPARE(SessionManager::activeSession(), "session2"); QCOMPARE(ProjectManager::projects().count(), 1); } - QVERIFY(ProjectManager::loadSession("session1")); + QVERIFY(SessionManager::loadSession("session1")); ProjectManager::closeAllProjects(); - QVERIFY(ProjectManager::loadSession("session2")); + QVERIFY(SessionManager::loadSession("session2")); ProjectManager::closeAllProjects(); QVERIFY(SessionManager::deleteSession("session1")); QVERIFY(SessionManager::deleteSession("session2")); diff --git a/src/plugins/projectexplorer/projectmanager.h b/src/plugins/projectexplorer/projectmanager.h index 1aa58d6aa5..7f51586901 100644 --- a/src/plugins/projectexplorer/projectmanager.h +++ b/src/plugins/projectexplorer/projectmanager.h @@ -82,8 +82,6 @@ public: static Utils::FilePaths projectsForSessionName(const QString &session); - static bool loadSession(const QString &session, bool initial = false); - signals: void targetAdded(ProjectExplorer::Target *target); void targetRemoved(ProjectExplorer::Target *target); diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp index a259e5336e..5edd7b4f9d 100644 --- a/src/plugins/projectexplorer/session.cpp +++ b/src/plugins/projectexplorer/session.cpp @@ -213,7 +213,7 @@ bool SessionManager::renameSession(const QString &original, const QString &newNa if (!cloneSession(original, newName)) return false; if (original == activeSession()) - ProjectManager::loadSession(newName); + loadSession(newName); emit instance()->sessionRenamed(original, newName); return deleteSession(original); } @@ -341,7 +341,7 @@ void SessionManagerPrivate::restoreStartupSession() } // !arguments.isEmpty() // Restore latest session or what was passed on the command line - ProjectManager::loadSession(!sessionToRestoreAtStartup.isEmpty() ? sessionToRestoreAtStartup + SessionManager::loadSession(!sessionToRestoreAtStartup.isEmpty() ? sessionToRestoreAtStartup : QString(), true); @@ -446,4 +446,129 @@ void SessionManager::addSessionLoadingSteps(int steps) sb_d->m_future.setProgressRange(0, sb_d->m_future.progressMaximum() + steps); } +/* + * ========== Notes on storing and loading the default session ========== + * The default session comes in two flavors: implicit and explicit. The implicit one, + * also referred to as "default virgin" in the code base, is the one that is active + * at start-up, if no session has been explicitly loaded due to command-line arguments + * or the "restore last session" setting in the session manager. + * The implicit default session silently turns into the explicit default session + * by loading a project or a file or changing settings in the Dependencies panel. The explicit + * default session can also be loaded by the user via the Welcome Screen. + * This mechanism somewhat complicates the handling of session-specific settings such as + * the ones in the task pane: Users expect that changes they make there become persistent, even + * when they are in the implicit default session. However, we can't just blindly store + * the implicit default session, because then we'd overwrite the project list of the explicit + * default session. Therefore, we use the following logic: + * - Upon start-up, if no session is to be explicitly loaded, we restore the parts of the + * explicit default session that are not related to projects, editors etc; the + * "general settings" of the session, so to speak. + * - When storing the implicit default session, we overwrite only these "general settings" + * of the explicit default session and keep the others as they are. + * - When switching from the implicit to the explicit default session, we keep the + * "general settings" and load everything else from the session file. + * This guarantees that user changes are properly transferred and nothing gets lost from + * either the implicit or the explicit default session. + * + */ +bool SessionManager::loadSession(const QString &session, bool initial) +{ + const bool loadImplicitDefault = session.isEmpty(); + const bool switchFromImplicitToExplicitDefault = session == DEFAULT_SESSION + && sb_d->m_sessionName == DEFAULT_SESSION + && !initial; + + // Do nothing if we have that session already loaded, + // exception if the session is the default virgin session + // we still want to be able to load the default session + if (session == sb_d->m_sessionName && !SessionManager::isDefaultVirgin()) + return true; + + if (!loadImplicitDefault && !SessionManager::sessions().contains(session)) + return false; + + // Try loading the file + FilePath fileName = SessionManager::sessionNameToFileName(loadImplicitDefault ? DEFAULT_SESSION + : session); + PersistentSettingsReader reader; + if (fileName.exists()) { + if (!reader.load(fileName)) { + QMessageBox::warning(ICore::dialogParent(), + Tr::tr("Error while restoring session"), + Tr::tr("Could not restore session %1").arg(fileName.toUserOutput())); + + return false; + } + + if (loadImplicitDefault) { + sb_d->restoreValues(reader); + emit SessionManager::instance()->sessionLoaded(DEFAULT_SESSION); + return true; + } + } else if (loadImplicitDefault) { + return true; + } + + sb_d->m_loadingSession = true; + + // Allow everyone to set something in the session and before saving + emit SessionManager::instance()->aboutToUnloadSession(sb_d->m_sessionName); + + if (!ProjectManager::save()) { + sb_d->m_loadingSession = false; + return false; + } + + // Clean up + if (!EditorManager::closeAllEditors()) { + sb_d->m_loadingSession = false; + return false; + } + + if (!switchFromImplicitToExplicitDefault) + sb_d->m_values.clear(); + sb_d->m_sessionValues.clear(); + + sb_d->m_sessionName = session; + delete sb_d->m_writer; + sb_d->m_writer = nullptr; + EditorManager::updateWindowTitles(); + + sb_d->m_virginSession = false; + + ProgressManager::addTask(sb_d->m_future.future(), + Tr::tr("Loading Session"), + "ProjectExplorer.SessionFile.Load"); + + sb_d->m_future.setProgressRange(0, 1 /*initialization*/ + 1 /*editors*/); + sb_d->m_future.setProgressValue(0); + + if (fileName.exists()) { + if (!switchFromImplicitToExplicitDefault) + sb_d->restoreValues(reader); + sb_d->restoreSessionValues(reader); + } + + QColor c = QColor(SessionManager::sessionValue("Color").toString()); + if (c.isValid()) + StyleHelper::setBaseColor(c); + + SessionManager::sessionLoadingProgress(); + + sb_d->restoreEditors(); + + // let other code restore the session + emit SessionManager::instance()->aboutToLoadSession(session); + + sb_d->m_future.reportFinished(); + sb_d->m_future = QFutureInterface(); + + sb_d->m_lastActiveTimes.insert(session, QDateTime::currentDateTime()); + + emit SessionManager::instance()->sessionLoaded(session); + + sb_d->m_loadingSession = false; + return true; +} + } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/session.h b/src/plugins/projectexplorer/session.h index 9af82d066c..b40e687d64 100644 --- a/src/plugins/projectexplorer/session.h +++ b/src/plugins/projectexplorer/session.h @@ -62,6 +62,9 @@ public: static void sessionLoadingProgress(); static void addSessionLoadingSteps(int steps); + + static bool loadSession(const QString &session, bool initial = false); + signals: void startupSessionRestored(); void aboutToUnloadSession(QString sessionName); diff --git a/src/plugins/projectexplorer/sessionmodel.cpp b/src/plugins/projectexplorer/sessionmodel.cpp index 6e22c3b091..960a9dbdee 100644 --- a/src/plugins/projectexplorer/sessionmodel.cpp +++ b/src/plugins/projectexplorer/sessionmodel.cpp @@ -241,7 +241,7 @@ void SessionModel::renameSession(QWidget *parent, const QString &session) void SessionModel::switchToSession(const QString &session) { - ProjectManager::loadSession(session); + SessionManager::loadSession(session); emit sessionSwitched(); } -- cgit v1.2.1