2012-10-02 09:12:39 +02:00
|
|
|
/****************************************************************************
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** This file is part of Qt Creator.
|
2008-12-02 12:01:29 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
** Commercial License Usage
|
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
2016-01-15 14:57:40 +01:00
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
2008-12-02 14:17:16 +01:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** GNU General Public License Usage
|
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
2010-12-17 16:01:08 +01:00
|
|
|
**
|
2012-10-02 09:12:39 +02:00
|
|
|
****************************************************************************/
|
2008-12-02 16:19:05 +01:00
|
|
|
|
|
|
|
|
#include "session.h"
|
|
|
|
|
|
2015-07-28 18:29:52 +02:00
|
|
|
#include "buildconfiguration.h"
|
|
|
|
|
#include "deployconfiguration.h"
|
2017-12-04 10:41:46 +01:00
|
|
|
#include "editorconfiguration.h"
|
|
|
|
|
#include "kit.h"
|
|
|
|
|
#include "project.h"
|
2008-12-02 12:01:29 +01:00
|
|
|
#include "projectexplorer.h"
|
2012-01-31 13:40:59 +01:00
|
|
|
#include "projectnodes.h"
|
2017-12-04 10:41:46 +01:00
|
|
|
#include "target.h"
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2017-12-04 10:41:46 +01:00
|
|
|
#include <coreplugin/coreconstants.h>
|
|
|
|
|
#include <coreplugin/editormanager/editormanager.h>
|
2021-10-21 15:39:28 +02:00
|
|
|
#include <coreplugin/foldernavigationwidget.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
#include <coreplugin/icore.h>
|
2015-02-26 13:38:54 +01:00
|
|
|
#include <coreplugin/idocument.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
#include <coreplugin/imode.h>
|
|
|
|
|
#include <coreplugin/modemanager.h>
|
2017-12-04 10:41:46 +01:00
|
|
|
#include <coreplugin/progressmanager/progressmanager.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2014-09-26 09:14:03 +02:00
|
|
|
#include <texteditor/texteditor.h>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2014-07-07 19:02:26 +02:00
|
|
|
#include <utils/algorithm.h>
|
2012-03-12 13:03:26 +01:00
|
|
|
#include <utils/stylehelper.h>
|
2008-12-09 15:25:01 +01:00
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QDebug>
|
|
|
|
|
#include <QDir>
|
|
|
|
|
#include <QFileInfo>
|
2008-12-09 15:25:01 +01:00
|
|
|
|
2012-02-15 10:42:41 +01:00
|
|
|
#include <QMessageBox>
|
|
|
|
|
#include <QPushButton>
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2019-04-26 14:41:45 +02:00
|
|
|
#ifdef WITH_TESTS
|
|
|
|
|
#include <QTemporaryFile>
|
|
|
|
|
#include <QTest>
|
|
|
|
|
#include <vector>
|
|
|
|
|
#endif
|
|
|
|
|
|
2011-09-02 17:15:18 +02:00
|
|
|
using namespace Core;
|
2013-09-05 11:46:07 +02:00
|
|
|
using namespace Utils;
|
2009-06-03 17:19:26 +02:00
|
|
|
using namespace ProjectExplorer::Internal;
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
namespace ProjectExplorer {
|
|
|
|
|
|
2011-04-14 12:58:14 +02:00
|
|
|
/*!
|
|
|
|
|
\class ProjectExplorer::SessionManager
|
|
|
|
|
|
2013-06-05 14:29:24 +02:00
|
|
|
\brief The SessionManager class manages sessions.
|
2011-04-14 12:58:14 +02:00
|
|
|
|
|
|
|
|
TODO the interface of this class is not really great.
|
2013-09-10 17:16:10 +02:00
|
|
|
The implementation suffers from that all the functions from the
|
|
|
|
|
public interface just wrap around functions which do the actual work.
|
2011-04-14 12:58:14 +02:00
|
|
|
This could be improved.
|
|
|
|
|
*/
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
class SessionManagerPrivate
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
void restoreValues(const PersistentSettingsReader &reader);
|
|
|
|
|
void restoreDependencies(const PersistentSettingsReader &reader);
|
|
|
|
|
void restoreStartupProject(const PersistentSettingsReader &reader);
|
|
|
|
|
void restoreEditors(const PersistentSettingsReader &reader);
|
2021-07-16 17:31:41 +02:00
|
|
|
void restoreProjects(const Utils::FilePaths &fileList);
|
2013-09-05 11:46:07 +02:00
|
|
|
void askUserAboutFailedProjects();
|
|
|
|
|
void sessionLoadingProgress();
|
|
|
|
|
|
|
|
|
|
bool recursiveDependencyCheck(const QString &newDep, const QString &checkDep) const;
|
|
|
|
|
QStringList dependencies(const QString &proName) const;
|
|
|
|
|
QStringList dependenciesOrder() const;
|
|
|
|
|
void dependencies(const QString &proName, QStringList &result) const;
|
|
|
|
|
|
2014-07-23 15:36:55 +02:00
|
|
|
static QString windowTitleAddition(const QString &filePath);
|
2016-11-05 10:30:30 +01:00
|
|
|
static QString sessionTitle(const QString &filePath);
|
2014-07-23 15:36:55 +02:00
|
|
|
|
2017-03-01 17:53:15 +01:00
|
|
|
bool hasProjects() const { return !m_projects.isEmpty(); }
|
|
|
|
|
|
2016-04-15 15:43:44 +02:00
|
|
|
QString m_sessionName = QLatin1String("default");
|
|
|
|
|
bool m_virginSession = true;
|
|
|
|
|
bool m_loadingSession = false;
|
|
|
|
|
bool m_casadeSetActive = false;
|
2013-09-05 11:46:07 +02:00
|
|
|
|
|
|
|
|
mutable QStringList m_sessions;
|
2016-09-23 19:14:50 +02:00
|
|
|
mutable QHash<QString, QDateTime> m_sessionDateTimes;
|
2013-09-05 11:46:07 +02:00
|
|
|
|
2016-04-15 15:43:44 +02:00
|
|
|
Project *m_startupProject = nullptr;
|
2017-03-17 12:26:00 +01:00
|
|
|
QList<Project *> m_projects;
|
2021-07-16 17:31:41 +02:00
|
|
|
FilePaths m_failedProjects;
|
2013-09-05 11:46:07 +02:00
|
|
|
QMap<QString, QStringList> m_depMap;
|
|
|
|
|
QMap<QString, QVariant> m_values;
|
|
|
|
|
QFutureInterface<void> m_future;
|
2016-04-15 15:43:44 +02:00
|
|
|
PersistentSettingsWriter *m_writer = nullptr;
|
2016-11-05 10:30:30 +01:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
static QString locationInProject(const QString &filePath);
|
2013-09-05 11:46:07 +02:00
|
|
|
};
|
|
|
|
|
|
2016-02-26 15:01:51 +01:00
|
|
|
static SessionManager *m_instance = nullptr;
|
|
|
|
|
static SessionManagerPrivate *d = nullptr;
|
2013-09-05 11:46:07 +02:00
|
|
|
|
2017-09-26 10:41:57 +02:00
|
|
|
static QString projectFolderId(Project *pro)
|
|
|
|
|
{
|
2017-09-26 17:19:00 +02:00
|
|
|
return pro->projectFilePath().toString();
|
2017-09-26 10:41:57 +02:00
|
|
|
}
|
|
|
|
|
|
2017-09-26 17:19:00 +02:00
|
|
|
const int PROJECT_SORT_VALUE = 100;
|
|
|
|
|
|
2016-04-13 15:52:14 +02:00
|
|
|
SessionManager::SessionManager(QObject *parent) : QObject(parent)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2013-09-05 11:46:07 +02:00
|
|
|
m_instance = this;
|
|
|
|
|
d = new SessionManagerPrivate;
|
|
|
|
|
|
2015-02-23 14:06:58 +01:00
|
|
|
connect(ModeManager::instance(), &ModeManager::currentModeChanged,
|
|
|
|
|
this, &SessionManager::saveActiveMode);
|
2010-03-03 15:54:32 +01:00
|
|
|
|
2015-02-02 00:37:38 +02:00
|
|
|
connect(EditorManager::instance(), &EditorManager::editorCreated,
|
|
|
|
|
this, &SessionManager::configureEditor);
|
2015-02-23 14:06:58 +01:00
|
|
|
connect(this, &SessionManager::projectAdded,
|
|
|
|
|
EditorManager::instance(), &EditorManager::updateWindowTitles);
|
|
|
|
|
connect(this, &SessionManager::projectRemoved,
|
|
|
|
|
EditorManager::instance(), &EditorManager::updateWindowTitles);
|
|
|
|
|
connect(this, &SessionManager::projectDisplayNameChanged,
|
|
|
|
|
EditorManager::instance(), &EditorManager::updateWindowTitles);
|
|
|
|
|
connect(EditorManager::instance(), &EditorManager::editorOpened,
|
2018-05-25 17:06:42 +02:00
|
|
|
this, &SessionManager::markSessionFileDirty);
|
2015-02-23 14:06:58 +01:00
|
|
|
connect(EditorManager::instance(), &EditorManager::editorsClosed,
|
2018-05-25 17:06:42 +02:00
|
|
|
this, &SessionManager::markSessionFileDirty);
|
2014-07-23 15:36:55 +02:00
|
|
|
|
|
|
|
|
EditorManager::setWindowTitleAdditionHandler(&SessionManagerPrivate::windowTitleAddition);
|
2016-11-05 10:30:30 +01:00
|
|
|
EditorManager::setSessionTitleHandler(&SessionManagerPrivate::sessionTitle);
|
2009-01-20 17:14:00 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
SessionManager::~SessionManager()
|
|
|
|
|
{
|
2019-10-15 14:08:02 +02:00
|
|
|
EditorManager::setWindowTitleAdditionHandler({});
|
|
|
|
|
EditorManager::setSessionTitleHandler({});
|
2013-09-05 11:46:07 +02:00
|
|
|
emit m_instance->aboutToUnloadSession(d->m_sessionName);
|
|
|
|
|
delete d->m_writer;
|
|
|
|
|
delete d;
|
2018-07-16 13:59:39 +02:00
|
|
|
d = nullptr;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2014-10-09 16:46:13 +02:00
|
|
|
SessionManager *SessionManager::instance()
|
2013-09-05 11:46:07 +02:00
|
|
|
{
|
|
|
|
|
return m_instance;
|
|
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
bool SessionManager::isDefaultVirgin()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2013-09-05 11:46:07 +02:00
|
|
|
return isDefaultSession(d->m_sessionName) && d->m_virginSession;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
bool SessionManager::isDefaultSession(const QString &session)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2008-12-09 11:07:24 +01:00
|
|
|
return session == QLatin1String("default");
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2016-03-25 20:00:19 +01:00
|
|
|
void SessionManager::saveActiveMode(Id mode)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2016-03-25 20:00:19 +01:00
|
|
|
if (mode != Core::Constants::MODE_WELCOME)
|
|
|
|
|
setValue(QLatin1String("ActiveMode"), mode.toString());
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
bool SessionManagerPrivate::recursiveDependencyCheck(const QString &newDep, const QString &checkDep) const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
if (newDep == checkDep)
|
|
|
|
|
return false;
|
|
|
|
|
|
2016-02-26 15:01:51 +01:00
|
|
|
foreach (const QString &dependency, m_depMap.value(checkDep)) {
|
2008-12-02 12:01:29 +01:00
|
|
|
if (!recursiveDependencyCheck(newDep, dependency))
|
|
|
|
|
return false;
|
2016-02-26 15:01:51 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-16 16:30:22 +01:00
|
|
|
/*
|
2012-05-03 17:05:38 +02:00
|
|
|
* The dependency management exposes an interface based on projects, but
|
2009-01-16 16:30:22 +01:00
|
|
|
* is internally purely string based. This is suboptimal. Probably it would be
|
|
|
|
|
* nicer to map the filenames to projects on load and only map it back to
|
|
|
|
|
* filenames when saving.
|
|
|
|
|
*/
|
|
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
QList<Project *> SessionManager::dependencies(const Project *project)
|
2009-01-16 16:30:22 +01:00
|
|
|
{
|
2014-05-02 12:22:58 +02:00
|
|
|
const QString proName = project->projectFilePath().toString();
|
2013-09-05 11:46:07 +02:00
|
|
|
const QStringList proDeps = d->m_depMap.value(proName);
|
2009-01-16 16:30:22 +01:00
|
|
|
|
|
|
|
|
QList<Project *> projects;
|
|
|
|
|
foreach (const QString &dep, proDeps) {
|
2019-05-28 13:49:26 +02:00
|
|
|
const Utils::FilePath fn = Utils::FilePath::fromString(dep);
|
2017-12-04 13:53:38 +01:00
|
|
|
Project *pro = Utils::findOrDefault(d->m_projects, [&fn](Project *p) { return p->projectFilePath() == fn; });
|
|
|
|
|
if (pro)
|
2009-01-16 16:30:22 +01:00
|
|
|
projects += pro;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return projects;
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
bool SessionManager::hasDependency(const Project *project, const Project *depProject)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2014-05-02 12:22:58 +02:00
|
|
|
const QString proName = project->projectFilePath().toString();
|
|
|
|
|
const QString depName = depProject->projectFilePath().toString();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
const QStringList proDeps = d->m_depMap.value(proName);
|
2008-12-02 12:01:29 +01:00
|
|
|
return proDeps.contains(depName);
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
bool SessionManager::canAddDependency(const Project *project, const Project *depProject)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2014-05-02 12:22:58 +02:00
|
|
|
const QString newDep = project->projectFilePath().toString();
|
|
|
|
|
const QString checkDep = depProject->projectFilePath().toString();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
return d->recursiveDependencyCheck(newDep, checkDep);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2009-08-06 15:31:32 +02:00
|
|
|
bool SessionManager::addDependency(Project *project, Project *depProject)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2014-05-02 12:22:58 +02:00
|
|
|
const QString proName = project->projectFilePath().toString();
|
|
|
|
|
const QString depName = depProject->projectFilePath().toString();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
// check if this dependency is valid
|
2013-09-05 11:46:07 +02:00
|
|
|
if (!d->recursiveDependencyCheck(proName, depName))
|
2008-12-02 12:01:29 +01:00
|
|
|
return false;
|
|
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
QStringList proDeps = d->m_depMap.value(proName);
|
2008-12-02 12:01:29 +01:00
|
|
|
if (!proDeps.contains(depName)) {
|
|
|
|
|
proDeps.append(depName);
|
2013-09-05 11:46:07 +02:00
|
|
|
d->m_depMap[proName] = proDeps;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
2013-09-05 11:46:07 +02:00
|
|
|
emit m_instance->dependencyChanged(project, depProject);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2009-08-06 15:31:32 +02:00
|
|
|
void SessionManager::removeDependency(Project *project, Project *depProject)
|
2009-01-16 16:30:22 +01:00
|
|
|
{
|
2014-05-02 12:22:58 +02:00
|
|
|
const QString proName = project->projectFilePath().toString();
|
|
|
|
|
const QString depName = depProject->projectFilePath().toString();
|
2009-01-16 16:30:22 +01:00
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
QStringList proDeps = d->m_depMap.value(proName);
|
2009-01-16 16:30:22 +01:00
|
|
|
proDeps.removeAll(depName);
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
if (proDeps.isEmpty())
|
2013-09-05 11:46:07 +02:00
|
|
|
d->m_depMap.remove(proName);
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
else
|
2013-09-05 11:46:07 +02:00
|
|
|
d->m_depMap[proName] = proDeps;
|
|
|
|
|
emit m_instance->dependencyChanged(project, depProject);
|
2009-01-16 16:30:22 +01:00
|
|
|
}
|
|
|
|
|
|
2015-07-28 18:29:52 +02:00
|
|
|
bool SessionManager::isProjectConfigurationCascading()
|
|
|
|
|
{
|
|
|
|
|
return d->m_casadeSetActive;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SessionManager::setProjectConfigurationCascading(bool b)
|
|
|
|
|
{
|
|
|
|
|
d->m_casadeSetActive = b;
|
|
|
|
|
markSessionFileDirty();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SessionManager::setActiveTarget(Project *project, Target *target, SetActive cascade)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(project, return);
|
|
|
|
|
|
2021-05-05 11:18:51 +02:00
|
|
|
if (project->isShuttingDown())
|
|
|
|
|
return;
|
|
|
|
|
|
2015-07-28 18:29:52 +02:00
|
|
|
project->setActiveTarget(target);
|
|
|
|
|
|
|
|
|
|
if (!target) // never cascade setting no target
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (cascade != SetActive::Cascade || !d->m_casadeSetActive)
|
|
|
|
|
return;
|
|
|
|
|
|
2020-06-26 13:59:38 +02:00
|
|
|
Utils::Id kitId = target->kit()->id();
|
2017-03-01 17:53:15 +01:00
|
|
|
for (Project *otherProject : SessionManager::projects()) {
|
2015-07-28 18:29:52 +02:00
|
|
|
if (otherProject == project)
|
|
|
|
|
continue;
|
2016-05-09 13:30:30 +02:00
|
|
|
if (Target *otherTarget = Utils::findOrDefault(otherProject->targets(),
|
|
|
|
|
[kitId](Target *t) { return t->kit()->id() == kitId; }))
|
|
|
|
|
otherProject->setActiveTarget(otherTarget);
|
2015-07-28 18:29:52 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SessionManager::setActiveBuildConfiguration(Target *target, BuildConfiguration *bc, SetActive cascade)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(target, return);
|
2021-05-05 11:18:51 +02:00
|
|
|
QTC_ASSERT(target->project(), return);
|
|
|
|
|
|
|
|
|
|
if (target->project()->isShuttingDown() || target->isShuttingDown())
|
|
|
|
|
return;
|
|
|
|
|
|
2015-07-28 18:29:52 +02:00
|
|
|
target->setActiveBuildConfiguration(bc);
|
|
|
|
|
|
|
|
|
|
if (!bc)
|
|
|
|
|
return;
|
|
|
|
|
if (cascade != SetActive::Cascade || !d->m_casadeSetActive)
|
|
|
|
|
return;
|
|
|
|
|
|
2020-06-26 13:59:38 +02:00
|
|
|
Utils::Id kitId = target->kit()->id();
|
2015-07-28 18:29:52 +02:00
|
|
|
QString name = bc->displayName(); // We match on displayname
|
2017-03-01 17:53:15 +01:00
|
|
|
for (Project *otherProject : SessionManager::projects()) {
|
2015-07-28 18:29:52 +02:00
|
|
|
if (otherProject == target->project())
|
|
|
|
|
continue;
|
|
|
|
|
Target *otherTarget = otherProject->activeTarget();
|
2016-02-17 12:21:41 +01:00
|
|
|
if (!otherTarget || otherTarget->kit()->id() != kitId)
|
2015-07-28 18:29:52 +02:00
|
|
|
continue;
|
|
|
|
|
|
2020-02-28 16:58:37 +01:00
|
|
|
for (BuildConfiguration *otherBc : otherTarget->buildConfigurations()) {
|
2015-07-28 18:29:52 +02:00
|
|
|
if (otherBc->displayName() == name) {
|
|
|
|
|
otherTarget->setActiveBuildConfiguration(otherBc);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SessionManager::setActiveDeployConfiguration(Target *target, DeployConfiguration *dc, SetActive cascade)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(target, return);
|
2021-05-05 11:18:51 +02:00
|
|
|
QTC_ASSERT(target->project(), return);
|
|
|
|
|
|
|
|
|
|
if (target->project()->isShuttingDown() || target->isShuttingDown())
|
|
|
|
|
return;
|
|
|
|
|
|
2015-07-28 18:29:52 +02:00
|
|
|
target->setActiveDeployConfiguration(dc);
|
|
|
|
|
|
|
|
|
|
if (!dc)
|
|
|
|
|
return;
|
|
|
|
|
if (cascade != SetActive::Cascade || !d->m_casadeSetActive)
|
|
|
|
|
return;
|
|
|
|
|
|
2020-06-26 13:59:38 +02:00
|
|
|
Utils::Id kitId = target->kit()->id();
|
2015-07-28 18:29:52 +02:00
|
|
|
QString name = dc->displayName(); // We match on displayname
|
2017-03-01 17:53:15 +01:00
|
|
|
for (Project *otherProject : SessionManager::projects()) {
|
2015-07-28 18:29:52 +02:00
|
|
|
if (otherProject == target->project())
|
|
|
|
|
continue;
|
|
|
|
|
Target *otherTarget = otherProject->activeTarget();
|
2016-02-17 12:21:41 +01:00
|
|
|
if (!otherTarget || otherTarget->kit()->id() != kitId)
|
2015-07-28 18:29:52 +02:00
|
|
|
continue;
|
|
|
|
|
|
2020-02-28 16:58:37 +01:00
|
|
|
for (DeployConfiguration *otherDc : otherTarget->deployConfigurations()) {
|
2015-07-28 18:29:52 +02:00
|
|
|
if (otherDc->displayName() == name) {
|
|
|
|
|
otherTarget->setActiveDeployConfiguration(otherDc);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void SessionManager::setStartupProject(Project *startupProject)
|
|
|
|
|
{
|
2017-10-04 15:11:47 +02:00
|
|
|
QTC_ASSERT((!startupProject && d->m_projects.isEmpty())
|
2017-03-17 12:26:00 +01:00
|
|
|
|| (startupProject && d->m_projects.contains(startupProject)), return);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
if (d->m_startupProject == startupProject)
|
2009-02-03 11:39:18 +01:00
|
|
|
return;
|
|
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
d->m_startupProject = startupProject;
|
2019-07-15 15:47:02 +02:00
|
|
|
if (d->m_startupProject && d->m_startupProject->needsConfiguration()) {
|
|
|
|
|
ModeManager::activateMode(Constants::MODE_SESSION);
|
|
|
|
|
ModeManager::setFocusToCurrentMode();
|
|
|
|
|
}
|
2021-09-29 12:07:22 +02:00
|
|
|
FolderNavigationWidgetFactory::setFallbackSyncFilePath(
|
|
|
|
|
startupProject ? startupProject->projectFilePath().parentDir() : FilePath());
|
2013-09-05 11:46:07 +02:00
|
|
|
emit m_instance->startupProjectChanged(startupProject);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
Project *SessionManager::startupProject()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2013-09-05 11:46:07 +02:00
|
|
|
return d->m_startupProject;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
Target *SessionManager::startupTarget()
|
|
|
|
|
{
|
|
|
|
|
return d->m_startupProject ? d->m_startupProject->activeTarget() : nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BuildSystem *SessionManager::startupBuildSystem()
|
|
|
|
|
{
|
|
|
|
|
Target *t = startupTarget();
|
|
|
|
|
return t ? t->buildSystem() : nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-21 16:32:50 +01:00
|
|
|
/*!
|
|
|
|
|
* Returns the RunConfiguration of the currently active target
|
|
|
|
|
* of the startup project, if such exists, or \c nullptr otherwise.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RunConfiguration *SessionManager::startupRunConfiguration()
|
|
|
|
|
{
|
|
|
|
|
Target *t = startupTarget();
|
|
|
|
|
return t ? t->activeRunConfiguration() : nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-13 11:41:35 +02:00
|
|
|
void SessionManager::addProject(Project *pro)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2016-06-13 11:41:35 +02:00
|
|
|
QTC_ASSERT(pro, return);
|
2018-01-10 12:34:28 +01:00
|
|
|
QTC_CHECK(!pro->displayName().isEmpty());
|
|
|
|
|
QTC_CHECK(pro->id().isValid());
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
d->m_virginSession = false;
|
2017-03-17 12:26:00 +01:00
|
|
|
QTC_ASSERT(!d->m_projects.contains(pro), return);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2017-03-17 12:26:00 +01:00
|
|
|
d->m_projects.append(pro);
|
2016-06-13 11:41:35 +02:00
|
|
|
|
2017-04-07 14:36:22 +02:00
|
|
|
connect(pro, &Project::displayNameChanged,
|
2019-01-16 18:06:21 +01:00
|
|
|
m_instance, [pro]() { emit m_instance->projectDisplayNameChanged(pro); });
|
2016-06-13 11:41:35 +02:00
|
|
|
|
|
|
|
|
emit m_instance->projectAdded(pro);
|
2017-09-26 10:41:57 +02:00
|
|
|
const auto updateFolderNavigation = [pro] {
|
2018-04-20 11:31:58 +02:00
|
|
|
// destructing projects might trigger changes, so check if the project is actually there
|
|
|
|
|
if (QTC_GUARD(d->m_projects.contains(pro))) {
|
|
|
|
|
const QIcon icon = pro->rootProjectNode() ? pro->rootProjectNode()->icon() : QIcon();
|
|
|
|
|
FolderNavigationWidgetFactory::insertRootDirectory({projectFolderId(pro),
|
|
|
|
|
PROJECT_SORT_VALUE,
|
|
|
|
|
pro->displayName(),
|
|
|
|
|
pro->projectFilePath().parentDir(),
|
|
|
|
|
icon});
|
|
|
|
|
}
|
2017-09-26 10:41:57 +02:00
|
|
|
};
|
|
|
|
|
updateFolderNavigation();
|
2016-06-13 11:41:35 +02:00
|
|
|
configureEditors(pro);
|
2018-04-20 11:31:58 +02:00
|
|
|
connect(pro, &Project::fileListChanged, m_instance, [pro, updateFolderNavigation]() {
|
2017-10-09 06:59:54 +02:00
|
|
|
configureEditors(pro);
|
|
|
|
|
updateFolderNavigation(); // update icon
|
|
|
|
|
});
|
2018-04-20 11:31:58 +02:00
|
|
|
connect(pro, &Project::displayNameChanged, m_instance, updateFolderNavigation);
|
2017-10-04 12:00:47 +02:00
|
|
|
|
|
|
|
|
if (!startupProject())
|
|
|
|
|
setStartupProject(pro);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SessionManager::removeProject(Project *project)
|
|
|
|
|
{
|
2013-09-05 11:46:07 +02:00
|
|
|
d->m_virginSession = false;
|
2016-02-26 15:01:51 +01:00
|
|
|
QTC_ASSERT(project, return);
|
2017-03-03 14:40:02 +01:00
|
|
|
removeProjects({project});
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2012-05-31 13:02:08 +02:00
|
|
|
bool SessionManager::loadingSession()
|
|
|
|
|
{
|
2013-09-05 11:46:07 +02:00
|
|
|
return d->m_loadingSession;
|
2012-05-31 13:02:08 +02:00
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
bool SessionManager::save()
|
|
|
|
|
{
|
2013-09-05 11:46:07 +02:00
|
|
|
emit m_instance->aboutToSaveSession();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2019-12-12 11:27:22 +01:00
|
|
|
const FilePath filePath = sessionNameToFileName(d->m_sessionName);
|
2012-08-31 17:01:15 +02:00
|
|
|
QVariantMap data;
|
2012-03-12 13:03:26 +01:00
|
|
|
|
2019-12-12 11:27:22 +01:00
|
|
|
// See the explanation at loadSession() for how we handle the implicit default session.
|
|
|
|
|
if (isDefaultVirgin()) {
|
|
|
|
|
if (filePath.exists()) {
|
|
|
|
|
PersistentSettingsReader reader;
|
|
|
|
|
if (!reader.load(filePath)) {
|
|
|
|
|
QMessageBox::warning(ICore::dialogParent(), tr("Error while saving session"),
|
|
|
|
|
tr("Could not save session %1").arg(filePath.toUserOutput()));
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
data = reader.restoreValues();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// save the startup project
|
|
|
|
|
if (d->m_startupProject) {
|
|
|
|
|
data.insert(QLatin1String("StartupProject"),
|
|
|
|
|
d->m_startupProject->projectFilePath().toString());
|
|
|
|
|
}
|
2012-02-06 15:39:38 +01:00
|
|
|
|
2019-12-12 11:27:22 +01:00
|
|
|
const QColor c = StyleHelper::requestedBaseColor();
|
|
|
|
|
if (c.isValid()) {
|
|
|
|
|
QString tmp = QString::fromLatin1("#%1%2%3")
|
|
|
|
|
.arg(c.red(), 2, 16, QLatin1Char('0'))
|
|
|
|
|
.arg(c.green(), 2, 16, QLatin1Char('0'))
|
|
|
|
|
.arg(c.blue(), 2, 16, QLatin1Char('0'));
|
|
|
|
|
data.insert(QLatin1String("Color"), tmp);
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-16 17:31:41 +02:00
|
|
|
FilePaths projectFiles = Utils::transform(projects(), &Project::projectFilePath);
|
2019-12-12 11:27:22 +01:00
|
|
|
// Restore information on projects that failed to load:
|
|
|
|
|
// don't read projects to the list, which the user loaded
|
2021-07-16 17:31:41 +02:00
|
|
|
for (const FilePath &failed : qAsConst(d->m_failedProjects)) {
|
2019-12-12 11:27:22 +01:00
|
|
|
if (!projectFiles.contains(failed))
|
|
|
|
|
projectFiles << failed;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-16 17:31:41 +02:00
|
|
|
data.insert("ProjectList", Utils::transform<QStringList>(projectFiles,
|
|
|
|
|
&FilePath::toString));
|
|
|
|
|
data.insert("CascadeSetActive", d->m_casadeSetActive);
|
2019-12-12 11:27:22 +01:00
|
|
|
|
|
|
|
|
QVariantMap depMap;
|
|
|
|
|
auto i = d->m_depMap.constBegin();
|
|
|
|
|
while (i != d->m_depMap.constEnd()) {
|
|
|
|
|
QString key = i.key();
|
|
|
|
|
QStringList values;
|
|
|
|
|
foreach (const QString &value, i.value())
|
|
|
|
|
values << value;
|
|
|
|
|
depMap.insert(key, values);
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
data.insert(QLatin1String("ProjectDependencies"), QVariant(depMap));
|
|
|
|
|
data.insert(QLatin1String("EditorSettings"), EditorManager::saveState().toBase64());
|
2012-02-06 15:39:38 +01:00
|
|
|
}
|
|
|
|
|
|
2019-12-12 11:27:22 +01:00
|
|
|
const auto end = d->m_values.constEnd();
|
2012-02-06 15:39:38 +01:00
|
|
|
QStringList keys;
|
2016-04-13 15:52:14 +02:00
|
|
|
for (auto it = d->m_values.constBegin(); it != end; ++it) {
|
2012-08-31 17:01:15 +02:00
|
|
|
data.insert(QLatin1String("value-") + it.key(), it.value());
|
2012-02-06 15:39:38 +01:00
|
|
|
keys << it.key();
|
|
|
|
|
}
|
2012-08-31 17:01:15 +02:00
|
|
|
data.insert(QLatin1String("valueKeys"), keys);
|
2012-02-06 15:39:38 +01:00
|
|
|
|
2019-12-12 11:27:22 +01:00
|
|
|
if (!d->m_writer || d->m_writer->fileName() != filePath) {
|
|
|
|
|
delete d->m_writer;
|
|
|
|
|
d->m_writer = new PersistentSettingsWriter(filePath, "QtCreatorSession");
|
|
|
|
|
}
|
2020-06-02 09:10:40 +02:00
|
|
|
const bool result = d->m_writer->save(data, ICore::dialogParent());
|
2016-09-23 19:14:50 +02:00
|
|
|
if (result) {
|
2019-12-12 11:27:22 +01:00
|
|
|
if (!isDefaultVirgin())
|
|
|
|
|
d->m_sessionDateTimes.insert(activeSession(), QDateTime::currentDateTime());
|
2016-09-23 19:14:50 +02:00
|
|
|
} else {
|
2014-03-11 18:09:23 +01:00
|
|
|
QMessageBox::warning(ICore::dialogParent(), tr("Error while saving session"),
|
2013-09-05 11:46:07 +02:00
|
|
|
tr("Could not save session to file %1").arg(d->m_writer->fileName().toUserOutput()));
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
2012-02-10 12:55:15 +01:00
|
|
|
Closes all projects
|
2008-12-02 12:01:29 +01:00
|
|
|
*/
|
2012-02-10 12:55:15 +01:00
|
|
|
void SessionManager::closeAllProjects()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2012-02-10 12:55:15 +01:00
|
|
|
removeProjects(projects());
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2017-03-01 17:53:15 +01:00
|
|
|
const QList<Project *> SessionManager::projects()
|
2013-09-05 11:46:07 +02:00
|
|
|
{
|
2017-03-17 12:26:00 +01:00
|
|
|
return d->m_projects;
|
2013-09-05 11:46:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SessionManager::hasProjects()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2017-03-01 17:53:15 +01:00
|
|
|
return d->hasProjects();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SessionManager::hasProject(Project *p)
|
|
|
|
|
{
|
2017-03-17 12:26:00 +01:00
|
|
|
return d->m_projects.contains(p);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
QStringList SessionManagerPrivate::dependencies(const QString &proName) const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
QStringList result;
|
2013-07-09 13:45:52 +02:00
|
|
|
dependencies(proName, result);
|
2008-12-02 12:01:29 +01:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
void SessionManagerPrivate::dependencies(const QString &proName, QStringList &result) const
|
2013-07-09 13:45:52 +02:00
|
|
|
{
|
|
|
|
|
QStringList depends = m_depMap.value(proName);
|
|
|
|
|
|
|
|
|
|
foreach (const QString &dep, depends)
|
|
|
|
|
dependencies(dep, result);
|
|
|
|
|
|
|
|
|
|
if (!result.contains(proName))
|
|
|
|
|
result.append(proName);
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-05 10:30:30 +01:00
|
|
|
QString SessionManagerPrivate::sessionTitle(const QString &filePath)
|
2014-07-23 15:36:55 +02:00
|
|
|
{
|
|
|
|
|
if (SessionManager::isDefaultSession(d->m_sessionName)) {
|
|
|
|
|
if (filePath.isEmpty()) {
|
|
|
|
|
// use single project's name if there is only one loaded.
|
2014-10-13 22:37:28 +03:00
|
|
|
const QList<Project *> projects = SessionManager::projects();
|
2014-07-23 15:36:55 +02:00
|
|
|
if (projects.size() == 1)
|
|
|
|
|
return projects.first()->displayName();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
QString sessionName = d->m_sessionName;
|
|
|
|
|
if (sessionName.isEmpty())
|
|
|
|
|
sessionName = SessionManager::tr("Untitled");
|
|
|
|
|
return sessionName;
|
|
|
|
|
}
|
2016-11-05 10:30:30 +01:00
|
|
|
return QString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString SessionManagerPrivate::locationInProject(const QString &filePath) {
|
2019-05-28 13:49:26 +02:00
|
|
|
const Project *project = SessionManager::projectForFile(Utils::FilePath::fromString(filePath));
|
2016-11-05 10:30:30 +01:00
|
|
|
if (!project)
|
|
|
|
|
return QString();
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
const Utils::FilePath file = Utils::FilePath::fromString(filePath);
|
|
|
|
|
const Utils::FilePath parentDir = file.parentDir();
|
2016-11-05 10:30:30 +01:00
|
|
|
if (parentDir == project->projectDirectory())
|
|
|
|
|
return "@ " + project->displayName();
|
|
|
|
|
|
|
|
|
|
if (file.isChildOf(project->projectDirectory())) {
|
2019-05-28 13:49:26 +02:00
|
|
|
const Utils::FilePath dirInProject = parentDir.relativeChildPath(project->projectDirectory());
|
2016-11-05 10:30:30 +01:00
|
|
|
return "(" + dirInProject.toUserOutput() + " @ " + project->displayName() + ")";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// For a file that is "outside" the project it belongs to, we display its
|
|
|
|
|
// dir's full path because it is easier to read than a series of "../../.".
|
|
|
|
|
// Example: /home/hugo/GenericProject/App.files lists /home/hugo/lib/Bar.cpp
|
|
|
|
|
return "(" + parentDir.toUserOutput() + " @ " + project->displayName() + ")";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString SessionManagerPrivate::windowTitleAddition(const QString &filePath)
|
|
|
|
|
{
|
|
|
|
|
return locationInProject(filePath);
|
2014-07-23 15:36:55 +02:00
|
|
|
}
|
|
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
QStringList SessionManagerPrivate::dependenciesOrder() const
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
QList<QPair<QString, QStringList> > unordered;
|
|
|
|
|
QStringList ordered;
|
|
|
|
|
|
|
|
|
|
// copy the map to a temporary list
|
2017-03-17 12:26:00 +01:00
|
|
|
for (const Project *pro : m_projects) {
|
|
|
|
|
const QString proName = pro->projectFilePath().toString();
|
2020-01-29 15:16:10 +01:00
|
|
|
const QStringList depList = filtered(m_depMap.value(proName),
|
|
|
|
|
[this](const QString &proPath) {
|
|
|
|
|
return contains(m_projects, [proPath](const Project *p) {
|
|
|
|
|
return p->projectFilePath().toString() == proPath;
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
unordered << qMakePair(proName, depList);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (!unordered.isEmpty()) {
|
2016-04-13 15:52:14 +02:00
|
|
|
for (int i = (unordered.count() - 1); i >= 0; --i) {
|
2008-12-02 12:01:29 +01:00
|
|
|
if (unordered.at(i).second.isEmpty()) {
|
|
|
|
|
ordered << unordered.at(i).first;
|
|
|
|
|
unordered.removeAt(i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// remove the handled projects from the dependency lists
|
|
|
|
|
// of the remaining unordered projects
|
|
|
|
|
for (int i = 0; i < unordered.count(); ++i) {
|
|
|
|
|
foreach (const QString &pro, ordered) {
|
|
|
|
|
QStringList depList = unordered.at(i).second;
|
|
|
|
|
depList.removeAll(pro);
|
|
|
|
|
unordered[i].second = depList;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ordered;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-16 14:39:07 +01:00
|
|
|
QList<Project *> SessionManager::projectOrder(const Project *project)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
|
|
|
|
QList<Project *> result;
|
|
|
|
|
|
|
|
|
|
QStringList pros;
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
if (project)
|
2014-05-02 12:22:58 +02:00
|
|
|
pros = d->dependencies(project->projectFilePath().toString());
|
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
|
|
|
else
|
2013-09-05 11:46:07 +02:00
|
|
|
pros = d->dependenciesOrder();
|
2008-12-02 12:01:29 +01:00
|
|
|
|
|
|
|
|
foreach (const QString &proFile, pros) {
|
2017-03-01 17:53:15 +01:00
|
|
|
for (Project *pro : projects()) {
|
2014-05-02 12:22:58 +02:00
|
|
|
if (pro->projectFilePath().toString() == proFile) {
|
2008-12-02 12:01:29 +01:00
|
|
|
result << pro;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
Project *SessionManager::projectForFile(const Utils::FilePath &fileName)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2017-12-04 13:53:38 +01:00
|
|
|
return Utils::findOrDefault(SessionManager::projects(),
|
|
|
|
|
[&fileName](const Project *p) { return p->isKnownFile(fileName); });
|
2008-12-05 15:58:19 +01:00
|
|
|
}
|
|
|
|
|
|
2021-05-07 16:10:07 +02:00
|
|
|
Project *SessionManager::projectWithProjectFilePath(const Utils::FilePath &filePath)
|
|
|
|
|
{
|
|
|
|
|
return Utils::findOrDefault(SessionManager::projects(),
|
|
|
|
|
[&filePath](const Project *p) { return p->projectFilePath() == filePath; });
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-03 23:59:04 +02:00
|
|
|
void SessionManager::configureEditor(IEditor *editor, const QString &fileName)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2016-02-26 15:01:51 +01:00
|
|
|
if (auto textEditor = qobject_cast<TextEditor::BaseTextEditor*>(editor)) {
|
2019-05-28 13:49:26 +02:00
|
|
|
Project *project = projectForFile(Utils::FilePath::fromString(fileName));
|
2011-02-01 14:13:54 +01:00
|
|
|
// Global settings are the default.
|
2011-02-03 15:48:14 +01:00
|
|
|
if (project)
|
|
|
|
|
project->editorConfiguration()->configureEditor(textEditor);
|
2011-02-01 14:13:54 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2014-11-04 17:40:29 +01:00
|
|
|
void SessionManager::configureEditors(Project *project)
|
|
|
|
|
{
|
|
|
|
|
foreach (IDocument *document, DocumentModel::openedDocuments()) {
|
2017-12-04 13:02:15 +01:00
|
|
|
if (project->isKnownFile(document->filePath())) {
|
2014-11-04 17:40:29 +01:00
|
|
|
foreach (IEditor *editor, DocumentModel::editorsForDocument(document)) {
|
2016-02-26 15:01:51 +01:00
|
|
|
if (auto textEditor = qobject_cast<TextEditor::BaseTextEditor*>(editor)) {
|
2014-11-04 17:40:29 +01:00
|
|
|
project->editorConfiguration()->configureEditor(textEditor);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-29 12:50:19 +02:00
|
|
|
void SessionManager::removeProjects(const QList<Project *> &remove)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2017-09-29 12:50:19 +02:00
|
|
|
for (Project *pro : remove)
|
2013-09-05 11:46:07 +02:00
|
|
|
emit m_instance->aboutToRemoveProject(pro);
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2017-09-29 12:46:00 +02:00
|
|
|
bool changeStartupProject = false;
|
2011-03-21 18:27:54 +01:00
|
|
|
|
|
|
|
|
// Delete projects
|
2017-09-29 12:50:19 +02:00
|
|
|
for (Project *pro : remove) {
|
2011-03-21 18:27:54 +01:00
|
|
|
pro->saveSettings();
|
2021-05-05 11:18:51 +02:00
|
|
|
pro->markAsShuttingDown();
|
2017-03-03 14:40:02 +01:00
|
|
|
|
2017-03-16 15:03:45 +01:00
|
|
|
// Remove the project node:
|
2017-03-17 12:26:00 +01:00
|
|
|
d->m_projects.removeOne(pro);
|
2011-03-21 18:27:54 +01:00
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
if (pro == d->m_startupProject)
|
2017-09-29 12:46:00 +02:00
|
|
|
changeStartupProject = true;
|
2011-03-21 18:27:54 +01:00
|
|
|
|
2017-09-26 10:41:57 +02:00
|
|
|
FolderNavigationWidgetFactory::removeRootDirectory(projectFolderId(pro));
|
2018-04-20 11:31:58 +02:00
|
|
|
disconnect(pro, nullptr, m_instance, nullptr);
|
|
|
|
|
emit m_instance->projectRemoved(pro);
|
2011-03-21 18:27:54 +01:00
|
|
|
}
|
|
|
|
|
|
2017-09-29 12:46:00 +02:00
|
|
|
if (changeStartupProject)
|
|
|
|
|
setStartupProject(hasProjects() ? projects().first() : nullptr);
|
2017-10-05 16:25:36 +02:00
|
|
|
|
|
|
|
|
qDeleteAll(remove);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2011-04-14 12:58:14 +02:00
|
|
|
/*!
|
2013-09-10 17:16:10 +02:00
|
|
|
Lets other plugins store persistent values within the session file.
|
2011-04-14 12:58:14 +02:00
|
|
|
*/
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
void SessionManager::setValue(const QString &name, const QVariant &value)
|
|
|
|
|
{
|
2013-09-05 11:46:07 +02:00
|
|
|
if (d->m_values.value(name) == value)
|
2010-03-03 15:54:32 +01:00
|
|
|
return;
|
2013-09-05 11:46:07 +02:00
|
|
|
d->m_values.insert(name, value);
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QVariant SessionManager::value(const QString &name)
|
|
|
|
|
{
|
2016-04-13 15:52:14 +02:00
|
|
|
auto it = d->m_values.constFind(name);
|
2013-09-05 11:46:07 +02:00
|
|
|
return (it == d->m_values.constEnd()) ? QVariant() : *it;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
QString SessionManager::activeSession()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2013-09-05 11:46:07 +02:00
|
|
|
return d->m_sessionName;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
QStringList SessionManager::sessions()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2013-09-05 11:46:07 +02:00
|
|
|
if (d->m_sessions.isEmpty()) {
|
2010-01-11 10:22:55 +01:00
|
|
|
// We are not initialized yet, so do that now
|
2021-06-29 17:51:56 +02:00
|
|
|
const FilePaths sessionFiles =
|
|
|
|
|
ICore::userResourcePath().dirEntries({"*.qws"}, QDir::NoFilter, QDir::Time);
|
|
|
|
|
for (const FilePath &file : sessionFiles) {
|
|
|
|
|
const QString &name = file.completeBaseName();
|
|
|
|
|
d->m_sessionDateTimes.insert(name, file.lastModified());
|
2016-09-23 19:14:50 +02:00
|
|
|
if (name != QLatin1String("default"))
|
|
|
|
|
d->m_sessions << name;
|
2009-06-18 11:36:39 +02:00
|
|
|
}
|
2013-09-05 11:46:07 +02:00
|
|
|
d->m_sessions.prepend(QLatin1String("default"));
|
2009-06-18 11:36:39 +02:00
|
|
|
}
|
2013-09-05 11:46:07 +02:00
|
|
|
return d->m_sessions;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2016-09-23 19:14:50 +02:00
|
|
|
QDateTime SessionManager::sessionDateTime(const QString &session)
|
|
|
|
|
{
|
|
|
|
|
return d->m_sessionDateTimes.value(session);
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
FilePath SessionManager::sessionNameToFileName(const QString &session)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2021-04-26 15:46:09 +02:00
|
|
|
return ICore::userResourcePath(session + ".qws");
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2011-04-14 12:58:14 +02:00
|
|
|
/*!
|
2013-09-10 17:16:10 +02:00
|
|
|
Creates \a session, but does not actually create the file.
|
2011-04-14 12:58:14 +02:00
|
|
|
*/
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
bool SessionManager::createSession(const QString &session)
|
|
|
|
|
{
|
|
|
|
|
if (sessions().contains(session))
|
|
|
|
|
return false;
|
2013-09-05 11:46:07 +02:00
|
|
|
Q_ASSERT(d->m_sessions.size() > 0);
|
|
|
|
|
d->m_sessions.insert(1, session);
|
2008-12-02 12:01:29 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2010-04-21 16:08:13 +02:00
|
|
|
bool SessionManager::renameSession(const QString &original, const QString &newName)
|
|
|
|
|
{
|
|
|
|
|
if (!cloneSession(original, newName))
|
|
|
|
|
return false;
|
|
|
|
|
if (original == activeSession())
|
|
|
|
|
loadSession(newName);
|
|
|
|
|
return deleteSession(original);
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-23 15:51:50 +02:00
|
|
|
|
|
|
|
|
/*!
|
|
|
|
|
\brief Shows a dialog asking the user to confirm deleting the session \p session
|
|
|
|
|
*/
|
2019-05-09 16:21:42 +02:00
|
|
|
bool SessionManager::confirmSessionDelete(const QStringList &sessions)
|
2013-05-23 15:51:50 +02:00
|
|
|
{
|
2019-05-09 16:21:42 +02:00
|
|
|
const QString title = sessions.size() == 1 ? tr("Delete Session") : tr("Delete Sessions");
|
|
|
|
|
const QString question = sessions.size() == 1
|
|
|
|
|
? tr("Delete session %1?").arg(sessions.first())
|
|
|
|
|
: tr("Delete these sessions?\n %1").arg(sessions.join("\n "));
|
2020-06-02 09:10:40 +02:00
|
|
|
return QMessageBox::question(ICore::dialogParent(),
|
2019-05-09 16:21:42 +02:00
|
|
|
title,
|
|
|
|
|
question,
|
2013-05-23 15:51:50 +02:00
|
|
|
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes;
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-14 12:58:14 +02:00
|
|
|
/*!
|
2013-09-10 17:16:10 +02:00
|
|
|
Deletes \a session name from session list and the file from disk.
|
2011-04-14 12:58:14 +02:00
|
|
|
*/
|
2008-12-02 12:01:29 +01:00
|
|
|
bool SessionManager::deleteSession(const QString &session)
|
|
|
|
|
{
|
2013-09-05 11:46:07 +02:00
|
|
|
if (!d->m_sessions.contains(session))
|
2008-12-02 12:01:29 +01:00
|
|
|
return false;
|
2013-09-05 11:46:07 +02:00
|
|
|
d->m_sessions.removeOne(session);
|
2012-08-20 18:52:20 +02:00
|
|
|
QFile fi(sessionNameToFileName(session).toString());
|
2008-12-02 12:01:29 +01:00
|
|
|
if (fi.exists())
|
|
|
|
|
return fi.remove();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-09 16:21:42 +02:00
|
|
|
void SessionManager::deleteSessions(const QStringList &sessions)
|
|
|
|
|
{
|
|
|
|
|
for (const QString &session : sessions)
|
|
|
|
|
deleteSession(session);
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
bool SessionManager::cloneSession(const QString &original, const QString &clone)
|
|
|
|
|
{
|
2013-09-05 11:46:07 +02:00
|
|
|
if (!d->m_sessions.contains(original))
|
2008-12-02 12:01:29 +01:00
|
|
|
return false;
|
|
|
|
|
|
2012-08-20 18:52:20 +02:00
|
|
|
QFile fi(sessionNameToFileName(original).toString());
|
2008-12-02 12:01:29 +01:00
|
|
|
// If the file does not exist, we can still clone
|
2012-08-20 18:52:20 +02:00
|
|
|
if (!fi.exists() || fi.copy(sessionNameToFileName(clone).toString())) {
|
2013-09-05 11:46:07 +02:00
|
|
|
d->m_sessions.insert(1, clone);
|
2021-06-17 17:25:38 +02:00
|
|
|
d->m_sessionDateTimes.insert(clone, sessionNameToFileName(clone).lastModified());
|
2008-12-02 12:01:29 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
void SessionManagerPrivate::restoreValues(const PersistentSettingsReader &reader)
|
2012-02-10 12:46:33 +01:00
|
|
|
{
|
2013-09-05 11:46:07 +02:00
|
|
|
const QStringList keys = reader.restoreValue(QLatin1String("valueKeys")).toStringList();
|
2012-02-10 12:46:33 +01:00
|
|
|
foreach (const QString &key, keys) {
|
|
|
|
|
QVariant value = reader.restoreValue(QLatin1String("value-") + key);
|
|
|
|
|
m_values.insert(key, value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
void SessionManagerPrivate::restoreDependencies(const PersistentSettingsReader &reader)
|
2012-02-10 12:46:33 +01:00
|
|
|
{
|
|
|
|
|
QMap<QString, QVariant> depMap = reader.restoreValue(QLatin1String("ProjectDependencies")).toMap();
|
2016-04-13 15:52:14 +02:00
|
|
|
auto i = depMap.constBegin();
|
2012-02-10 12:46:33 +01:00
|
|
|
while (i != depMap.constEnd()) {
|
|
|
|
|
const QString &key = i.key();
|
2020-01-29 15:16:10 +01:00
|
|
|
QStringList values;
|
|
|
|
|
foreach (const QString &value, i.value().toStringList())
|
|
|
|
|
values << value;
|
|
|
|
|
m_depMap.insert(key, values);
|
2012-02-10 12:46:33 +01:00
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
void SessionManagerPrivate::askUserAboutFailedProjects()
|
2012-02-10 12:46:33 +01:00
|
|
|
{
|
2021-07-16 17:31:41 +02:00
|
|
|
FilePaths failedProjects = m_failedProjects;
|
2012-02-10 12:46:33 +01:00
|
|
|
if (!failedProjects.isEmpty()) {
|
2021-07-16 17:31:41 +02:00
|
|
|
QString fileList = FilePath::formatFilePaths(failedProjects, "<br>");
|
2017-02-21 10:04:31 +01:00
|
|
|
QMessageBox box(QMessageBox::Warning,
|
2016-02-26 15:01:51 +01:00
|
|
|
SessionManager::tr("Failed to restore project files"),
|
|
|
|
|
SessionManager::tr("Could not restore the following project files:<br><b>%1</b>").
|
|
|
|
|
arg(fileList));
|
2017-02-21 10:04:31 +01:00
|
|
|
auto keepButton = new QPushButton(SessionManager::tr("Keep projects in Session"), &box);
|
|
|
|
|
auto removeButton = new QPushButton(SessionManager::tr("Remove projects from Session"), &box);
|
|
|
|
|
box.addButton(keepButton, QMessageBox::AcceptRole);
|
|
|
|
|
box.addButton(removeButton, QMessageBox::DestructiveRole);
|
2012-02-10 12:46:33 +01:00
|
|
|
|
2017-02-21 10:04:31 +01:00
|
|
|
box.exec();
|
2012-02-10 12:46:33 +01:00
|
|
|
|
2017-02-21 10:04:31 +01:00
|
|
|
if (box.clickedButton() == removeButton)
|
2012-02-10 12:46:33 +01:00
|
|
|
m_failedProjects.clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
void SessionManagerPrivate::restoreStartupProject(const PersistentSettingsReader &reader)
|
2012-02-10 12:46:33 +01:00
|
|
|
{
|
|
|
|
|
const QString startupProject = reader.restoreValue(QLatin1String("StartupProject")).toString();
|
|
|
|
|
if (!startupProject.isEmpty()) {
|
2021-02-16 22:43:21 +01:00
|
|
|
for (Project *pro : qAsConst(m_projects)) {
|
2017-03-17 12:26:00 +01:00
|
|
|
if (pro->projectFilePath().toString() == startupProject) {
|
|
|
|
|
m_instance->setStartupProject(pro);
|
2012-02-10 12:46:33 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-05-08 17:41:08 +02:00
|
|
|
}
|
|
|
|
|
if (!m_startupProject) {
|
2013-11-11 16:51:58 +01:00
|
|
|
if (!startupProject.isEmpty())
|
|
|
|
|
qWarning() << "Could not find startup project" << startupProject;
|
2017-03-01 17:53:15 +01:00
|
|
|
if (hasProjects())
|
2017-03-17 12:26:00 +01:00
|
|
|
m_instance->setStartupProject(m_projects.first());
|
2012-02-10 12:46:33 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
void SessionManagerPrivate::restoreEditors(const PersistentSettingsReader &reader)
|
2012-02-10 12:46:33 +01:00
|
|
|
{
|
2013-09-05 11:46:07 +02:00
|
|
|
const QVariant editorsettings = reader.restoreValue(QLatin1String("EditorSettings"));
|
2012-02-10 12:46:33 +01:00
|
|
|
if (editorsettings.isValid()) {
|
2013-08-29 17:17:24 +02:00
|
|
|
EditorManager::restoreState(QByteArray::fromBase64(editorsettings.toByteArray()));
|
2013-07-08 16:26:29 +02:00
|
|
|
sessionLoadingProgress();
|
2012-02-10 12:46:33 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-14 12:58:14 +02:00
|
|
|
/*!
|
2013-09-10 17:16:10 +02:00
|
|
|
Loads a session, takes a session name (not filename).
|
2011-04-14 12:58:14 +02:00
|
|
|
*/
|
2021-07-16 17:31:41 +02:00
|
|
|
void SessionManagerPrivate::restoreProjects(const FilePaths &fileList)
|
2012-02-10 12:46:33 +01:00
|
|
|
{
|
|
|
|
|
// indirectly adds projects to session
|
|
|
|
|
// Keep projects that failed to load in the session!
|
|
|
|
|
m_failedProjects = fileList;
|
|
|
|
|
if (!fileList.isEmpty()) {
|
2015-08-20 14:47:02 +02:00
|
|
|
ProjectExplorerPlugin::OpenProjectResult result = ProjectExplorerPlugin::openProjects(fileList);
|
|
|
|
|
if (!result)
|
|
|
|
|
ProjectExplorerPlugin::showOpenProjectError(result);
|
|
|
|
|
foreach (Project *p, result.projects())
|
2021-07-16 17:31:41 +02:00
|
|
|
m_failedProjects.removeAll(p->projectFilePath());
|
2012-02-10 12:46:33 +01:00
|
|
|
}
|
|
|
|
|
}
|
2011-04-14 12:58:14 +02:00
|
|
|
|
2019-12-12 11:27:22 +01:00
|
|
|
/*
|
|
|
|
|
* ========== 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)
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2019-12-12 11:27:22 +01:00
|
|
|
const bool loadImplicitDefault = session.isEmpty();
|
|
|
|
|
const bool switchFromImplicitToExplicitDefault = session == "default"
|
|
|
|
|
&& d->m_sessionName == "default" && !initial;
|
|
|
|
|
|
2008-12-02 12:01:29 +01:00
|
|
|
// 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
|
2013-09-05 11:46:07 +02:00
|
|
|
if (session == d->m_sessionName && !isDefaultVirgin())
|
2008-12-02 12:01:29 +01:00
|
|
|
return true;
|
|
|
|
|
|
2019-12-12 11:27:22 +01:00
|
|
|
if (!loadImplicitDefault && !sessions().contains(session))
|
2008-12-02 12:01:29 +01:00
|
|
|
return false;
|
2011-11-09 17:03:00 +01:00
|
|
|
|
2021-07-16 17:31:41 +02:00
|
|
|
FilePaths fileList;
|
2012-02-10 12:46:33 +01:00
|
|
|
// Try loading the file
|
2019-12-12 11:27:22 +01:00
|
|
|
FilePath fileName = sessionNameToFileName(loadImplicitDefault ? "default" : session);
|
2012-02-10 12:46:33 +01:00
|
|
|
PersistentSettingsReader reader;
|
2014-10-24 13:15:54 +02:00
|
|
|
if (fileName.exists()) {
|
2012-02-10 12:46:33 +01:00
|
|
|
if (!reader.load(fileName)) {
|
2014-03-11 18:09:23 +01:00
|
|
|
QMessageBox::warning(ICore::dialogParent(), tr("Error while restoring session"),
|
2012-08-20 18:52:20 +02:00
|
|
|
tr("Could not restore session %1").arg(fileName.toUserOutput()));
|
2015-08-20 16:27:19 +02:00
|
|
|
|
2012-02-10 12:46:33 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
2019-12-12 11:27:22 +01:00
|
|
|
|
|
|
|
|
if (loadImplicitDefault) {
|
|
|
|
|
d->restoreValues(reader);
|
|
|
|
|
emit m_instance->sessionLoaded("default");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-16 17:31:41 +02:00
|
|
|
fileList = Utils::transform(reader.restoreValue("ProjectList").toStringList(),
|
|
|
|
|
&FilePath::fromString);
|
2019-12-12 11:27:22 +01:00
|
|
|
} else if (loadImplicitDefault) {
|
|
|
|
|
return true;
|
2012-02-10 12:46:33 +01:00
|
|
|
}
|
|
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
d->m_loadingSession = true;
|
2012-05-31 13:02:08 +02:00
|
|
|
|
2012-02-10 12:46:33 +01:00
|
|
|
// Allow everyone to set something in the session and before saving
|
2013-09-05 11:46:07 +02:00
|
|
|
emit m_instance->aboutToUnloadSession(d->m_sessionName);
|
2012-02-10 12:46:33 +01:00
|
|
|
|
2016-10-11 15:34:06 +03:00
|
|
|
if (!save()) {
|
|
|
|
|
d->m_loadingSession = false;
|
|
|
|
|
return false;
|
2012-02-10 12:46:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Clean up
|
2013-08-29 17:17:24 +02:00
|
|
|
if (!EditorManager::closeAllEditors()) {
|
2013-09-05 11:46:07 +02:00
|
|
|
d->m_loadingSession = false;
|
2012-02-10 12:46:33 +01:00
|
|
|
return false;
|
2012-05-31 13:02:08 +02:00
|
|
|
}
|
2012-02-10 12:46:33 +01:00
|
|
|
|
2017-10-04 15:11:47 +02:00
|
|
|
// find a list of projects to close later
|
2017-10-18 16:06:53 +02:00
|
|
|
const QList<Project *> projectsToRemove = Utils::filtered(projects(), [&fileList](Project *p) {
|
2021-07-16 17:31:41 +02:00
|
|
|
return !fileList.contains(p->projectFilePath());
|
2017-10-18 16:06:53 +02:00
|
|
|
});
|
|
|
|
|
const QList<Project *> openProjects = projects();
|
2021-07-16 17:31:41 +02:00
|
|
|
const FilePaths projectPathsToLoad = Utils::filtered(fileList, [&openProjects](const FilePath &path) {
|
2017-10-18 16:06:53 +02:00
|
|
|
return !Utils::contains(openProjects, [&path](Project *p) {
|
2021-07-16 17:31:41 +02:00
|
|
|
return p->projectFilePath() == path;
|
2017-10-18 16:06:53 +02:00
|
|
|
});
|
2017-10-04 15:11:47 +02:00
|
|
|
});
|
2013-09-05 11:46:07 +02:00
|
|
|
d->m_failedProjects.clear();
|
|
|
|
|
d->m_depMap.clear();
|
2019-12-12 11:27:22 +01:00
|
|
|
if (!switchFromImplicitToExplicitDefault)
|
|
|
|
|
d->m_values.clear();
|
2015-07-28 18:29:52 +02:00
|
|
|
d->m_casadeSetActive = false;
|
2011-11-09 17:03:00 +01:00
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
d->m_sessionName = session;
|
2015-04-15 15:38:20 +02:00
|
|
|
delete d->m_writer;
|
2016-02-26 15:01:51 +01:00
|
|
|
d->m_writer = nullptr;
|
2014-07-23 15:36:55 +02:00
|
|
|
EditorManager::updateWindowTitles();
|
2012-02-10 12:46:33 +01:00
|
|
|
|
2014-10-24 13:15:54 +02:00
|
|
|
if (fileName.exists()) {
|
2013-09-05 11:46:07 +02:00
|
|
|
d->m_virginSession = false;
|
2012-02-10 12:46:33 +01:00
|
|
|
|
2014-04-17 15:14:14 +02:00
|
|
|
ProgressManager::addTask(d->m_future.future(), tr("Loading Session"),
|
2013-09-03 15:18:37 +02:00
|
|
|
"ProjectExplorer.SessionFile.Load");
|
2012-02-10 12:46:33 +01:00
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
d->m_future.setProgressRange(0, 1);
|
|
|
|
|
d->m_future.setProgressValue(0);
|
2013-07-08 16:26:29 +02:00
|
|
|
|
2019-12-12 11:27:22 +01:00
|
|
|
if (!switchFromImplicitToExplicitDefault)
|
|
|
|
|
d->restoreValues(reader);
|
2013-09-05 11:46:07 +02:00
|
|
|
emit m_instance->aboutToLoadSession(session);
|
2012-02-10 12:46:33 +01:00
|
|
|
|
2015-03-11 17:32:27 +01:00
|
|
|
// retrieve all values before the following code could change them again
|
|
|
|
|
Id modeId = Id::fromSetting(value(QLatin1String("ActiveMode")));
|
2015-11-12 14:02:20 +01:00
|
|
|
if (!modeId.isValid())
|
|
|
|
|
modeId = Id(Core::Constants::MODE_EDIT);
|
2015-03-11 17:32:27 +01:00
|
|
|
|
2012-03-12 13:03:26 +01:00
|
|
|
QColor c = QColor(reader.restoreValue(QLatin1String("Color")).toString());
|
|
|
|
|
if (c.isValid())
|
2013-09-05 11:46:07 +02:00
|
|
|
StyleHelper::setBaseColor(c);
|
2012-03-12 13:03:26 +01:00
|
|
|
|
2017-10-18 16:06:53 +02:00
|
|
|
d->m_future.setProgressRange(0, projectPathsToLoad.count() + 1/*initialization above*/ + 1/*editors*/);
|
2013-09-05 11:46:07 +02:00
|
|
|
d->m_future.setProgressValue(1);
|
2013-02-12 14:25:21 +01:00
|
|
|
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
2019-04-26 16:46:09 +02:00
|
|
|
|
2017-10-18 16:06:53 +02:00
|
|
|
d->restoreProjects(projectPathsToLoad);
|
2013-09-05 11:46:07 +02:00
|
|
|
d->sessionLoadingProgress();
|
|
|
|
|
d->restoreDependencies(reader);
|
|
|
|
|
d->restoreStartupProject(reader);
|
2017-10-04 15:11:47 +02:00
|
|
|
|
2017-10-18 16:06:53 +02:00
|
|
|
removeProjects(projectsToRemove); // only remove old projects now that the startup project is set!
|
2017-10-04 15:11:47 +02:00
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
d->restoreEditors(reader);
|
2012-02-10 12:46:33 +01:00
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
d->m_future.reportFinished();
|
|
|
|
|
d->m_future = QFutureInterface<void>();
|
2012-02-10 12:46:33 +01:00
|
|
|
|
2015-11-12 14:02:20 +01:00
|
|
|
// 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);
|
2012-02-10 12:46:33 +01:00
|
|
|
|
2012-05-07 18:28:03 +02:00
|
|
|
ModeManager::activateMode(modeId);
|
2012-02-10 12:46:33 +01:00
|
|
|
ModeManager::setFocusToCurrentMode();
|
|
|
|
|
} else {
|
2017-10-18 16:06:53 +02:00
|
|
|
removeProjects(projects());
|
2012-05-07 18:28:03 +02:00
|
|
|
ModeManager::activateMode(Id(Core::Constants::MODE_EDIT));
|
2012-02-10 12:46:33 +01:00
|
|
|
ModeManager::setFocusToCurrentMode();
|
|
|
|
|
}
|
2015-07-28 18:29:52 +02:00
|
|
|
|
|
|
|
|
d->m_casadeSetActive = reader.restoreValue(QLatin1String("CascadeSetActive"), false).toBool();
|
|
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
emit m_instance->sessionLoaded(session);
|
2012-02-10 12:46:33 +01:00
|
|
|
|
|
|
|
|
// Starts a event loop, better do that at the very end
|
2013-09-05 11:46:07 +02:00
|
|
|
d->askUserAboutFailedProjects();
|
|
|
|
|
d->m_loadingSession = false;
|
2012-02-10 12:46:33 +01:00
|
|
|
return true;
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2020-01-08 10:51:06 +01:00
|
|
|
/*!
|
|
|
|
|
Returns the last session that was opened by the user.
|
|
|
|
|
*/
|
2013-09-05 11:46:07 +02:00
|
|
|
QString SessionManager::lastSession()
|
2008-12-02 12:01:29 +01:00
|
|
|
{
|
2020-01-07 12:34:31 +01:00
|
|
|
return ICore::settings()->value(Constants::LASTSESSION_KEY).toString();
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-08 10:51:06 +01:00
|
|
|
/*!
|
|
|
|
|
Returns the session that was active when Qt Creator was last closed, if any.
|
|
|
|
|
*/
|
2020-01-07 12:34:31 +01:00
|
|
|
QString SessionManager::startupSession()
|
|
|
|
|
{
|
|
|
|
|
return ICore::settings()->value(Constants::STARTUPSESSION_KEY).toString();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SessionManager::reportProjectLoadingProgress()
|
|
|
|
|
{
|
2013-09-05 11:46:07 +02:00
|
|
|
d->sessionLoadingProgress();
|
2008-12-02 12:01:29 +01:00
|
|
|
}
|
|
|
|
|
|
2018-05-25 17:06:42 +02:00
|
|
|
void SessionManager::markSessionFileDirty()
|
2010-03-03 15:54:32 +01:00
|
|
|
{
|
2018-05-25 17:06:42 +02:00
|
|
|
d->m_virginSession = false;
|
2010-03-03 15:54:32 +01:00
|
|
|
}
|
2008-12-02 12:01:29 +01:00
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
void SessionManagerPrivate::sessionLoadingProgress()
|
2012-02-06 16:45:03 +01:00
|
|
|
{
|
2012-02-06 17:26:31 +01:00
|
|
|
m_future.setProgressValue(m_future.progressValue() + 1);
|
2012-02-06 16:45:03 +01:00
|
|
|
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
|
|
|
|
}
|
2012-02-23 17:50:30 +01:00
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
QStringList SessionManager::projectsForSessionName(const QString &session)
|
2012-02-23 17:50:30 +01:00
|
|
|
{
|
2019-05-28 13:49:26 +02:00
|
|
|
const FilePath fileName = sessionNameToFileName(session);
|
2012-02-23 17:50:30 +01:00
|
|
|
PersistentSettingsReader reader;
|
2014-10-24 13:15:54 +02:00
|
|
|
if (fileName.exists()) {
|
2012-02-23 17:50:30 +01:00
|
|
|
if (!reader.load(fileName)) {
|
2012-08-20 18:52:20 +02:00
|
|
|
qWarning() << "Could not restore session" << fileName.toUserOutput();
|
2012-02-23 17:50:30 +01:00
|
|
|
return QStringList();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return reader.restoreValue(QLatin1String("ProjectList")).toStringList();
|
|
|
|
|
}
|
2013-09-05 11:46:07 +02:00
|
|
|
|
2019-04-26 14:41:45 +02:00
|
|
|
#ifdef WITH_TESTS
|
|
|
|
|
|
|
|
|
|
void ProjectExplorerPlugin::testSessionSwitch()
|
|
|
|
|
{
|
|
|
|
|
QVERIFY(SessionManager::createSession("session1"));
|
|
|
|
|
QVERIFY(SessionManager::createSession("session2"));
|
|
|
|
|
QTemporaryFile cppFile("main.cpp");
|
|
|
|
|
QVERIFY(cppFile.open());
|
|
|
|
|
cppFile.close();
|
|
|
|
|
QTemporaryFile projectFile1("XXXXXX.pro");
|
|
|
|
|
QTemporaryFile projectFile2("XXXXXX.pro");
|
|
|
|
|
struct SessionSpec {
|
|
|
|
|
SessionSpec(const QString &n, QTemporaryFile &f) : name(n), projectFile(f) {}
|
|
|
|
|
const QString name;
|
|
|
|
|
QTemporaryFile &projectFile;
|
|
|
|
|
};
|
|
|
|
|
std::vector<SessionSpec> sessionSpecs{SessionSpec("session1", projectFile1),
|
|
|
|
|
SessionSpec("session2", projectFile2)};
|
|
|
|
|
for (const SessionSpec &sessionSpec : sessionSpecs) {
|
|
|
|
|
static const QByteArray proFileContents
|
|
|
|
|
= "TEMPLATE = app\n"
|
|
|
|
|
"CONFIG -= qt\n"
|
|
|
|
|
"SOURCES = " + cppFile.fileName().toLocal8Bit();
|
|
|
|
|
QVERIFY(sessionSpec.projectFile.open());
|
|
|
|
|
sessionSpec.projectFile.write(proFileContents);
|
|
|
|
|
sessionSpec.projectFile.close();
|
|
|
|
|
QVERIFY(SessionManager::loadSession(sessionSpec.name));
|
|
|
|
|
const OpenProjectResult openResult
|
2021-07-16 17:31:41 +02:00
|
|
|
= ProjectExplorerPlugin::openProject(
|
|
|
|
|
FilePath::fromString(sessionSpec.projectFile.fileName()));
|
2019-04-26 14:41:45 +02:00
|
|
|
if (openResult.errorMessage().contains("text/plain"))
|
|
|
|
|
QSKIP("This test requires the presence of QmakeProjectManager to be fully functional");
|
|
|
|
|
QVERIFY(openResult);
|
|
|
|
|
QCOMPARE(openResult.projects().count(), 1);
|
|
|
|
|
QVERIFY(openResult.project());
|
|
|
|
|
QCOMPARE(SessionManager::projects().count(), 1);
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < 30; ++i) {
|
|
|
|
|
QVERIFY(SessionManager::loadSession("session1"));
|
|
|
|
|
QCOMPARE(SessionManager::activeSession(), "session1");
|
|
|
|
|
QCOMPARE(SessionManager::projects().count(), 1);
|
|
|
|
|
QVERIFY(SessionManager::loadSession("session2"));
|
|
|
|
|
QCOMPARE(SessionManager::activeSession(), "session2");
|
|
|
|
|
QCOMPARE(SessionManager::projects().count(), 1);
|
|
|
|
|
}
|
|
|
|
|
QVERIFY(SessionManager::loadSession("session1"));
|
|
|
|
|
SessionManager::closeAllProjects();
|
|
|
|
|
QVERIFY(SessionManager::loadSession("session2"));
|
|
|
|
|
SessionManager::closeAllProjects();
|
|
|
|
|
QVERIFY(SessionManager::deleteSession("session1"));
|
|
|
|
|
QVERIFY(SessionManager::deleteSession("session2"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif // WITH_TESTS
|
|
|
|
|
|
2013-09-05 11:46:07 +02:00
|
|
|
} // namespace ProjectExplorer
|