Merge remote-tracking branch 'origin/11.0'

Change-Id: Ic7bd1fb91f46c5f8fef47b2c442382186aeb7ad3
This commit is contained in:
Eike Ziller
2023-05-23 10:17:31 +02:00
71 changed files with 440 additions and 198 deletions

View File

@@ -16,6 +16,7 @@ headerdirs = . \
../src \ ../src \
../../../src/libs/aggregation \ ../../../src/libs/aggregation \
../../../src/libs/extensionsystem \ ../../../src/libs/extensionsystem \
../../../src/libs/solutions/tasking \
../../../src/libs/utils \ ../../../src/libs/utils \
../../../src/plugins/coreplugin ../../../src/plugins/coreplugin
@@ -23,6 +24,7 @@ sourcedirs = . \
../src \ ../src \
../../../src/libs/aggregation \ ../../../src/libs/aggregation \
../../../src/libs/extensionsystem \ ../../../src/libs/extensionsystem \
../../../src/libs/solutions/tasking \
../../../src/libs/utils \ ../../../src/libs/utils \
../../../src/plugins/coreplugin ../../../src/plugins/coreplugin

View File

@@ -34,6 +34,11 @@
for plugins and basic mechanisms for plugin interaction like an for plugins and basic mechanisms for plugin interaction like an
object pool. object pool.
\row
\li \l{Tasking}
\li A solution containing a TaskTree and other classes for writing
declarative trees of asynchronous task flows.
\row \row
\li \l{Utils} \li \l{Utils}
\li Useful classes that are reused in a lot of places in Qt Creator code. \li Useful classes that are reused in a lot of places in Qt Creator code.

View File

@@ -1034,6 +1034,7 @@ void PluginManagerPrivate::readSettings()
*/ */
void PluginManagerPrivate::stopAll() void PluginManagerPrivate::stopAll()
{ {
m_isShuttingDown = true;
if (delayedInitializeTimer && delayedInitializeTimer->isActive()) { if (delayedInitializeTimer && delayedInitializeTimer->isActive()) {
delayedInitializeTimer->stop(); delayedInitializeTimer->stop();
delete delayedInitializeTimer; delete delayedInitializeTimer;
@@ -1839,6 +1840,11 @@ bool PluginManager::isInitializationDone()
return d->m_isInitializationDone; return d->m_isInitializationDone;
} }
bool PluginManager::isShuttingDown()
{
return d->m_isShuttingDown;
}
/*! /*!
Retrieves one object with \a name from the object pool. Retrieves one object with \a name from the object pool.
\sa addObject() \sa addObject()

View File

@@ -129,6 +129,7 @@ public:
static QString platformName(); static QString platformName();
static bool isInitializationDone(); static bool isInitializationDone();
static bool isShuttingDown();
static void remoteArguments(const QString &serializedArguments, QObject *socket); static void remoteArguments(const QString &serializedArguments, QObject *socket);
static void shutdown(); static void shutdown();

View File

@@ -124,6 +124,7 @@ public:
bool m_isInitializationDone = false; bool m_isInitializationDone = false;
bool enableCrashCheck = true; bool enableCrashCheck = true;
bool m_isShuttingDown = false;
QHash<QString, std::function<bool()>> m_scenarios; QHash<QString, std::function<bool()>> m_scenarios;
QString m_requestedScenario; QString m_requestedScenario;

View File

@@ -724,7 +724,16 @@ void TaskNode::invokeEndHandler(bool success)
} }
/*! /*!
\class TaskTree \namespace Tasking
\inmodule QtCreator
\brief The Tasking namespace contains a general purpose TaskTree solution.
The Tasking namespace depends on Qt only, and doesn't depend on any \QC
specific code.
*/
/*!
\class Tasking::TaskTree
\inheaderfile solutions/tasking/tasktree.h \inheaderfile solutions/tasking/tasktree.h
\inmodule QtCreator \inmodule QtCreator
\ingroup mainclasses \ingroup mainclasses
@@ -1180,8 +1189,7 @@ void TaskNode::invokeEndHandler(bool success)
sequential mode). sequential mode).
\li Immediately finishes with an error. \li Immediately finishes with an error.
\endlist \endlist
If all child tasks finish successfully or the group is empty, the group If all child tasks finish successfully, the group finishes with success.
finishes with success.
\row \row
\li continueOnError \li continueOnError
\li Similar to stopOnError, but in case any child finishes with \li Similar to stopOnError, but in case any child finishes with
@@ -1194,8 +1202,7 @@ void TaskNode::invokeEndHandler(bool success)
started yet. started yet.
\li Finishes with an error when all tasks finish. \li Finishes with an error when all tasks finish.
\endlist \endlist
If all tasks finish successfully or the group is empty, the group If all tasks finish successfully, the group finishes with success.
finishes with success.
\row \row
\li stopOnDone \li stopOnDone
\li If a task finishes with success, the group: \li If a task finishes with success, the group:
@@ -1203,8 +1210,7 @@ void TaskNode::invokeEndHandler(bool success)
\li Stops running tasks and skips those that it has not started. \li Stops running tasks and skips those that it has not started.
\li Immediately finishes with success. \li Immediately finishes with success.
\endlist \endlist
If all tasks finish with an error or the group is empty, the group If all tasks finish with an error, the group finishes with an error.
finishes with an error.
\row \row
\li continueOnDone \li continueOnDone
\li Similar to stopOnDone, but in case any child finishes \li Similar to stopOnDone, but in case any child finishes
@@ -1217,22 +1223,22 @@ void TaskNode::invokeEndHandler(bool success)
started yet. started yet.
\li Finishes with success when all tasks finish. \li Finishes with success when all tasks finish.
\endlist \endlist
If all tasks finish with an error or the group is empty, the group If all tasks finish with an error, the group finishes with an error.
finishes with an error.
\row \row
\li stopOnFinished \li stopOnFinished
\li The group starts as many tasks as it can. When a task finishes \li The group starts as many tasks as it can. When a task finishes
the group stops and reports the task's result. the group stops and reports the task's result.
When the group is empty, it finishes immediately with success.
Useful only in parallel mode. Useful only in parallel mode.
In sequential mode, only the first task is started, and when finished, In sequential mode, only the first task is started, and when finished,
the group finishes too, so the other tasks are ignored. the group finishes too, so the other tasks are ignored.
\row \row
\li optional \li optional
\li The group executes all tasks and ignores their return state. If all \li The group executes all tasks and ignores their return state. If all
tasks finish or the group is empty, the group finishes with success. tasks finish, the group finishes with success.
\endtable \endtable
When the group is empty, it finishes immediately with success,
regardless of its workflow policy.
If a child of a group is also a group (in a nested tree), the child group If a child of a group is also a group (in a nested tree), the child group
runs its tasks according to its own workflow policy. runs its tasks according to its own workflow policy.

View File

@@ -9,6 +9,7 @@ namespace Utils {
/*! /*!
\class Utils::AnsiEscapeCodeHandler \class Utils::AnsiEscapeCodeHandler
\inmodule QtCreator
\brief The AnsiEscapeCodeHandler class parses text and extracts ANSI escape codes from it. \brief The AnsiEscapeCodeHandler class parses text and extracts ANSI escape codes from it.

View File

@@ -2328,6 +2328,7 @@ void IntegersAspect::setDefaultValue(const QList<int> &value)
/*! /*!
\class Utils::TextDisplay \class Utils::TextDisplay
\inmodule QtCreator
\brief A text display is a phony aspect with the sole purpose of providing \brief A text display is a phony aspect with the sole purpose of providing
some text display using an Utils::InfoLabel in places where otherwise some text display using an Utils::InfoLabel in places where otherwise

View File

@@ -18,6 +18,7 @@
/*! /*!
\class Utils::CheckableMessageBox \class Utils::CheckableMessageBox
\inmodule QtCreator
\brief The CheckableMessageBox class implements a message box suitable for \brief The CheckableMessageBox class implements a message box suitable for
questions with a questions with a

View File

@@ -10,6 +10,7 @@
/*! /*!
\class Utils::ClassNameValidatingLineEdit \class Utils::ClassNameValidatingLineEdit
\inmodule QtCreator
\brief The ClassNameValidatingLineEdit class implements a line edit that \brief The ClassNameValidatingLineEdit class implements a line edit that
validates a C++ class name and emits a signal validates a C++ class name and emits a signal

View File

@@ -41,6 +41,7 @@ namespace Utils {
/*! /*!
\class Utils::ProcessArgs \class Utils::ProcessArgs
\inmodule QtCreator
\brief The ProcessArgs class provides functionality for dealing with \brief The ProcessArgs class provides functionality for dealing with
shell-quoted process arguments. shell-quoted process arguments.
@@ -217,7 +218,7 @@ static QStringList doSplitArgsWin(const QString &args, ProcessArgs::SplitError *
If \a err is not NULL, stores a status code at the pointer target. For more If \a err is not NULL, stores a status code at the pointer target. For more
information, see \l SplitError. information, see \l SplitError.
If \env is not NULL, performs variable substitution with the If \a env is not NULL, performs variable substitution with the
given environment. given environment.
Returns a list of unquoted words or an empty list if an error occurred. Returns a list of unquoted words or an empty list if an error occurred.
@@ -253,7 +254,6 @@ static QStringList doSplitArgsWin(const QString &args, ProcessArgs::SplitError *
\c{foo " bar}. \c{foo " bar}.
*/ */
static QStringList splitArgsWin(const QString &_args, bool abortOnMeta, static QStringList splitArgsWin(const QString &_args, bool abortOnMeta,
ProcessArgs::SplitError *err, ProcessArgs::SplitError *err,
const Environment *env, const QString *pwd) const Environment *env, const QString *pwd)
@@ -1398,6 +1398,7 @@ QString ProcessArgs::toString() const
/*! /*!
\class Utils::CommandLine \class Utils::CommandLine
\inmodule QtCreator
\brief The CommandLine class represents a command line of a QProcess or \brief The CommandLine class represents a command line of a QProcess or
similar utility. similar utility.

View File

@@ -13,7 +13,9 @@ static bool isEndOfWordChar(const QChar &c)
return !c.isLetterOrNumber() && c.category() != QChar::Punctuation_Connector; return !c.isLetterOrNumber() && c.category() != QChar::Punctuation_Connector;
} }
/*! \class Utils::CompletingTextEdit /*!
\class Utils::CompletingTextEdit
\inmodule QtCreator
\brief The CompletingTextEdit class is a QTextEdit with auto-completion \brief The CompletingTextEdit class is a QTextEdit with auto-completion
support. support.

View File

@@ -20,6 +20,7 @@
/*! /*!
\class Utils::DetailsWidget \class Utils::DetailsWidget
\inmodule QtCreator
\brief The DetailsWidget class implements a button to expand a \e Details \brief The DetailsWidget class implements a button to expand a \e Details
area. area.

View File

@@ -14,10 +14,10 @@ Q_LOGGING_CATEGORY(deviceShellLog, "qtc.utils.deviceshell", QtWarningMsg)
namespace Utils { namespace Utils {
/*! /*
* The multiplex script waits for input via stdin. * The multiplex script waits for input via stdin.
* *
* To start a command, a message is send with * To start a command, a message is sent with
* the format "<cmd-id> "<base64-encoded-stdin-data>" <commandline>\n" * the format "<cmd-id> "<base64-encoded-stdin-data>" <commandline>\n"
* To stop the script, simply send "exit\n" via stdin * To stop the script, simply send "exit\n" via stdin
* *

View File

@@ -9,6 +9,7 @@
/*! /*!
\class Utils::ElidingLabel \class Utils::ElidingLabel
\inmodule QtCreator
\brief The ElidingLabel class is a label suitable for displaying elided \brief The ElidingLabel class is a label suitable for displaying elided
text. text.

View File

@@ -8,6 +8,7 @@
/*! /*!
\class Utils::FakeToolTip \class Utils::FakeToolTip
\inmodule QtCreator
\brief The FakeToolTip class is a widget that pretends to be a tooltip. \brief The FakeToolTip class is a widget that pretends to be a tooltip.

View File

@@ -26,6 +26,7 @@
/*! /*!
\class Utils::FancyLineEdit \class Utils::FancyLineEdit
\inmodule QtCreator
\brief The FancyLineEdit class is an enhanced line edit with several \brief The FancyLineEdit class is an enhanced line edit with several
opt-in features. opt-in features.

View File

@@ -311,7 +311,9 @@ void DockWidget::handleToplevelChanged(bool floating)
/*! \class Utils::FancyMainWindow /*!
\class Utils::FancyMainWindow
\inmodule QtCreator
\brief The FancyMainWindow class is a MainWindow with dock widgets and \brief The FancyMainWindow class is a MainWindow with dock widgets and
additional "lock" functionality additional "lock" functionality

View File

@@ -40,6 +40,7 @@ static bool checkPath(const FilePath &candidate, int matchLength,
/*! /*!
\class Utils::FileInProjectFinder \class Utils::FileInProjectFinder
\inmodule QtCreator
\brief The FileInProjectFinder class is a helper class to find the \e original \brief The FileInProjectFinder class is a helper class to find the \e original
file in the project directory for a given file URL. file in the project directory for a given file URL.

View File

@@ -10,6 +10,7 @@
/*! /*!
\class Utils::FileNameValidatingLineEdit \class Utils::FileNameValidatingLineEdit
\inmodule QtCreator
\brief The FileNameValidatingLineEdit class is a control that lets the user \brief The FileNameValidatingLineEdit class is a control that lets the user
choose a (base) file name, based on a QLineEdit. choose a (base) file name, based on a QLineEdit.

View File

@@ -37,7 +37,9 @@ static DeviceFileHooks s_deviceHooks;
inline bool isWindowsDriveLetter(QChar ch); inline bool isWindowsDriveLetter(QChar ch);
/*! \class Utils::FilePath /*!
\class Utils::FilePath
\inmodule QtCreator
\brief The FilePath class is an abstraction for handles to objects \brief The FilePath class is an abstraction for handles to objects
in a (possibly remote) file system, similar to a URL or, in the local in a (possibly remote) file system, similar to a URL or, in the local
@@ -710,20 +712,39 @@ bool FilePath::isSameFile(const FilePath &other) const
return false; return false;
} }
static FilePaths appendExeExtensions(const Environment &env, const FilePath &executable) static FilePaths appendExeExtensions(const FilePath &executable,
FilePath::MatchScope matchScope)
{ {
FilePaths execs = {executable}; FilePaths result = {executable};
if (executable.osType() == OsTypeWindows) { const QStringView suffix = executable.suffixView();
if (executable.osType() == OsTypeWindows && suffix.isEmpty()) {
switch (matchScope) {
case FilePath::ExactMatchOnly:
break;
case FilePath::WithExeSuffix:
result.append(executable.stringAppended(".exe"));
break;
case FilePath::WithBatSuffix:
result.append(executable.stringAppended(".bat"));
break;
case FilePath::WithExeOrBatSuffix:
result.append(executable.stringAppended(".exe"));
result.append(executable.stringAppended(".bat"));
break;
case FilePath::WithAnySuffix: {
// Check all the executable extensions on windows: // Check all the executable extensions on windows:
// PATHEXT is only used if the executable has no extension // PATHEXT is only used if the executable has no extension
if (executable.suffixView().isEmpty()) { static const QStringList extensions = Environment::systemEnvironment()
const QStringList extensions = env.expandedValueForKey("PATHEXT").split(';'); .expandedValueForKey("PATHEXT").split(';');
for (const QString &ext : extensions) for (const QString &ext : extensions)
execs << executable.stringAppended(ext.toLower()); result.append(executable.stringAppended(ext.toLower()));
break;
}
default:
break;
} }
} }
return execs; return result;
} }
bool FilePath::isSameExecutable(const FilePath &other) const bool FilePath::isSameExecutable(const FilePath &other) const
@@ -734,9 +755,8 @@ bool FilePath::isSameExecutable(const FilePath &other) const
if (!isSameDevice(other)) if (!isSameDevice(other))
return false; return false;
const Environment env = other.deviceEnvironment(); const FilePaths exe1List = appendExeExtensions(*this, WithAnySuffix);
const FilePaths exe1List = appendExeExtensions(env, *this); const FilePaths exe2List = appendExeExtensions(other, WithAnySuffix);
const FilePaths exe2List = appendExeExtensions(env, other);
for (const FilePath &f1 : exe1List) { for (const FilePath &f1 : exe1List) {
for (const FilePath &f2 : exe2List) { for (const FilePath &f2 : exe2List) {
if (f1.isSameFile(f2)) if (f1.isSameFile(f2))
@@ -1478,32 +1498,63 @@ FilePath FilePath::withNewPath(const QString &newPath) const
assert(fullPath == FilePath::fromUrl("docker://123/usr/bin/make")) assert(fullPath == FilePath::fromUrl("docker://123/usr/bin/make"))
\endcode \endcode
*/ */
FilePath FilePath::searchInDirectories(const FilePaths &dirs, const FilePathPredicate &filter) const
FilePath FilePath::searchInDirectories(const FilePaths &dirs,
const FilePathPredicate &filter,
const MatchScope &matchScope) const
{ {
if (isAbsolutePath()) if (isEmpty())
return *this; return {};
return deviceEnvironment().searchInDirectories(path(), dirs, filter);
const FilePaths execs = appendExeExtensions(*this, matchScope);
if (isAbsolutePath()) {
for (const FilePath &filePath : execs) {
if (filePath.isExecutableFile() && (!filter || filter(filePath)))
return filePath;
}
return {};
}
QSet<FilePath> alreadyCheckedDirectories;
for (const FilePath &dir : dirs) {
// Compare the initial size of the set with the size after insertion to check
// if the directory was already checked.
const int initialCount = alreadyCheckedDirectories.count();
alreadyCheckedDirectories.insert(dir);
const bool wasAlreadyChecked = alreadyCheckedDirectories.count() == initialCount;
if (dir.isEmpty() || wasAlreadyChecked)
continue;
for (const FilePath &exe : execs) {
const FilePath filePath = dir / exe.path();
if (filePath.isExecutableFile() && (!filter || filter(filePath)))
return filePath;
}
}
return {};
} }
FilePath FilePath::searchInPath(const FilePaths &additionalDirs, FilePath FilePath::searchInPath(const FilePaths &additionalDirs,
PathAmending amending, PathAmending amending,
const FilePathPredicate &filter) const const FilePathPredicate &filter,
const MatchScope &matchScope) const
{ {
if (isAbsolutePath()) if (isAbsolutePath())
return *this; return *this;
FilePaths directories = deviceEnvironment().path();
if (needsDevice()) { FilePaths directories = devicePathEnvironmentVariable();
directories = Utils::transform(directories, [this](const FilePath &filePath) {
return withNewPath(filePath.path());
});
}
if (!additionalDirs.isEmpty()) { if (!additionalDirs.isEmpty()) {
if (amending == AppendToPath) if (amending == AppendToPath)
directories.append(additionalDirs); directories.append(additionalDirs);
else else
directories = additionalDirs + directories; directories = additionalDirs + directories;
} }
return searchInDirectories(directories, filter); return searchInDirectories(directories, filter, matchScope);
} }
Environment FilePath::deviceEnvironment() const Environment FilePath::deviceEnvironment() const
@@ -1515,6 +1566,16 @@ Environment FilePath::deviceEnvironment() const
return Environment::systemEnvironment(); return Environment::systemEnvironment();
} }
FilePaths FilePath::devicePathEnvironmentVariable() const
{
FilePaths result = deviceEnvironment().path();
if (needsDevice()) {
for (FilePath &dir : result)
dir.setParts(this->scheme(), this->host(), dir.path());
}
return result;
}
QString FilePath::formatFilePaths(const FilePaths &files, const QString &separator) QString FilePath::formatFilePaths(const FilePaths &files, const QString &separator)
{ {
const QStringList nativeFiles = transform(files, &FilePath::toUserOutput); const QStringList nativeFiles = transform(files, &FilePath::toUserOutput);

View File

@@ -161,9 +161,8 @@ public:
[[nodiscard]] FilePath withExecutableSuffix() const; [[nodiscard]] FilePath withExecutableSuffix() const;
[[nodiscard]] FilePath relativeChildPath(const FilePath &parent) const; [[nodiscard]] FilePath relativeChildPath(const FilePath &parent) const;
[[nodiscard]] FilePath relativePathFrom(const FilePath &anchor) const; [[nodiscard]] FilePath relativePathFrom(const FilePath &anchor) const;
[[nodiscard]] FilePath searchInDirectories(const FilePaths &dirs,
const FilePathPredicate &filter = {}) const;
[[nodiscard]] Environment deviceEnvironment() const; [[nodiscard]] Environment deviceEnvironment() const;
[[nodiscard]] FilePaths devicePathEnvironmentVariable() const;
[[nodiscard]] FilePath withNewPath(const QString &newPath) const; [[nodiscard]] FilePath withNewPath(const QString &newPath) const;
[[nodiscard]] FilePath withNewMappedPath(const FilePath &newPath) const; [[nodiscard]] FilePath withNewMappedPath(const FilePath &newPath) const;
@@ -183,12 +182,17 @@ public:
const FileFilter &filter); const FileFilter &filter);
enum PathAmending { AppendToPath, PrependToPath }; enum PathAmending { AppendToPath, PrependToPath };
[[nodiscard]] FilePath searchInPath(const FilePaths &additionalDirs = {},
PathAmending = AppendToPath,
const FilePathPredicate &filter = {}) const;
enum MatchScope { ExactMatchOnly, WithExeSuffix, WithBatSuffix, enum MatchScope { ExactMatchOnly, WithExeSuffix, WithBatSuffix,
WithExeOrBatSuffix, WithAnySuffix }; WithExeOrBatSuffix, WithAnySuffix };
[[nodiscard]] FilePath searchInDirectories(const FilePaths &dirs,
const FilePathPredicate &filter = {},
const MatchScope &matchScope = {}) const;
[[nodiscard]] FilePath searchInPath(const FilePaths &additionalDirs = {},
PathAmending = AppendToPath,
const FilePathPredicate &filter = {},
const MatchScope &matchScope = {}) const;
std::optional<FilePath> refersToExecutableFile(MatchScope considerScript) const; std::optional<FilePath> refersToExecutableFile(MatchScope considerScript) const;
[[nodiscard]] expected_str<FilePath> tmpDir() const; [[nodiscard]] expected_str<FilePath> tmpDir() const;

View File

@@ -28,6 +28,7 @@ static inline quint64 getFileLimit()
/*! /*!
\class Utils::FileSystemWatcher \class Utils::FileSystemWatcher
\inmodule QtCreator
\brief The FileSystemWatcher class is a file watcher that internally uses \brief The FileSystemWatcher class is a file watcher that internally uses
a centralized QFileSystemWatcher a centralized QFileSystemWatcher
and enforces limits on Mac OS. and enforces limits on Mac OS.

View File

@@ -259,7 +259,9 @@ TempFileSaver::~TempFileSaver()
QFile::remove(m_filePath.toString()); QFile::remove(m_filePath.toString());
} }
/*! \class Utils::FileUtils /*!
\class Utils::FileUtils
\inmodule QtCreator
\brief The FileUtils class contains file and directory related convenience \brief The FileUtils class contains file and directory related convenience
functions. functions.

View File

@@ -8,6 +8,7 @@
/*! /*!
\class Utils::FileWizardPage \class Utils::FileWizardPage
\inmodule QtCreator
\brief The FileWizardPage class is a standard wizard page for a single file \brief The FileWizardPage class is a standard wizard page for a single file
letting the user choose name letting the user choose name

View File

@@ -3,7 +3,9 @@
#include "futuresynchronizer.h" #include "futuresynchronizer.h"
/*! \class Utils::FutureSynchronizer /*!
\class Utils::FutureSynchronizer
\inmodule QtCreator
\brief The FutureSynchronizer is an enhanced version of QFutureSynchronizer. \brief The FutureSynchronizer is an enhanced version of QFutureSynchronizer.
*/ */

View File

@@ -4,7 +4,9 @@
#include "guard.h" #include "guard.h"
#include "qtcassert.h" #include "qtcassert.h"
/*! \class Utils::Guard /*!
\class Utils::Guard
\inmodule QtCreator
\brief The Guard class implements a recursive guard with locking mechanism. \brief The Guard class implements a recursive guard with locking mechanism.

View File

@@ -10,6 +10,7 @@ using namespace Utils;
/*! /*!
\class Utils::HeaderViewStretcher \class Utils::HeaderViewStretcher
\inmodule QtCreator
\brief The HeaderViewStretcher class fixes QHeaderView to resize all \brief The HeaderViewStretcher class fixes QHeaderView to resize all
columns to contents, except one columns to contents, except one

View File

@@ -5,6 +5,7 @@
/*! /*!
\class Utils::TreeView \class Utils::TreeView
\inmodule QtCreator
\brief The TreeView adds setActivationMode to QTreeView \brief The TreeView adds setActivationMode to QTreeView
to allow for single click/double click behavior on to allow for single click/double click behavior on
@@ -15,6 +16,7 @@
/*! /*!
\class Utils::TreeWidget \class Utils::TreeWidget
\inmodule QtCreator
\brief The TreeWidget adds setActivationMode to QTreeWidget \brief The TreeWidget adds setActivationMode to QTreeWidget
to allow for single click/double click behavior on to allow for single click/double click behavior on
@@ -25,6 +27,7 @@
/*! /*!
\class Utils::ListView \class Utils::ListView
\inmodule QtCreator
\brief The ListView adds setActivationMode to QListView \brief The ListView adds setActivationMode to QListView
to allow for single click/double click behavior on to allow for single click/double click behavior on
@@ -35,6 +38,7 @@
/*! /*!
\class Utils::ListWidget \class Utils::ListWidget
\inmodule QtCreator
\brief The ListWidget adds setActivationMode to QListWidget \brief The ListWidget adds setActivationMode to QListWidget
to allow for single click/double click behavior on to allow for single click/double click behavior on

View File

@@ -175,6 +175,14 @@ private:
int m_vSpace; int m_vSpace;
}; };
/*!
\namespace Layouting
\inmodule QtCreator
\brief The Layouting namespace contains classes for use with layout builders.
*/
/*! /*!
\class Layouting::LayoutItem \class Layouting::LayoutItem
\inmodule QtCreator \inmodule QtCreator
@@ -469,18 +477,18 @@ void doAddWidget(LayoutBuilder &builder, QWidget *widget)
\class Layouting::Space \class Layouting::Space
\inmodule QtCreator \inmodule QtCreator
\brief The Layouting::Space class represents some empty space in a layout. \brief The Space class represents some empty space in a layout.
*/ */
/*! /*!
\class Layouting::Stretch \class Layouting::Stretch
\inmodule QtCreator \inmodule QtCreator
\brief The Layouting::Stretch class represents some stretch in a layout. \brief The Stretch class represents some stretch in a layout.
*/ */
/*! /*!
\class LayoutBuilder \class Layouting::LayoutBuilder
\inmodule QtCreator \inmodule QtCreator
\brief The LayoutBuilder class provides a convenient way to fill \c QFormLayout \brief The LayoutBuilder class provides a convenient way to fill \c QFormLayout

View File

@@ -104,6 +104,7 @@ using namespace Internal;
/*! /*!
\class Utils::MacroExpander \class Utils::MacroExpander
\inmodule QtCreator
\brief The MacroExpander class manages \QC wide variables, that a user \brief The MacroExpander class manages \QC wide variables, that a user
can enter into many string settings. The variables are replaced by an actual value when the string can enter into many string settings. The variables are replaced by an actual value when the string
is used, similar to how environment variables are expanded by a shell. is used, similar to how environment variables are expanded by a shell.

View File

@@ -9,6 +9,7 @@
/*! /*!
\class Utils::NavigationTreeView \class Utils::NavigationTreeView
\inmodule QtCreator
\brief The NavigationTreeView class implements a general TreeView for any \brief The NavigationTreeView class implements a general TreeView for any
sidebar widget. sidebar widget.

View File

@@ -11,6 +11,7 @@ namespace Utils {
/*! /*!
\class Utils::OptionPushButton \class Utils::OptionPushButton
\inmodule QtCreator
\brief The OptionPushButton class implements a QPushButton for which the menu is only opened \brief The OptionPushButton class implements a QPushButton for which the menu is only opened
if the user presses the menu indicator. if the user presses the menu indicator.

View File

@@ -5,6 +5,7 @@
/*! /*!
\class Utils::ParameterAction \class Utils::ParameterAction
\inmodule QtCreator
\brief The ParameterAction class is intended for actions that act on a 'current', \brief The ParameterAction class is intended for actions that act on a 'current',
string-type parameter (typically a file name), for example 'Save file %1'. string-type parameter (typically a file name), for example 'Save file %1'.

View File

@@ -16,6 +16,7 @@
/*! /*!
\class Utils::PathListEditor \class Utils::PathListEditor
\inmodule QtCreator
\brief The PathListEditor class is a control that lets the user edit a list \brief The PathListEditor class is a control that lets the user edit a list
of (directory) paths of (directory) paths

View File

@@ -50,6 +50,7 @@ static QRect stringToRectangle(const QString &v)
/*! /*!
\class Utils::PersistentSettingsReader \class Utils::PersistentSettingsReader
\inmodule QtCreator
\brief The PersistentSettingsReader class reads a QVariantMap of arbitrary, \brief The PersistentSettingsReader class reads a QVariantMap of arbitrary,
nested data structures from an XML file. nested data structures from an XML file.
@@ -349,6 +350,7 @@ FilePath PersistentSettingsReader::filePath()
/*! /*!
\class Utils::PersistentSettingsWriter \class Utils::PersistentSettingsWriter
\inmodule QtCreator
\brief The PersistentSettingsWriter class serializes a QVariantMap of \brief The PersistentSettingsWriter class serializes a QVariantMap of
arbitrary, nested data structures to an XML file. arbitrary, nested data structures to an XML file.

View File

@@ -10,7 +10,9 @@
#include <limits> #include <limits>
/*! \class Utils::Port /*!
\class Utils::Port
\inmodule QtCreator
\brief The Port class implements a wrapper around a 16 bit port number \brief The Port class implements a wrapper around a 16 bit port number
to be used in conjunction with IP addresses. to be used in conjunction with IP addresses.

View File

@@ -1086,6 +1086,7 @@ ProcessResult ProcessPrivate::interpretExitCode(int exitCode)
/*! /*!
\class Utils::Process \class Utils::Process
\inmodule QtCreator
\brief The Process class provides functionality for with processes. \brief The Process class provides functionality for with processes.
@@ -1596,6 +1597,7 @@ QString Process::readAllStandardError()
/*! /*!
\class Utils::SynchronousProcess \class Utils::SynchronousProcess
\inmodule QtCreator
\brief The SynchronousProcess class runs a synchronous process in its own \brief The SynchronousProcess class runs a synchronous process in its own
event loop that blocks only user input events. Thus, it allows for the GUI to event loop that blocks only user input events. Thus, it allows for the GUI to

View File

@@ -7,6 +7,7 @@ namespace Utils {
/*! /*!
\class Utils::ProcessHandle \class Utils::ProcessHandle
\inmodule QtCreator
\brief The ProcessHandle class is a helper class to describe a process. \brief The ProcessHandle class is a helper class to describe a process.
Encapsulates parameters of a running process, local (PID) or remote (to be Encapsulates parameters of a running process, local (PID) or remote (to be

View File

@@ -22,6 +22,7 @@
/*! /*!
\class Utils::ProjectIntroPage \class Utils::ProjectIntroPage
\inmodule QtCreator
\brief The ProjectIntroPage class is the standard wizard page for a project, \brief The ProjectIntroPage class is the standard wizard page for a project,
letting the user choose its name letting the user choose its name

View File

@@ -7,6 +7,7 @@
/*! /*!
\class Utils::StatusLabel \class Utils::StatusLabel
\inmodule QtCreator
\brief The StatusLabel class displays messages for a while with a timeout. \brief The StatusLabel class displays messages for a while with a timeout.
*/ */

View File

@@ -7,6 +7,7 @@ namespace Utils {
/*! /*!
\class Utils::TextFieldCheckBox \class Utils::TextFieldCheckBox
\inmodule QtCreator
\brief The TextFieldCheckBox class is a aheckbox that plays with \brief The TextFieldCheckBox class is a aheckbox that plays with
\c QWizard::registerField. \c QWizard::registerField.

View File

@@ -9,6 +9,7 @@ namespace Utils {
/*! /*!
\class Utils::TextFieldComboBox \class Utils::TextFieldComboBox
\inmodule QtCreator
\brief The TextFieldComboBox class is a non-editable combo box for text \brief The TextFieldComboBox class is a non-editable combo box for text
editing purposes that plays with \c QWizard::registerField (providing a editing purposes that plays with \c QWizard::registerField (providing a
settable 'text' property). settable 'text' property).

View File

@@ -33,6 +33,7 @@ QDebug operator<<(QDebug d, const TextFileFormat &format)
/*! /*!
\class Utils::TextFileFormat \class Utils::TextFileFormat
\inmodule QtCreator
\brief The TextFileFormat class describes the format of a text file and \brief The TextFileFormat class describes the format of a text file and
provides autodetection. provides autodetection.

View File

@@ -895,6 +895,7 @@ void TreeItem::propagateModel(BaseTreeModel *m)
/*! /*!
\class Utils::TreeModel \class Utils::TreeModel
\inmodule QtCreator
\brief The TreeModel class is a convienience base class for models \brief The TreeModel class is a convienience base class for models
to use in a QTreeView. to use in a QTreeView.

View File

@@ -3,7 +3,8 @@
/*! /*!
\namespace Utils \namespace Utils
\inmodule QtCreator
The Utils namespace contains a collection of utility classes and functions for use by all \brief The Utils namespace contains a collection of utility classes and functions for use by all
plugins. plugins.
*/ */

View File

@@ -23,7 +23,9 @@
#include <QVBoxLayout> #include <QVBoxLayout>
/*! \class Utils::Wizard /*!
\class Utils::Wizard
\inmodule QtCreator
\brief The Wizard class implements a wizard with a progress bar on the left. \brief The Wizard class implements a wizard with a progress bar on the left.

View File

@@ -5,7 +5,9 @@
#include "wizard.h" #include "wizard.h"
/*! \class Utils::WizardPage /*!
\class Utils::WizardPage
\inmodule QtCreator
\brief QWizardPage with a couple of improvements. \brief QWizardPage with a couple of improvements.

View File

@@ -1268,6 +1268,7 @@ LocatorFilterEntries LocatorFileCachePrivate::generate(const QFuture<void> &futu
/*! /*!
\class Core::LocatorFileCache \class Core::LocatorFileCache
\inmodule QtCreator
\brief The LocatorFileCache class encapsulates all the responsibilities needed for \brief The LocatorFileCache class encapsulates all the responsibilities needed for
implementing a cache for file filters. implementing a cache for file filters.

View File

@@ -26,6 +26,8 @@
#include "../settingsdatabase.h" #include "../settingsdatabase.h"
#include "../statusbarmanager.h" #include "../statusbarmanager.h"
#include <extensionsystem/pluginmanager.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/async.h> #include <utils/async.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -147,7 +149,6 @@ bool Locator::delayedInitialize()
void Locator::aboutToShutdown() void Locator::aboutToShutdown()
{ {
m_shuttingDown = true;
m_refreshTimer.stop(); m_refreshTimer.stop();
m_taskTree.reset(); m_taskTree.reset();
} }
@@ -373,7 +374,7 @@ void Locator::setUseCenteredPopupForShortcut(bool center)
void Locator::refresh(const QList<ILocatorFilter *> &filters) void Locator::refresh(const QList<ILocatorFilter *> &filters)
{ {
if (m_shuttingDown) if (ExtensionSystem::PluginManager::isShuttingDown())
return; return;
m_taskTree.reset(); // Superfluous, just for clarity. The next reset() below is enough. m_taskTree.reset(); // Superfluous, just for clarity. The next reset() below is enough.

View File

@@ -67,7 +67,6 @@ private:
bool useCenteredPopup = false; bool useCenteredPopup = false;
}; };
bool m_shuttingDown = false;
bool m_settingsInitialized = false; bool m_settingsInitialized = false;
Settings m_settings; Settings m_settings;
QList<ILocatorFilter *> m_filters; QList<ILocatorFilter *> m_filters;

View File

@@ -70,6 +70,7 @@ void ProcessProgressPrivate::parseProgress(const QString &inputText)
/*! /*!
\class Core::ProcessProgress \class Core::ProcessProgress
\inmodule QtCreator
\brief The ProcessProgress class is responsible for showing progress of the running process. \brief The ProcessProgress class is responsible for showing progress of the running process.

View File

@@ -91,6 +91,7 @@ void TaskProgressPrivate::updateProgress()
/*! /*!
\class Core::TaskProgress \class Core::TaskProgress
\inmodule QtCreator
\brief The TaskProgress class is responsible for showing progress of the running task tree. \brief The TaskProgress class is responsible for showing progress of the running task tree.

View File

@@ -686,7 +686,6 @@ public:
EngineManager m_engineManager; EngineManager m_engineManager;
QTimer m_shutdownTimer; QTimer m_shutdownTimer;
bool m_shuttingDown = false;
Console m_console; // ensure Debugger Console is created before settings are taken into account Console m_console; // ensure Debugger Console is created before settings are taken into account
DebuggerSettings m_debuggerSettings; DebuggerSettings m_debuggerSettings;
@@ -1392,7 +1391,7 @@ static QVariant configValue(const QString &name)
void DebuggerPluginPrivate::updatePresetState() void DebuggerPluginPrivate::updatePresetState()
{ {
if (m_shuttingDown) if (PluginManager::isShuttingDown())
return; return;
Project *startupProject = ProjectManager::startupProject(); Project *startupProject = ProjectManager::startupProject();
@@ -1996,8 +1995,6 @@ void DebuggerPluginPrivate::dumpLog()
void DebuggerPluginPrivate::aboutToShutdown() void DebuggerPluginPrivate::aboutToShutdown()
{ {
m_shuttingDown = true;
disconnect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, this, nullptr); disconnect(ProjectManager::instance(), &ProjectManager::startupProjectChanged, this, nullptr);
m_shutdownTimer.setInterval(0); m_shutdownTimer.setInterval(0);
@@ -2081,7 +2078,7 @@ QWidget *addSearch(BaseTreeView *treeView)
void openTextEditor(const QString &titlePattern0, const QString &contents) void openTextEditor(const QString &titlePattern0, const QString &contents)
{ {
if (dd->m_shuttingDown) if (PluginManager::isShuttingDown())
return; return;
QString titlePattern = titlePattern0; QString titlePattern = titlePattern0;
IEditor *editor = EditorManager::openEditorWithContents( IEditor *editor = EditorManager::openEditorWithContents(

View File

@@ -135,11 +135,6 @@ void EmacsKeysPlugin::extensionsInitialized()
{ {
} }
ExtensionSystem::IPlugin::ShutdownFlag EmacsKeysPlugin::aboutToShutdown()
{
return SynchronousShutdown;
}
void EmacsKeysPlugin::editorAboutToClose(IEditor *editor) void EmacsKeysPlugin::editorAboutToClose(IEditor *editor)
{ {
auto w = qobject_cast<QPlainTextEdit*>(editor->widget()); auto w = qobject_cast<QPlainTextEdit*>(editor->widget());

View File

@@ -57,7 +57,6 @@ public:
void initialize() override; void initialize() override;
void extensionsInitialized() override; void extensionsInitialized() override;
ShutdownFlag aboutToShutdown() override;
private: private:
void editorAboutToClose(Core::IEditor *editor); void editorAboutToClose(Core::IEditor *editor);

View File

@@ -107,12 +107,9 @@ class FossilLogConfig : public VcsBaseEditorConfig
Q_OBJECT Q_OBJECT
public: public:
FossilLogConfig(FossilClient *client, QToolBar *toolBar) : FossilLogConfig(QToolBar *toolBar)
VcsBaseEditorConfig(toolBar), : VcsBaseEditorConfig(toolBar)
m_client(client)
{ {
QTC_ASSERT(client, return);
addReloadButton(); addReloadButton();
addLineageComboBox(); addLineageComboBox();
addVerboseToggleButton(); addVerboseToggleButton();
@@ -192,9 +189,6 @@ public:
} }
return args; return args;
} }
private:
FossilClient *m_client;
}; };
unsigned FossilClient::makeVersionNumber(int major, int minor, int patch) unsigned FossilClient::makeVersionNumber(int major, int minor, int patch)
@@ -1169,7 +1163,7 @@ VcsBaseEditorConfig *FossilClient::createLogCurrentFileEditor(VcsBaseEditorWidge
VcsBaseEditorConfig *FossilClient::createLogEditor(VcsBaseEditorWidget *editor) VcsBaseEditorConfig *FossilClient::createLogEditor(VcsBaseEditorWidget *editor)
{ {
return new FossilLogConfig(this, editor->toolBar()); return new FossilLogConfig(editor->toolBar());
} }
} // namespace Internal } // namespace Internal

View File

@@ -28,6 +28,8 @@
#include <coreplugin/messagemanager.h> #include <coreplugin/messagemanager.h>
#include <coreplugin/progressmanager/progressmanager.h> #include <coreplugin/progressmanager/progressmanager.h>
#include <extensionsystem/pluginmanager.h>
#include <languageserverprotocol/completion.h> #include <languageserverprotocol/completion.h>
#include <languageserverprotocol/diagnostics.h> #include <languageserverprotocol/diagnostics.h>
#include <languageserverprotocol/initializemessages.h> #include <languageserverprotocol/initializemessages.h>
@@ -194,7 +196,7 @@ public:
// temporary container needed since m_resetAssistProvider is changed in resetAssistProviders // temporary container needed since m_resetAssistProvider is changed in resetAssistProviders
for (TextDocument *document : m_resetAssistProvider.keys()) for (TextDocument *document : m_resetAssistProvider.keys())
resetAssistProviders(document); resetAssistProviders(document);
if (!LanguageClientManager::isShuttingDown()) { if (!ExtensionSystem::PluginManager::isShuttingDown()) {
// prevent accessing deleted editors on Creator shutdown // prevent accessing deleted editors on Creator shutdown
const QList<Core::IEditor *> &editors = Core::DocumentModel::editorsForOpenedDocuments(); const QList<Core::IEditor *> &editors = Core::DocumentModel::editorsForOpenedDocuments();
for (Core::IEditor *editor : editors) { for (Core::IEditor *editor : editors) {

View File

@@ -14,6 +14,8 @@
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/navigationwidget.h> #include <coreplugin/navigationwidget.h>
#include <extensionsystem/pluginmanager.h>
#include <languageserverprotocol/messages.h> #include <languageserverprotocol/messages.h>
#include <languageserverprotocol/progresssupport.h> #include <languageserverprotocol/progresssupport.h>
@@ -32,6 +34,7 @@
#include <QTimer> #include <QTimer>
using namespace ExtensionSystem;
using namespace LanguageServerProtocol; using namespace LanguageServerProtocol;
namespace LanguageClient { namespace LanguageClient {
@@ -39,7 +42,6 @@ namespace LanguageClient {
static Q_LOGGING_CATEGORY(Log, "qtc.languageclient.manager", QtWarningMsg) static Q_LOGGING_CATEGORY(Log, "qtc.languageclient.manager", QtWarningMsg)
static LanguageClientManager *managerInstance = nullptr; static LanguageClientManager *managerInstance = nullptr;
static bool g_shuttingDown = false;
class LanguageClientManagerPrivate class LanguageClientManagerPrivate
{ {
@@ -139,7 +141,7 @@ void LanguageClientManager::clientStarted(Client *client)
QTC_ASSERT(client, return); QTC_ASSERT(client, return);
if (client->state() != Client::Uninitialized) // do not proceed if we already received an error if (client->state() != Client::Uninitialized) // do not proceed if we already received an error
return; return;
if (g_shuttingDown) { if (PluginManager::isShuttingDown()) {
clientFinished(client); clientFinished(client);
return; return;
} }
@@ -165,7 +167,7 @@ void LanguageClientManager::clientFinished(Client *client)
&& client->state() != Client::ShutdownRequested; && client->state() != Client::ShutdownRequested;
if (unexpectedFinish) { if (unexpectedFinish) {
if (!g_shuttingDown) { if (!PluginManager::isShuttingDown()) {
const QList<TextEditor::TextDocument *> &clientDocs const QList<TextEditor::TextDocument *> &clientDocs
= managerInstance->m_clientForDocument.keys(client); = managerInstance->m_clientForDocument.keys(client);
if (client->reset()) { if (client->reset()) {
@@ -187,7 +189,7 @@ void LanguageClientManager::clientFinished(Client *client)
} }
} }
deleteClient(client); deleteClient(client);
if (g_shuttingDown && managerInstance->m_clients.isEmpty()) if (PluginManager::isShuttingDown() && managerInstance->m_clients.isEmpty())
emit managerInstance->shutdownFinished(); emit managerInstance->shutdownFinished();
} }
@@ -236,17 +238,14 @@ void LanguageClientManager::deleteClient(Client *client)
for (QList<Client *> &clients : managerInstance->m_clientsForSetting) for (QList<Client *> &clients : managerInstance->m_clientsForSetting)
clients.removeAll(client); clients.removeAll(client);
client->deleteLater(); client->deleteLater();
if (!g_shuttingDown) if (!PluginManager::isShuttingDown())
emit instance()->clientRemoved(client); emit instance()->clientRemoved(client);
} }
void LanguageClientManager::shutdown() void LanguageClientManager::shutdown()
{ {
QTC_ASSERT(managerInstance, return); QTC_ASSERT(managerInstance, return);
if (g_shuttingDown)
return;
qCDebug(Log) << "shutdown manager"; qCDebug(Log) << "shutdown manager";
g_shuttingDown = true;
const auto clients = managerInstance->clients(); const auto clients = managerInstance->clients();
for (Client *client : clients) for (Client *client : clients)
shutdownClient(client); shutdownClient(client);
@@ -258,11 +257,6 @@ void LanguageClientManager::shutdown()
}); });
} }
bool LanguageClientManager::isShuttingDown()
{
return g_shuttingDown;
}
LanguageClientManager *LanguageClientManager::instance() LanguageClientManager *LanguageClientManager::instance()
{ {
return managerInstance; return managerInstance;

View File

@@ -48,7 +48,6 @@ public:
static void deleteClient(Client *client); static void deleteClient(Client *client);
static void shutdown(); static void shutdown();
static bool isShuttingDown();
static LanguageClientManager *instance(); static LanguageClientManager *instance();

View File

@@ -22,9 +22,6 @@
#include <utils/utilsicons.h> #include <utils/utilsicons.h>
#include <utils/variablechooser.h> #include <utils/variablechooser.h>
#include <QCheckBox>
#include <QLabel>
#include <QLineEdit>
#include <QThread> #include <QThread>
#include <optional> #include <optional>

View File

@@ -73,7 +73,6 @@ private:
QStringList jobArguments() const; QStringList jobArguments() const;
Utils::MultiSelectionAspect *m_buildTargetsAspect = nullptr; Utils::MultiSelectionAspect *m_buildTargetsAspect = nullptr;
QStringList m_availableTargets; // FIXME: Unused, remove in 4.15.
Utils::StringAspect *m_makeCommandAspect = nullptr; Utils::StringAspect *m_makeCommandAspect = nullptr;
Utils::StringAspect *m_userArgumentsAspect = nullptr; Utils::StringAspect *m_userArgumentsAspect = nullptr;
Utils::IntegerAspect *m_userJobCountAspect = nullptr; Utils::IntegerAspect *m_userJobCountAspect = nullptr;

View File

@@ -177,6 +177,7 @@
*/ */
using namespace Core; using namespace Core;
using namespace ExtensionSystem;
using namespace ProjectExplorer::Internal; using namespace ProjectExplorer::Internal;
using namespace Utils; using namespace Utils;
@@ -600,7 +601,6 @@ public:
BuildPropertiesSettings m_buildPropertiesSettings; BuildPropertiesSettings m_buildPropertiesSettings;
QList<CustomParserSettings> m_customParsers; QList<CustomParserSettings> m_customParsers;
bool m_shouldHaveRunConfiguration = false; bool m_shouldHaveRunConfiguration = false;
bool m_shuttingDown = false;
Id m_runMode = Constants::NO_RUN_MODE; Id m_runMode = Constants::NO_RUN_MODE;
ToolChainManager *m_toolChainManager = nullptr; ToolChainManager *m_toolChainManager = nullptr;
@@ -1632,11 +1632,11 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er
connect(ICore::instance(), &ICore::saveSettingsRequested, connect(ICore::instance(), &ICore::saveSettingsRequested,
dd, &ProjectExplorerPluginPrivate::savePersistentSettings); dd, &ProjectExplorerPluginPrivate::savePersistentSettings);
connect(EditorManager::instance(), &EditorManager::autoSaved, this, [] { connect(EditorManager::instance(), &EditorManager::autoSaved, this, [] {
if (!dd->m_shuttingDown && !SessionManager::loadingSession()) if (!PluginManager::isShuttingDown() && !SessionManager::loadingSession())
ProjectManager::save(); SessionManager::saveSession();
}); });
connect(qApp, &QApplication::applicationStateChanged, this, [](Qt::ApplicationState state) { connect(qApp, &QApplication::applicationStateChanged, this, [](Qt::ApplicationState state) {
if (!dd->m_shuttingDown && state == Qt::ApplicationActive) if (!PluginManager::isShuttingDown() && state == Qt::ApplicationActive)
dd->updateWelcomePage(); dd->updateWelcomePage();
}); });
@@ -2173,7 +2173,7 @@ void ProjectExplorerPluginPrivate::updateRunWithoutDeployMenu()
m_runWithoutDeployAction->setVisible(m_projectExplorerSettings.deployBeforeRun); m_runWithoutDeployAction->setVisible(m_projectExplorerSettings.deployBeforeRun);
} }
ExtensionSystem::IPlugin::ShutdownFlag ProjectExplorerPlugin::aboutToShutdown() IPlugin::ShutdownFlag ProjectExplorerPlugin::aboutToShutdown()
{ {
disconnect(ModeManager::instance(), &ModeManager::currentModeChanged, disconnect(ModeManager::instance(), &ModeManager::currentModeChanged,
dd, &ProjectExplorerPluginPrivate::currentModeChanged); dd, &ProjectExplorerPluginPrivate::currentModeChanged);
@@ -2181,8 +2181,6 @@ ExtensionSystem::IPlugin::ShutdownFlag ProjectExplorerPlugin::aboutToShutdown()
ToolChainManager::aboutToShutdown(); ToolChainManager::aboutToShutdown();
ProjectManager::closeAllProjects(); ProjectManager::closeAllProjects();
dd->m_shuttingDown = true;
// Attempt to synchronously shutdown all run controls. // Attempt to synchronously shutdown all run controls.
// If that fails, fall back to asynchronous shutdown (Debugger run controls // If that fails, fall back to asynchronous shutdown (Debugger run controls
// might shutdown asynchronously). // might shutdown asynchronously).
@@ -2212,7 +2210,7 @@ void ProjectExplorerPlugin::openNewProjectDialog()
void ProjectExplorerPluginPrivate::showSessionManager() void ProjectExplorerPluginPrivate::showSessionManager()
{ {
ProjectManager::save(); SessionManager::saveSession();
SessionDialog sessionDialog(ICore::dialogParent()); SessionDialog sessionDialog(ICore::dialogParent());
sessionDialog.setAutoLoadSession(sb_d->isAutoRestoreLastSession()); sessionDialog.setAutoLoadSession(sb_d->isAutoRestoreLastSession());
sessionDialog.exec(); sessionDialog.exec();
@@ -2251,14 +2249,14 @@ bool ProjectExplorerPluginPrivate::closeAllFilesInProject(const Project *project
void ProjectExplorerPluginPrivate::savePersistentSettings() void ProjectExplorerPluginPrivate::savePersistentSettings()
{ {
if (dd->m_shuttingDown) if (PluginManager::isShuttingDown())
return; return;
if (!SessionManager::loadingSession()) { if (!SessionManager::loadingSession()) {
for (Project *pro : ProjectManager::projects()) for (Project *pro : ProjectManager::projects())
pro->saveSettings(); pro->saveSettings();
ProjectManager::save(); SessionManager::saveSession();
} }
QtcSettings *s = ICore::settings(); QtcSettings *s = ICore::settings();
@@ -2560,7 +2558,7 @@ void ProjectExplorerPluginPrivate::checkForShutdown()
{ {
--m_activeRunControlCount; --m_activeRunControlCount;
QTC_ASSERT(m_activeRunControlCount >= 0, m_activeRunControlCount = 0); QTC_ASSERT(m_activeRunControlCount >= 0, m_activeRunControlCount = 0);
if (m_shuttingDown && m_activeRunControlCount == 0) if (PluginManager::isShuttingDown() && m_activeRunControlCount == 0)
emit m_instance->asynchronousShutdownFinished(); emit m_instance->asynchronousShutdownFinished();
} }

View File

@@ -53,6 +53,7 @@ class ProjectManagerPrivate
{ {
public: public:
void loadSession(); void loadSession();
void saveSession();
void restoreDependencies(); void restoreDependencies();
void restoreStartupProject(); void restoreStartupProject();
void restoreProjects(const FilePaths &fileList); void restoreProjects(const FilePaths &fileList);
@@ -109,6 +110,9 @@ ProjectManager::ProjectManager()
connect(SessionManager::instance(), &SessionManager::aboutToLoadSession, this, [] { connect(SessionManager::instance(), &SessionManager::aboutToLoadSession, this, [] {
d->loadSession(); d->loadSession();
}); });
connect(SessionManager::instance(), &SessionManager::aboutToSaveSession, this, [] {
d->saveSession();
});
} }
ProjectManager::~ProjectManager() ProjectManager::~ProjectManager()
@@ -315,53 +319,29 @@ void ProjectManager::removeProject(Project *project)
removeProjects({project}); removeProjects({project});
} }
bool ProjectManager::save() void ProjectManagerPrivate::saveSession()
{ {
emit SessionManager::instance()->aboutToSaveSession();
const FilePath filePath = SessionManager::sessionNameToFileName(sb_d->m_sessionName);
QVariantMap data;
// See the explanation at loadSession() for how we handle the implicit default session.
if (SessionManager::isDefaultVirgin()) {
if (filePath.exists()) {
PersistentSettingsReader reader;
if (!reader.load(filePath)) {
QMessageBox::warning(ICore::dialogParent(), Tr::tr("Error while saving session"),
Tr::tr("Could not save session %1").arg(filePath.toUserOutput()));
return false;
}
data = reader.restoreValues();
}
} else {
// save the startup project // save the startup project
if (d->m_startupProject) if (d->m_startupProject)
data.insert("StartupProject", d->m_startupProject->projectFilePath().toSettings()); SessionManager::setSessionValue("StartupProject",
m_startupProject->projectFilePath().toSettings());
const QColor c = StyleHelper::requestedBaseColor(); FilePaths projectFiles = Utils::transform(m_projects, &Project::projectFilePath);
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);
}
FilePaths projectFiles = Utils::transform(projects(), &Project::projectFilePath);
// Restore information on projects that failed to load: // Restore information on projects that failed to load:
// don't read projects to the list, which the user loaded // don't read projects to the list, which the user loaded
for (const FilePath &failed : std::as_const(d->m_failedProjects)) { for (const FilePath &failed : std::as_const(m_failedProjects)) {
if (!projectFiles.contains(failed)) if (!projectFiles.contains(failed))
projectFiles << failed; projectFiles << failed;
} }
data.insert("ProjectList", Utils::transform<QStringList>(projectFiles, SessionManager::setSessionValue("ProjectList",
Utils::transform<QStringList>(projectFiles,
&FilePath::toString)); &FilePath::toString));
data.insert("CascadeSetActive", d->m_casadeSetActive); SessionManager::setSessionValue("CascadeSetActive", m_casadeSetActive);
QVariantMap depMap; QVariantMap depMap;
auto i = d->m_depMap.constBegin(); auto i = m_depMap.constBegin();
while (i != d->m_depMap.constEnd()) { while (i != m_depMap.constEnd()) {
QString key = i.key().toString(); QString key = i.key().toString();
QStringList values; QStringList values;
const FilePaths valueList = i.value(); const FilePaths valueList = i.value();
@@ -370,32 +350,7 @@ bool ProjectManager::save()
depMap.insert(key, values); depMap.insert(key, values);
++i; ++i;
} }
data.insert(QLatin1String("ProjectDependencies"), QVariant(depMap)); SessionManager::setSessionValue(QLatin1String("ProjectDependencies"), QVariant(depMap));
data.insert(QLatin1String("EditorSettings"), EditorManager::saveState().toBase64());
}
const auto end = sb_d->m_values.constEnd();
QStringList keys;
for (auto it = sb_d->m_values.constBegin(); it != end; ++it) {
data.insert(QLatin1String("value-") + it.key(), it.value());
keys << it.key();
}
data.insert(QLatin1String("valueKeys"), keys);
if (!sb_d->m_writer || sb_d->m_writer->fileName() != filePath) {
delete sb_d->m_writer;
sb_d->m_writer = new PersistentSettingsWriter(filePath, "QtCreatorSession");
}
const bool result = sb_d->m_writer->save(data, ICore::dialogParent());
if (result) {
if (!SessionManager::isDefaultVirgin())
sb_d->m_sessionDateTimes.insert(SessionManager::activeSession(), QDateTime::currentDateTime());
} else {
QMessageBox::warning(ICore::dialogParent(), Tr::tr("Error while saving session"),
Tr::tr("Could not save session to file %1").arg(sb_d->m_writer->fileName().toUserOutput()));
}
return result;
} }
/*! /*!

View File

@@ -47,7 +47,6 @@ public:
}); });
} }
static bool save();
static void closeAllProjects(); static void closeAllProjects();
static void addProject(Project *project); static void addProject(Project *project);

View File

@@ -7,7 +7,6 @@
#include "projectexplorer.h" #include "projectexplorer.h"
#include "projectexplorertr.h" #include "projectexplorertr.h"
#include "projectmanager.h"
#include <extensionsystem/pluginmanager.h> #include <extensionsystem/pluginmanager.h>
#include <extensionsystem/pluginspec.h> #include <extensionsystem/pluginspec.h>
@@ -514,7 +513,7 @@ bool SessionManager::loadSession(const QString &session, bool initial)
// Allow everyone to set something in the session and before saving // Allow everyone to set something in the session and before saving
emit SessionManager::instance()->aboutToUnloadSession(sb_d->m_sessionName); emit SessionManager::instance()->aboutToUnloadSession(sb_d->m_sessionName);
if (!ProjectManager::save()) { if (!saveSession()) {
sb_d->m_loadingSession = false; sb_d->m_loadingSession = false;
return false; return false;
} }
@@ -571,4 +570,67 @@ bool SessionManager::loadSession(const QString &session, bool initial)
return true; return true;
} }
bool SessionManager::saveSession()
{
emit SessionManager::instance()->aboutToSaveSession();
const FilePath filePath = SessionManager::sessionNameToFileName(sb_d->m_sessionName);
QVariantMap data;
// See the explanation at loadSession() for how we handle the implicit default session.
if (SessionManager::isDefaultVirgin()) {
if (filePath.exists()) {
PersistentSettingsReader reader;
if (!reader.load(filePath)) {
QMessageBox::warning(ICore::dialogParent(),
Tr::tr("Error while saving session"),
Tr::tr("Could not save session %1")
.arg(filePath.toUserOutput()));
return false;
}
data = reader.restoreValues();
}
} else {
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'));
setSessionValue("Color", tmp);
}
setSessionValue("EditorSettings", EditorManager::saveState().toBase64());
const auto end = sb_d->m_sessionValues.constEnd();
for (auto it = sb_d->m_sessionValues.constBegin(); it != end; ++it)
data.insert(it.key(), it.value());
}
const auto end = sb_d->m_values.constEnd();
QStringList keys;
for (auto it = sb_d->m_values.constBegin(); it != end; ++it) {
data.insert("value-" + it.key(), it.value());
keys << it.key();
}
data.insert("valueKeys", keys);
if (!sb_d->m_writer || sb_d->m_writer->fileName() != filePath) {
delete sb_d->m_writer;
sb_d->m_writer = new PersistentSettingsWriter(filePath, "QtCreatorSession");
}
const bool result = sb_d->m_writer->save(data, ICore::dialogParent());
if (result) {
if (!SessionManager::isDefaultVirgin())
sb_d->m_sessionDateTimes.insert(SessionManager::activeSession(),
QDateTime::currentDateTime());
} else {
QMessageBox::warning(ICore::dialogParent(),
Tr::tr("Error while saving session"),
Tr::tr("Could not save session to file %1")
.arg(sb_d->m_writer->fileName().toUserOutput()));
}
return result;
}
} // namespace ProjectExplorer } // namespace ProjectExplorer

View File

@@ -64,6 +64,7 @@ public:
static void addSessionLoadingSteps(int steps); static void addSessionLoadingSteps(int steps);
static bool loadSession(const QString &session, bool initial = false); static bool loadSession(const QString &session, bool initial = false);
static bool saveSession();
signals: signals:
void startupSessionRestored(); void startupSessionRestored();

View File

@@ -210,11 +210,6 @@ void QmlJSEditorPlugin::extensionsInitialized()
QmllsSettingsManager::instance()->setupAutoupdate(); QmllsSettingsManager::instance()->setupAutoupdate();
} }
ExtensionSystem::IPlugin::ShutdownFlag QmlJSEditorPlugin::aboutToShutdown()
{
return IPlugin::aboutToShutdown();
}
Utils::JsonSchemaManager *QmlJSEditorPlugin::jsonManager() Utils::JsonSchemaManager *QmlJSEditorPlugin::jsonManager()
{ {
return &m_instance->d->m_jsonManager; return &m_instance->d->m_jsonManager;

View File

@@ -29,7 +29,6 @@ public:
private: private:
void initialize() final; void initialize() final;
void extensionsInitialized() final; void extensionsInitialized() final;
ShutdownFlag aboutToShutdown() final;
class QmlJSEditorPluginPrivate *d = nullptr; class QmlJSEditorPluginPrivate *d = nullptr;
}; };

View File

@@ -631,6 +631,115 @@ void tst_Tasking::testTree_data()
QTest::newRow("SequentialError") << TestData{storage, root, log, 5, OnDone::Failure}; QTest::newRow("SequentialError") << TestData{storage, root, log, 5, OnDone::Failure};
} }
{
const auto constructEmptyWorkflow = [=](WorkflowPolicy policy) {
return Group {
Storage(storage),
workflowPolicy(policy),
onGroupDone(groupDone(0)),
onGroupError(groupError(0))
};
};
const Log log = {{0, Handler::GroupDone}};
const Group root1 = constructEmptyWorkflow(WorkflowPolicy::StopOnError);
QTest::newRow("EmptyStopOnError") << TestData{storage, root1, log, 0, OnDone::Success};
const Group root2 = constructEmptyWorkflow(WorkflowPolicy::ContinueOnError);
QTest::newRow("EmptyContinueOnError") << TestData{storage, root2, log, 0, OnDone::Success};
const Group root3 = constructEmptyWorkflow(WorkflowPolicy::StopOnDone);
QTest::newRow("EmptyStopOnDone") << TestData{storage, root3, log, 0, OnDone::Success};
const Group root4 = constructEmptyWorkflow(WorkflowPolicy::ContinueOnDone);
QTest::newRow("EmptyContinueOnDone") << TestData{storage, root4, log, 0, OnDone::Success};
const Group root5 = constructEmptyWorkflow(WorkflowPolicy::StopOnFinished);
QTest::newRow("EmptyStopOnFinished") << TestData{storage, root5, log, 0, OnDone::Success};
const Group root6 = constructEmptyWorkflow(WorkflowPolicy::Optional);
QTest::newRow("EmptyOptional") << TestData{storage, root6, log, 0, OnDone::Success};
}
{
const auto constructDoneWorkflow = [=](WorkflowPolicy policy) {
return Group {
Storage(storage),
workflowPolicy(policy),
Test(setupTask(1), logDone, logError),
onGroupDone(groupDone(0)),
onGroupError(groupError(0))
};
};
const Log log = {
{1, Handler::Setup},
{1, Handler::Done},
{0, Handler::GroupDone}
};
const Group root1 = constructDoneWorkflow(WorkflowPolicy::StopOnError);
QTest::newRow("DoneStopOnError") << TestData{storage, root1, log, 1, OnDone::Success};
const Group root2 = constructDoneWorkflow(WorkflowPolicy::ContinueOnError);
QTest::newRow("DoneContinueOnError") << TestData{storage, root2, log, 1, OnDone::Success};
const Group root3 = constructDoneWorkflow(WorkflowPolicy::StopOnDone);
QTest::newRow("DoneStopOnDone") << TestData{storage, root3, log, 1, OnDone::Success};
const Group root4 = constructDoneWorkflow(WorkflowPolicy::ContinueOnDone);
QTest::newRow("DoneContinueOnDone") << TestData{storage, root4, log, 1, OnDone::Success};
const Group root5 = constructDoneWorkflow(WorkflowPolicy::StopOnFinished);
QTest::newRow("DoneStopOnFinished") << TestData{storage, root5, log, 1, OnDone::Success};
const Group root6 = constructDoneWorkflow(WorkflowPolicy::Optional);
QTest::newRow("DoneOptional") << TestData{storage, root6, log, 1, OnDone::Success};
}
{
const auto constructErrorWorkflow = [=](WorkflowPolicy policy) {
return Group {
Storage(storage),
workflowPolicy(policy),
Test(setupFailingTask(1), logDone, logError),
onGroupDone(groupDone(0)),
onGroupError(groupError(0))
};
};
const Log log = {
{1, Handler::Setup},
{1, Handler::Error},
{0, Handler::GroupError}
};
const Log optionalLog = {
{1, Handler::Setup},
{1, Handler::Error},
{0, Handler::GroupDone}
};
const Group root1 = constructErrorWorkflow(WorkflowPolicy::StopOnError);
QTest::newRow("ErrorStopOnError") << TestData{storage, root1, log, 1, OnDone::Failure};
const Group root2 = constructErrorWorkflow(WorkflowPolicy::ContinueOnError);
QTest::newRow("ErrorContinueOnError") << TestData{storage, root2, log, 1, OnDone::Failure};
const Group root3 = constructErrorWorkflow(WorkflowPolicy::StopOnDone);
QTest::newRow("ErrorStopOnDone") << TestData{storage, root3, log, 1, OnDone::Failure};
const Group root4 = constructErrorWorkflow(WorkflowPolicy::ContinueOnDone);
QTest::newRow("ErrorContinueOnDone") << TestData{storage, root4, log, 1, OnDone::Failure};
const Group root5 = constructErrorWorkflow(WorkflowPolicy::StopOnFinished);
QTest::newRow("ErrorStopOnFinished") << TestData{storage, root5, log, 1, OnDone::Failure};
const Group root6 = constructErrorWorkflow(WorkflowPolicy::Optional);
QTest::newRow("ErrorOptional") << TestData{storage, root6, optionalLog, 1, OnDone::Success};
}
{ {
const Group root = constructSimpleSequence(WorkflowPolicy::StopOnError); const Group root = constructSimpleSequence(WorkflowPolicy::StopOnError);
const Log log { const Log log {