Merge remote-tracking branch 'origin/6.0'

Conflicts:
	cmake/QtCreatorIDEBranding.cmake
	qbs/modules/qtc/qtc.qbs
	qtcreator_ide_branding.pri

Change-Id: Id5e67457e2c8c96cfcd29fb5469b6650ec7bcc94
This commit is contained in:
Eike Ziller
2021-11-01 09:46:02 +01:00
85 changed files with 770 additions and 706 deletions

View File

@@ -3,7 +3,7 @@ name: CMake Build Matrix
on: [push, pull_request]
env:
QT_VERSION: 6.2.0
QT_VERSION: 6.2.1
CLANG_VERSION: 130
ELFUTILS_VERSION: 0.175
CMAKE_VERSION: 3.21.1

View File

@@ -164,13 +164,13 @@ def fix_rpaths(path, qt_deploy_path, qt_install_info, chrpath=None):
if len(rpath) <= 0:
return
# remove previous Qt RPATH
new_rpath = list(filter(lambda path: not path.startswith(qt_install_prefix) and not path.startswith(qt_install_libs),
rpath))
new_rpath = [path for path in rpath if not path.startswith(qt_install_prefix)
and not path.startswith(qt_install_libs)]
# check for Qt linking
lddOutput = subprocess.check_output(['ldd', filepath])
lddDecodedOutput = lddOutput.decode(encoding) if encoding else lddOutput
if lddDecodedOutput.find('libQt5') >= 0 or lddDecodedOutput.find('libicu') >= 0:
if lddDecodedOutput.find('libQt') >= 0 or lddDecodedOutput.find('libicu') >= 0:
# add Qt RPATH if necessary
relative_path = os.path.relpath(qt_deploy_path, os.path.dirname(filepath))
if relative_path == '.':

View File

@@ -1137,6 +1137,7 @@ class DumperBase():
'char',
'wchar_t',
'unsigned char',
'uint8_t',
'signed char',
'CHAR',
'WCHAR'
@@ -1243,7 +1244,7 @@ class DumperBase():
if innerType.code == TypeCode.Typedef:
targetType = innerType.ltarget
if targetType.name in ('char', 'signed char', 'unsigned char', 'CHAR'):
if targetType.name in ('char', 'signed char', 'unsigned char', 'uint8_t', 'CHAR'):
# Use UTF-8 as default for char *.
self.putType(typeName)
(elided, shown, data) = self.readToFirstZero(ptr, 1, limit)
@@ -1406,6 +1407,7 @@ class DumperBase():
'char',
'signed char',
'unsigned char',
'uint8_t',
'wchar_t',
'CHAR',
'WCHAR'
@@ -3628,6 +3630,7 @@ class DumperBase():
'char': 'int:1',
'signed char': 'int:1',
'unsigned char': 'uint:1',
'uint8_t': 'uint:1',
'short': 'int:2',
'unsigned short': 'uint:2',
'int': 'int:4',

View File

@@ -140,25 +140,6 @@ Section {
ExpandingSpacer {}
}
PropertyLabel {
text: qsTr("Weight")
tooltip: qsTr("Font's weight.")
}
SecondColumnLayout {
ComboBox {
implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ StudioTheme.Values.actionIndicatorWidth
width: implicitWidth
backendValue: getBackendValue("weight")
model: ["Normal", "Light", "ExtraLight", "Thin", "Medium", "DemiBold", "Bold", "ExtraBold", "Black"]
scope: "Font"
enabled: !styleNameComboBox.styleSet
}
ExpandingSpacer {}
}
PropertyLabel {
text: qsTr("Style name")
tooltip: qsTr("Font's style.")
@@ -267,7 +248,30 @@ Section {
supportGradient: false
}
PropertyLabel { text: qsTr("Emphasis") }
PropertyLabel {
text: qsTr("Weight")
tooltip: qsTr("Font's weight.")
enabled: !styleNameComboBox.styleSet
}
SecondColumnLayout {
ComboBox {
implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ StudioTheme.Values.actionIndicatorWidth
width: implicitWidth
backendValue: getBackendValue("weight")
model: ["Normal", "Light", "ExtraLight", "Thin", "Medium", "DemiBold", "Bold", "ExtraBold", "Black"]
scope: "Font"
enabled: !styleNameComboBox.styleSet
}
ExpandingSpacer {}
}
PropertyLabel {
text: qsTr("Emphasis")
enabled: !styleNameComboBox.styleSet
}
FontStyleButtons {
bold: root.boldStyle

View File

@@ -35,6 +35,7 @@
<style name="String" foreground="#636363"/>
<style name="Text" foreground="#000000" background="#ffffff"/>
<style name="Type"/>
<style name="Namespace"/>
<style name="VirtualMethod" italic="true"/>
<style name="Occurrences.Unused" underlineColor="#8F8F8F" underlineStyle="SingleUnderline"/>
<style name="Warning" underlineColor="#505050" underlineStyle="SingleUnderline"/>

View File

@@ -632,6 +632,10 @@ LibraryInfo Snapshot::libraryInfo(const QString &path) const
return _libraries.value(QDir::cleanPath(path));
}
LibraryInfo Snapshot::libraryInfo(const Utils::FilePath &path) const
{
return _libraries.value(path.cleanPath().toString());
}
void ModuleApiInfo::addToHash(QCryptographicHash &hash) const
{

View File

@@ -256,7 +256,8 @@ public:
Document::Ptr document(const QString &fileName) const;
QList<Document::Ptr> documentsInDirectory(const QString &path) const;
LibraryInfo libraryInfo(const QString &path) const;
LibraryInfo libraryInfo(const QString &path) const; // FIXME: Remove
LibraryInfo libraryInfo(const Utils::FilePath &path) const;
Document::MutablePtr documentFromSource(const QString &code,
const QString &fileName,

View File

@@ -684,19 +684,19 @@ void ModelManagerInterface::updateDocument(const Document::Ptr &doc)
emit documentUpdated(doc);
}
void ModelManagerInterface::updateLibraryInfo(const QString &path, const LibraryInfo &info)
void ModelManagerInterface::updateLibraryInfo(const FilePath &path, const LibraryInfo &info)
{
if (!info.pluginTypeInfoError().isEmpty())
qCDebug(qmljsLog) << "Dumping errors for " << path << ":" << info.pluginTypeInfoError();
{
QMutexLocker locker(&m_mutex);
m_validSnapshot.insertLibraryInfo(path, info);
m_newestSnapshot.insertLibraryInfo(path, info);
m_validSnapshot.insertLibraryInfo(path.toString(), info);
m_newestSnapshot.insertLibraryInfo(path.toString(), info);
}
// only emit if we got new useful information
if (info.isValid())
emit libraryInfoUpdated(path, info);
emit libraryInfoUpdated(path.toString(), info);
}
static QStringList filesInDirectoryForLanguages(const QString &path,
@@ -773,7 +773,7 @@ enum class LibraryStatus {
Unknown
};
static LibraryStatus libraryStatus(const QString &path, const Snapshot &snapshot,
static LibraryStatus libraryStatus(const FilePath &path, const Snapshot &snapshot,
QSet<QString> *newLibraries)
{
if (path.isEmpty())
@@ -782,7 +782,7 @@ static LibraryStatus libraryStatus(const QString &path, const Snapshot &snapshot
const LibraryInfo &existingInfo = snapshot.libraryInfo(path);
if (existingInfo.isValid())
return LibraryStatus::Accepted;
if (newLibraries->contains(path))
if (newLibraries->contains(path.toString()))
return LibraryStatus::Accepted;
// if we looked at the path before, done
return existingInfo.wasScanned()
@@ -790,7 +790,7 @@ static LibraryStatus libraryStatus(const QString &path, const Snapshot &snapshot
: LibraryStatus::Unknown;
}
static bool findNewQmlApplicationInPath(const QString &path,
static bool findNewQmlApplicationInPath(const FilePath &path,
const Snapshot &snapshot,
ModelManagerInterface *modelManager,
QSet<QString> *newLibraries)
@@ -803,8 +803,8 @@ static bool findNewQmlApplicationInPath(const QString &path,
QString qmltypesFile;
QDir dir(path);
QDirIterator it(path, QStringList { "*.qmltypes" }, QDir::Files);
QDir dir(path.toString());
QDirIterator it(path.toString(), QStringList { "*.qmltypes" }, QDir::Files);
if (!it.hasNext())
return false;
@@ -828,7 +828,7 @@ static bool findNewQmlLibraryInPath(const QString &path,
QSet<QString> *newLibraries,
bool ignoreMissing)
{
switch (libraryStatus(path, snapshot, newLibraries)) {
switch (libraryStatus(FilePath::fromString(path), snapshot, newLibraries)) {
case LibraryStatus::Accepted: return true;
case LibraryStatus::Rejected: return false;
default: break;
@@ -839,7 +839,7 @@ static bool findNewQmlLibraryInPath(const QString &path,
if (!qmldirFile.exists()) {
if (!ignoreMissing) {
LibraryInfo libraryInfo(LibraryInfo::NotFound);
modelManager->updateLibraryInfo(path, libraryInfo);
modelManager->updateLibraryInfo(FilePath::fromString(path), libraryInfo);
}
return false;
}
@@ -858,7 +858,7 @@ static bool findNewQmlLibraryInPath(const QString &path,
const QString libraryPath = QFileInfo(qmldirFile).absolutePath();
newLibraries->insert(libraryPath);
modelManager->updateLibraryInfo(libraryPath, LibraryInfo(qmldirParser));
modelManager->updateLibraryInfo(FilePath::fromString(libraryPath), LibraryInfo(qmldirParser));
modelManager->loadPluginTypes(QFileInfo(libraryPath).canonicalFilePath(), libraryPath,
QString(), QString());
@@ -1252,7 +1252,7 @@ void ModelManagerInterface::updateImportPaths()
for (const Document::Ptr &doc : qAsConst(snapshot))
findNewLibraryImports(doc, snapshot, this, &importedFiles, &scannedPaths, &newLibraries);
for (const QString &path : qAsConst(allApplicationDirectories))
findNewQmlApplicationInPath(path, snapshot, this, &newLibraries);
findNewQmlApplicationInPath(FilePath::fromString(path), snapshot, this, &newLibraries);
updateSourceFiles(importedFiles, true);
@@ -1433,7 +1433,7 @@ LibraryInfo ModelManagerInterface::builtins(const Document::Ptr &doc) const
{
const ProjectInfo info = projectInfoForPath(doc->fileName());
if (!info.qtQmlPath.isEmpty())
return m_validSnapshot.libraryInfo(info.qtQmlPath.toString());
return m_validSnapshot.libraryInfo(info.qtQmlPath);
return LibraryInfo();
}

View File

@@ -156,7 +156,7 @@ public:
void updateProjectInfo(const ProjectInfo &pinfo, ProjectExplorer::Project *p);
void updateDocument(const QmlJS::Document::Ptr& doc);
void updateLibraryInfo(const QString &path, const QmlJS::LibraryInfo &info);
void updateLibraryInfo(const Utils::FilePath &path, const QmlJS::LibraryInfo &info);
void emitDocumentChangedOnDisk(QmlJS::Document::Ptr doc);
void updateQrcFile(const QString &path);
ProjectInfo projectInfoForPath(const QString &path) const;

View File

@@ -89,25 +89,23 @@ void PluginDumper::onLoadBuiltinTypes(const QmlJS::ModelManagerInterface::Projec
if (info.qmlDumpPath.isEmpty() || info.qtQmlPath.isEmpty())
return;
// FIXME: This doesn't work for non-local paths.
const QString importsPath = QDir::cleanPath(info.qtQmlPath.toString());
if (m_runningQmldumps.values().contains(importsPath))
if (m_runningQmldumps.values().contains(info.qmlDumpPath))
return;
LibraryInfo builtinInfo;
if (!force) {
const Snapshot snapshot = m_modelManager->snapshot();
builtinInfo = snapshot.libraryInfo(info.qtQmlPath.toString());
builtinInfo = snapshot.libraryInfo(info.qtQmlPath);
if (builtinInfo.isValid())
return;
}
builtinInfo = LibraryInfo(LibraryInfo::Found);
m_modelManager->updateLibraryInfo(info.qtQmlPath.toString(), builtinInfo);
m_modelManager->updateLibraryInfo(info.qtQmlPath, builtinInfo);
// prefer QTDIR/qml/builtins.qmltypes if available
const QString builtinQmltypesPath = info.qtQmlPath.toString() + QLatin1String("/builtins.qmltypes");
if (QFile::exists(builtinQmltypesPath)) {
loadQmltypesFile(QStringList(builtinQmltypesPath), info.qtQmlPath.toString(), builtinInfo);
const FilePath builtinQmltypesPath = info.qtQmlPath / "builtins.qmltypes";
if (builtinQmltypesPath.exists()) {
loadQmltypesFile({builtinQmltypesPath}, info.qtQmlPath, builtinInfo);
return;
}
@@ -115,16 +113,9 @@ void PluginDumper::onLoadBuiltinTypes(const QmlJS::ModelManagerInterface::Projec
m_qtToInfo.insert(info.qtQmlPath.toString(), info);
}
static QString makeAbsolute(const QString &path, const QString &base)
{
if (QFileInfo(path).isAbsolute())
return path;
return QString::fromLatin1("%1/%3").arg(base, path);
}
void PluginDumper::onLoadPluginTypes(const QString &libraryPath, const QString &importPath, const QString &importUri, const QString &importVersion)
{
const QString canonicalLibraryPath = QDir::cleanPath(libraryPath);
const FilePath canonicalLibraryPath = FilePath::fromUserInput(libraryPath).cleanPath();
if (m_runningQmldumps.values().contains(canonicalLibraryPath))
return;
const Snapshot snapshot = m_modelManager->snapshot();
@@ -135,7 +126,7 @@ void PluginDumper::onLoadPluginTypes(const QString &libraryPath, const QString &
// avoid inserting the same plugin twice
int index;
for (index = 0; index < m_plugins.size(); ++index) {
if (m_plugins.at(index).qmldirPath == libraryPath)
if (m_plugins.at(index).qmldirPath == canonicalLibraryPath)
break;
}
if (index == m_plugins.size())
@@ -148,10 +139,10 @@ void PluginDumper::onLoadPluginTypes(const QString &libraryPath, const QString &
plugin.importVersion = importVersion;
// add default qmltypes file if it exists
QDirIterator it(canonicalLibraryPath, QStringList { "*.qmltypes" }, QDir::Files);
QDirIterator it(canonicalLibraryPath.toString(), QStringList { "*.qmltypes" }, QDir::Files);
while (it.hasNext()) {
const QString defaultQmltypesPath = makeAbsolute(it.next(), canonicalLibraryPath);
const FilePath defaultQmltypesPath = canonicalLibraryPath.resolvePath(it.next());
if (!plugin.typeInfoPaths.contains(defaultQmltypesPath))
plugin.typeInfoPaths += defaultQmltypesPath;
@@ -159,29 +150,29 @@ void PluginDumper::onLoadPluginTypes(const QString &libraryPath, const QString &
// add typeinfo files listed in qmldir
foreach (const QString &typeInfo, libraryInfo.typeInfos()) {
QString pathNow = makeAbsolute(typeInfo, canonicalLibraryPath);
if (!plugin.typeInfoPaths.contains(pathNow) && QFile::exists(pathNow))
const FilePath pathNow = canonicalLibraryPath.resolvePath(typeInfo);
if (!plugin.typeInfoPaths.contains(pathNow) && pathNow.exists())
plugin.typeInfoPaths += pathNow;
}
// watch plugin libraries
foreach (const QmlDirParser::Plugin &plugin, snapshot.libraryInfo(canonicalLibraryPath).plugins()) {
const QString pluginLibrary = resolvePlugin(canonicalLibraryPath, plugin.path, plugin.name);
const QString pluginLibrary = resolvePlugin(canonicalLibraryPath.toString(), plugin.path, plugin.name);
if (!pluginLibrary.isEmpty()) {
if (!pluginWatcher()->watchesFile(pluginLibrary))
pluginWatcher()->addFile(pluginLibrary, Utils::FileSystemWatcher::WatchModifiedDate);
pluginWatcher()->addFile(pluginLibrary, FileSystemWatcher::WatchModifiedDate);
m_libraryToPluginIndex.insert(pluginLibrary, index);
}
}
// watch library qmltypes file
if (!plugin.typeInfoPaths.isEmpty()) {
foreach (const QString &path, plugin.typeInfoPaths) {
if (!QFile::exists(path))
for (const FilePath &path : qAsConst(plugin.typeInfoPaths)) {
if (!path.exists())
continue;
if (!pluginWatcher()->watchesFile(path))
pluginWatcher()->addFile(path, Utils::FileSystemWatcher::WatchModifiedDate);
m_libraryToPluginIndex.insert(path, index);
if (!pluginWatcher()->watchesFile(path.toString()))
pluginWatcher()->addFile(path.toString(), FileSystemWatcher::WatchModifiedDate);
m_libraryToPluginIndex.insert(path.toString(), index);
}
}
@@ -195,26 +186,25 @@ void PluginDumper::dumpAllPlugins()
}
}
static QString noTypeinfoError(const QString &libraryPath)
static QString noTypeinfoError(const FilePath &libraryPath)
{
return PluginDumper::tr("QML module does not contain information about components contained in plugins.\n\n"
"Module path: %1\n"
"See \"Using QML Modules with Plugins\" in the documentation.").arg(
libraryPath);
libraryPath.toUserOutput());
}
static QString qmldumpErrorMessage(const QString &libraryPath, const QString &error)
static QString qmldumpErrorMessage(const FilePath &libraryPath, const QString &error)
{
return noTypeinfoError(libraryPath) + QLatin1String("\n\n") +
return noTypeinfoError(libraryPath) + "\n\n" +
PluginDumper::tr("Automatic type dump of QML module failed.\nErrors:\n%1").
arg(error) + QLatin1Char('\n');
}
static QString qmldumpFailedMessage(const QString &libraryPath, const QString &error)
static QString qmldumpFailedMessage(const FilePath &libraryPath, const QString &error)
{
QString firstLines =
QStringList(error.split(QLatin1Char('\n')).mid(0, 10)).join(QLatin1Char('\n'));
return noTypeinfoError(libraryPath) + QLatin1String("\n\n") +
QString firstLines = QStringList(error.split('\n').mid(0, 10)).join('\n');
return noTypeinfoError(libraryPath) + "\n\n" +
PluginDumper::tr("Automatic type dump of QML module failed.\n"
"First 10 lines or errors:\n"
"\n"
@@ -224,11 +214,11 @@ static QString qmldumpFailedMessage(const QString &libraryPath, const QString &e
).arg(firstLines);
}
static void printParseWarnings(const QString &libraryPath, const QString &warning)
static void printParseWarnings(const FilePath &libraryPath, const QString &warning)
{
ModelManagerInterface::writeWarning(
PluginDumper::tr("Warnings while parsing QML type information of %1:\n"
"%2").arg(libraryPath, warning));
"%2").arg(libraryPath.toUserOutput(), warning));
}
static QString qmlPluginDumpErrorMessage(QtcProcess *process)
@@ -269,7 +259,7 @@ void PluginDumper::qmlPluginTypeDumpDone(QtcProcess *process)
{
process->deleteLater();
const QString libraryPath = m_runningQmldumps.take(process);
const FilePath libraryPath = m_runningQmldumps.take(process);
if (libraryPath.isEmpty())
return;
const Snapshot snapshot = m_modelManager->snapshot();
@@ -298,7 +288,7 @@ void PluginDumper::qmlPluginTypeDumpDone(QtcProcess *process)
CppQmlTypesInfo infos;
CppQmlTypesLoader::parseQmlTypeDescriptions(output, &infos.objectsList, &infos.moduleApis, &infos.dependencies,
&infos.error, &infos.warning,
QLatin1String("<dump of ") + libraryPath + QLatin1Char('>'));
"<dump of " + libraryPath.toUserOutput() + '>');
future.reportFinished(&infos);
});
m_modelManager->addFuture(future);
@@ -338,13 +328,13 @@ void PluginDumper::qmlPluginTypeDumpError(QtcProcess *process)
{
process->deleteLater();
const QString libraryPath = m_runningQmldumps.take(process);
const FilePath libraryPath = m_runningQmldumps.take(process);
if (libraryPath.isEmpty())
return;
const QString errorMessages = qmlPluginDumpErrorMessage(process);
const Snapshot snapshot = m_modelManager->snapshot();
LibraryInfo libraryInfo = snapshot.libraryInfo(libraryPath);
if (!libraryPath.endsWith(QLatin1String("private"), Qt::CaseInsensitive))
if (!libraryPath.path().endsWith(QLatin1String("private"), Qt::CaseInsensitive))
ModelManagerInterface::writeWarning(qmldumpErrorMessage(libraryPath, errorMessages));
libraryInfo.setPluginTypeInfoStatus(LibraryInfo::DumpError, qmldumpFailedMessage(libraryPath, errorMessages));
libraryInfo.updateFingerprint();
@@ -361,14 +351,15 @@ void PluginDumper::pluginChanged(const QString &pluginLibrary)
dump(plugin);
}
QFuture<PluginDumper::QmlTypeDescription> PluginDumper::loadQmlTypeDescription(const QStringList &paths) const {
QFuture<PluginDumper::QmlTypeDescription> PluginDumper::loadQmlTypeDescription(const FilePaths &paths) const
{
auto future = Utils::runAsync([=](QFutureInterface<PluginDumper::QmlTypeDescription> &future)
{
PluginDumper::QmlTypeDescription result;
for (const QString &p: paths) {
for (const FilePath &p: paths) {
Utils::FileReader reader;
if (!reader.fetch(Utils::FilePath::fromString(p), QFile::Text)) {
if (!reader.fetch(p, QFile::Text)) {
result.errors += reader.errorString();
continue;
}
@@ -378,9 +369,9 @@ QFuture<PluginDumper::QmlTypeDescription> PluginDumper::loadQmlTypeDescription(c
QList<ModuleApiInfo> apis;
QStringList deps;
CppQmlTypesLoader::parseQmlTypeDescriptions(reader.data(), &objs, &apis, &deps,
&error, &warning, p);
&error, &warning, p.toString());
if (!error.isEmpty()) {
result.errors += tr("Failed to parse \"%1\".\nError: %2").arg(p, error);
result.errors += tr("Failed to parse \"%1\".\nError: %2").arg(p.toUserOutput(), error);
} else {
result.objects += objs.values();
result.moduleApis += apis;
@@ -444,27 +435,26 @@ QString PluginDumper::buildQmltypesPath(const QString &name) const
* Recursively load type descriptions of dependencies, collecting results
* in \a objects.
*/
QFuture<PluginDumper::DependencyInfo> PluginDumper::loadDependencies(const QStringList &dependencies,
QSharedPointer<QSet<QString>> visited) const
QFuture<PluginDumper::DependencyInfo> PluginDumper::loadDependencies(const FilePaths &dependencies,
QSharedPointer<QSet<FilePath>> visited) const
{
auto iface = QSharedPointer<QFutureInterface<PluginDumper::DependencyInfo>>(new QFutureInterface<PluginDumper::DependencyInfo>);
if (visited.isNull()) {
visited = QSharedPointer<QSet<QString>>(new QSet<QString>());
}
if (visited.isNull())
visited = QSharedPointer<QSet<FilePath>>(new QSet<FilePath>());
QStringList dependenciesPaths;
FilePaths dependenciesPaths;
QString path;
for (const QString &name: dependencies) {
path = buildQmltypesPath(name);
for (const FilePath &name : dependencies) {
path = buildQmltypesPath(name.toString());
if (!path.isNull())
dependenciesPaths << path;
dependenciesPaths << FilePath::fromString(path);
visited->insert(name);
}
Utils::onFinished(loadQmlTypeDescription(dependenciesPaths), const_cast<PluginDumper*>(this), [=] (const QFuture<PluginDumper::QmlTypeDescription> &typesFuture) {
PluginDumper::QmlTypeDescription typesResult = typesFuture.result();
QStringList newDependencies = typesResult.dependencies;
FilePaths newDependencies = Utils::transform(typesResult.dependencies, &FilePath::fromString);
newDependencies = Utils::toList(Utils::toSet(newDependencies) - *visited.data());
if (!newDependencies.isEmpty()) {
Utils::onFinished(loadDependencies(newDependencies, visited),
@@ -564,7 +554,7 @@ static void applyQt515MissingImportWorkaround(const QString &path, LibraryInfo &
}
void PluginDumper::prepareLibraryInfo(LibraryInfo &libInfo,
const QString &libraryPath,
const FilePath &libraryPath,
const QStringList &deps,
const QStringList &errors,
const QStringList &warnings,
@@ -588,13 +578,13 @@ void PluginDumper::prepareLibraryInfo(LibraryInfo &libInfo,
if (!warnings.isEmpty())
printParseWarnings(libraryPath, warnings.join(QLatin1String("\n")));
applyQt515MissingImportWorkaround(libraryPath, libInfo);
applyQt515MissingImportWorkaround(libraryPath.toString(), libInfo);
libInfo.updateFingerprint();
}
void PluginDumper::loadQmltypesFile(const QStringList &qmltypesFilePaths,
const QString &libraryPath,
void PluginDumper::loadQmltypesFile(const FilePaths &qmltypesFilePaths,
const FilePath &libraryPath,
QmlJS::LibraryInfo libraryInfo)
{
Utils::onFinished(loadQmlTypeDescription(qmltypesFilePaths), this, [=](const QFuture<PluginDumper::QmlTypeDescription> &typesFuture)
@@ -602,7 +592,8 @@ void PluginDumper::loadQmltypesFile(const QStringList &qmltypesFilePaths,
PluginDumper::QmlTypeDescription typesResult = typesFuture.result();
if (!typesResult.dependencies.isEmpty())
{
Utils::onFinished(loadDependencies(typesResult.dependencies, QSharedPointer<QSet<QString>>()), this,
Utils::onFinished(loadDependencies(Utils::transform(typesResult.dependencies, &FilePath::fromString),
QSharedPointer<QSet<FilePath>>()), this,
[typesResult, libraryInfo, libraryPath, this] (const QFuture<PluginDumper::DependencyInfo> &loadFuture)
{
PluginDumper::DependencyInfo loadResult = loadFuture.result();
@@ -640,7 +631,7 @@ void PluginDumper::runQmlDump(const ModelManagerInterface::ProjectInfo &info,
connect(process, &QtcProcess::finished, this, [this, process] { qmlPluginTypeDumpDone(process); });
connect(process, &QtcProcess::errorOccurred, this, [this, process] { qmlPluginTypeDumpError(process); });
process->start();
m_runningQmldumps.insert(process, importPath.toString());
m_runningQmldumps.insert(process, importPath);
}
void PluginDumper::dump(const Plugin &plugin)
@@ -686,7 +677,7 @@ void PluginDumper::dump(const Plugin &plugin)
args << plugin.importUri;
args << plugin.importVersion;
args << (plugin.importPath.isEmpty() ? QLatin1String(".") : plugin.importPath);
runQmlDump(info, args, FilePath::fromString(plugin.qmldirPath));
runQmlDump(info, args, plugin.qmldirPath);
}
/*!

View File

@@ -65,11 +65,11 @@ private:
private:
class Plugin {
public:
QString qmldirPath;
Utils::FilePath qmldirPath;
QString importPath;
QString importUri;
QString importVersion;
QStringList typeInfoPaths;
Utils::FilePaths typeInfoPaths;
};
class QmlTypeDescription {
@@ -91,14 +91,14 @@ private:
void runQmlDump(const QmlJS::ModelManagerInterface::ProjectInfo &info, const QStringList &arguments,
const Utils::FilePath &importPath);
void dump(const Plugin &plugin);
QFuture<QmlTypeDescription> loadQmlTypeDescription(const QStringList &path) const;
QFuture<QmlTypeDescription> loadQmlTypeDescription(const Utils::FilePaths &path) const;
QString buildQmltypesPath(const QString &name) const;
QFuture<PluginDumper::DependencyInfo> loadDependencies(const QStringList &dependencies,
QSharedPointer<QSet<QString>> visited) const;
QFuture<PluginDumper::DependencyInfo> loadDependencies(const Utils::FilePaths &dependencies,
QSharedPointer<QSet<Utils::FilePath> > visited) const;
void loadQmltypesFile(const QStringList &qmltypesFilePaths,
const QString &libraryPath,
void loadQmltypesFile(const Utils::FilePaths &qmltypesFilePaths,
const Utils::FilePath &libraryPath,
QmlJS::LibraryInfo libraryInfo);
QString resolvePlugin(const QDir &qmldirPath, const QString &qmldirPluginPath,
const QString &baseName);
@@ -109,7 +109,7 @@ private:
private:
Utils::FileSystemWatcher *pluginWatcher();
void prepareLibraryInfo(LibraryInfo &libInfo,
const QString &libraryPath,
const Utils::FilePath &libraryPath,
const QStringList &deps,
const QStringList &errors,
const QStringList &warnings,
@@ -118,7 +118,7 @@ private:
ModelManagerInterface *m_modelManager;
Utils::FileSystemWatcher *m_pluginWatcher;
QHash<Utils::QtcProcess *, QString> m_runningQmldumps;
QHash<Utils::QtcProcess *, Utils::FilePath> m_runningQmldumps;
QList<Plugin> m_plugins;
QHash<QString, int> m_libraryToPluginIndex;
QHash<QString, QmlJS::ModelManagerInterface::ProjectInfo> m_qtToInfo;

View File

@@ -440,7 +440,7 @@ FilePath FilePath::fromFileInfo(const QFileInfo &info)
QFileInfo FilePath::toFileInfo() const
{
QTC_ASSERT(!needsDevice(), return QFileInfo());
return QFileInfo(m_data);
return QFileInfo(cleanPath().path());
}
FilePath FilePath::fromUrl(const QUrl &url)

View File

@@ -125,7 +125,9 @@ bool MultiTextCursor::hasSelection() const
QString MultiTextCursor::selectedText() const
{
QString text;
for (const QTextCursor &cursor : m_cursors) {
QList<QTextCursor> cursors = m_cursors;
Utils::sort(cursors);
for (const QTextCursor &cursor : cursors) {
const QString &cursorText = cursor.selectedText();
if (cursorText.isEmpty())
continue;
@@ -169,7 +171,9 @@ void MultiTextCursor::insertText(const QString &text, bool selectNewText)
lines.pop_back();
int index = 0;
if (lines.count() == m_cursors.count()) {
for (QTextCursor &cursor : m_cursors)
QList<QTextCursor> cursors = m_cursors;
Utils::sort(cursors);
for (QTextCursor &cursor : cursors)
insertAndSelect(cursor, lines.at(index++), selectNewText);
m_cursors.last().endEditBlock();
return;

View File

@@ -90,7 +90,8 @@ AndroidDeviceWidget::AndroidDeviceWidget(const IDevice::Ptr &device)
formLayout->addRow(AndroidDevice::tr("Device type:"), new QLabel(dev->deviceTypeName()));
const QString serialNumber = dev->serialNumber();
const QString printableSerialNumber = serialNumber.isEmpty() ? tr("Unknown") : serialNumber;
const QString printableSerialNumber = serialNumber.isEmpty() ? AndroidDevice::tr("Unknown")
: serialNumber;
formLayout->addRow(AndroidDevice::tr("Serial number:"), new QLabel(printableSerialNumber));
const QString abis = dev->supportedAbis().join(", ");
@@ -100,8 +101,9 @@ AndroidDeviceWidget::AndroidDeviceWidget(const IDevice::Ptr &device)
formLayout->addRow(AndroidDevice::tr("OS version:"), new QLabel(osString));
if (dev->machineType() == IDevice::Hardware) {
const QString authorizedStr = dev->deviceState() == IDevice::DeviceReadyToUse ? tr("Yes")
: tr("No");
const QString authorizedStr = dev->deviceState() == IDevice::DeviceReadyToUse
? AndroidDevice::tr("Yes")
: AndroidDevice::tr("No");
formLayout->addRow(AndroidDevice::tr("Authorized:"), new QLabel(authorizedStr));
}
@@ -117,7 +119,7 @@ AndroidDeviceWidget::AndroidDeviceWidget(const IDevice::Ptr &device)
QString AndroidDeviceWidget::dialogTitle()
{
return tr("Android Device Manager");
return AndroidDevice::tr("Android Device Manager");
}
bool AndroidDeviceWidget::criticalDialog(const QString &error, QWidget *parent)
@@ -480,7 +482,8 @@ void AndroidDeviceManager::eraseAvd(const IDevice::Ptr &device, QWidget *parent)
return;
const QString name = static_cast<const AndroidDevice *>(device.data())->avdName();
const QString question = tr("Erase the Android AVD \"%1\"?\nThis cannot be undone.").arg(name);
const QString question
= AndroidDevice::tr("Erase the Android AVD \"%1\"?\nThis cannot be undone.").arg(name);
if (!AndroidDeviceWidget::questionDialog(question, parent))
return;
@@ -515,9 +518,10 @@ void AndroidDeviceManager::setEmulatorArguments(QWidget *parent)
"https://developer.android.com/studio/run/emulator-commandline#startup-options";
QInputDialog dialog(parent ? parent : Core::ICore::dialogParent());
dialog.setWindowTitle(tr("Emulator Command-line Startup Options"));
dialog.setLabelText(tr("Emulator command-line startup options "
"(<a href=\"%1\">Help Web Page</a>):").arg(helpUrl));
dialog.setWindowTitle(AndroidDevice::tr("Emulator Command-line Startup Options"));
dialog.setLabelText(AndroidDevice::tr("Emulator command-line startup options "
"(<a href=\"%1\">Help Web Page</a>):")
.arg(helpUrl));
dialog.setTextValue(m_androidConfig.emulatorArgs().join(' '));
if (auto label = dialog.findChild<QLabel*>()) {

View File

@@ -327,7 +327,7 @@ AndroidRunnerWorker::~AndroidRunnerWorker()
}
bool AndroidRunnerWorker::runAdb(const QStringList &args, QString *stdOut,
const QByteArray &writeData)
QString *stdErr, const QByteArray &writeData)
{
QStringList adbArgs = selector() + args;
SdkToolResult result = AndroidManager::runAdbCommand(adbArgs, writeData);
@@ -335,6 +335,8 @@ bool AndroidRunnerWorker::runAdb(const QStringList &args, QString *stdOut,
emit remoteErrorOutput(result.stdErr());
if (stdOut)
*stdOut = result.stdOut();
if (stdErr)
*stdErr = result.stdErr();
return result.success();
}
@@ -651,10 +653,17 @@ void AndroidRunnerWorker::asyncStartHelper()
.toUtf8().toBase64());
}
if (!runAdb(args)) {
QString stdErr;
const bool startResult = runAdb(args, nullptr, &stdErr);
if (!startResult) {
emit remoteProcessFinished(tr("Failed to start the activity."));
return;
}
if (!stdErr.isEmpty()) {
emit remoteErrorOutput(tr("Activity Manager threw the error: %1").arg(stdErr));
return;
}
}
bool AndroidRunnerWorker::startDebuggerServer(const QString &packageDir,

View File

@@ -47,7 +47,8 @@ public:
AndroidRunnerWorker(ProjectExplorer::RunWorker *runner, const QString &packageName);
~AndroidRunnerWorker() override;
bool runAdb(const QStringList &args, QString *stdOut = nullptr, const QByteArray &writeData = {});
bool runAdb(const QStringList &args, QString *stdOut = nullptr, QString *stdErr = nullptr,
const QByteArray &writeData = {});
void adbKill(qint64 pid);
QStringList selector() const;
void forceStop();

View File

@@ -1302,15 +1302,25 @@ void ClangdClient::findUsages(TextDocument *document, const QTextCursor &cursor,
const Utils::optional<QString> &replacement)
{
// Quick check: Are we even on anything searchable?
if (d->searchTermFromCursor(cursor).isEmpty())
const QString searchTerm = d->searchTermFromCursor(cursor);
if (searchTerm.isEmpty())
return;
// Get the proper spelling of the search term from clang, so we can put it into the
const bool categorize = CppEditor::codeModelSettings()->categorizeFindReferences();
// If it's a "normal" symbol, go right ahead.
if (searchTerm != "operator" && Utils::allOf(searchTerm, [](const QChar &c) {
return c.isLetterOrNumber() || c == '_';
})) {
d->findUsages(document, cursor, searchTerm, replacement, categorize);
return;
}
// Otherwise get the proper spelling of the search term from clang, so we can put it into the
// search widget.
const TextDocumentIdentifier docId(DocumentUri::fromFilePath(document->filePath()));
const TextDocumentPositionParams params(docId, Range(cursor).start());
SymbolInfoRequest symReq(params);
const bool categorize = CppEditor::codeModelSettings()->categorizeFindReferences();
symReq.setResponseCallback([this, doc = QPointer(document), cursor, replacement, categorize]
(const SymbolInfoRequest::Response &response) {
if (!doc)
@@ -2442,7 +2452,7 @@ static void semanticHighlighter(QFutureInterface<HighlightingResult> &future,
} else if (token.type == "comment") { // "comment" means code disabled via the preprocessor
styles.mainStyle = C_DISABLED_CODE;
} else if (token.type == "namespace") {
styles.mainStyle = C_TYPE;
styles.mainStyle = C_NAMESPACE;
} else if (token.type == "property") {
styles.mainStyle = C_FIELD;
} else if (token.type == "enum") {
@@ -2463,6 +2473,8 @@ static void semanticHighlighter(QFutureInterface<HighlightingResult> &future,
}
if (token.modifiers.contains("declaration"))
styles.mixinStyles.push_back(C_DECLARATION);
if (token.modifiers.contains("static"))
styles.mixinStyles.push_back(C_STATIC_MEMBER);
if (isOutputParameter(token))
styles.mixinStyles.push_back(C_OUTPUT_ARGUMENT);
qCDebug(clangdLogHighlight) << "adding highlighting result"

View File

@@ -764,12 +764,12 @@ void ClangdTestHighlighting::test_data()
QTest::newRow("struct declaration") << 50 << 8 << 50 << 11
<< QList<int>{C_TYPE, C_DECLARATION} << 0;
QTest::newRow("namespace declaration") << 160 << 11 << 160 << 20
<< QList<int>{C_TYPE, C_DECLARATION} << 0;
<< QList<int>{C_NAMESPACE, C_DECLARATION} << 0;
QTest::newRow("namespace alias declaration") << 164 << 11 << 164 << 25
<< QList<int>{C_TYPE, C_DECLARATION} << 0;
<< QList<int>{C_NAMESPACE, C_DECLARATION} << 0;
QTest::newRow("struct in namespaced using declaration") << 165 << 18 << 165 << 35
<< QList<int>{C_TYPE} << 0;
QTest::newRow("namespace reference") << 166 << 1 << 166 << 10 << QList<int>{C_TYPE} << 0;
QTest::newRow("namespace reference") << 166 << 1 << 166 << 10 << QList<int>{C_NAMESPACE} << 0;
QTest::newRow("namespaced struct in global variable declaration") << 166 << 12 << 166 << 29
<< QList<int>{C_TYPE} << 0;
QTest::newRow("virtual function declaration") << 170 << 18 << 170 << 33
@@ -992,7 +992,8 @@ void ClangdTestHighlighting::test_data()
<< QList<int>{C_PUNCTUATION} << int(CppEditor::SemanticHighlighter::AngleBracketOpen);
QTest::newRow("class template instantiation (closing angle bracket)") << 384 << 22 << 384 << 23
<< QList<int>{C_PUNCTUATION} << int(CppEditor::SemanticHighlighter::AngleBracketClose);
QTest::newRow("namespace in declaration") << 413 << 4 << 413 << 26 << QList<int>{C_TYPE} << 0;
QTest::newRow("namespace in declaration") << 413 << 4 << 413 << 26
<< QList<int>{C_NAMESPACE} << 0;
QTest::newRow("namespaced class in declaration") << 413 << 28 << 413 << 41
<< QList<int>{C_TYPE} << 0;
QTest::newRow("class as template argument in declaration") << 413 << 42 << 413 << 52
@@ -1099,9 +1100,9 @@ void ClangdTestHighlighting::test_data()
QTest::newRow("local variable captured by lambda") << 442 << 24 << 442 << 27
<< QList<int>{C_LOCAL} << 0;
QTest::newRow("static protected member") << 693 << 16 << 693 << 30
<< QList<int>{C_FIELD, C_DECLARATION} << 0;
<< QList<int>{C_FIELD, C_DECLARATION, C_STATIC_MEMBER} << 0;
QTest::newRow("static private member") << 696 << 16 << 696 << 28
<< QList<int>{C_FIELD, C_DECLARATION} << 0;
<< QList<int>{C_FIELD, C_DECLARATION, C_STATIC_MEMBER} << 0;
QTest::newRow("alias template declaration (opening angle bracket)") << 700 << 10 << 700 << 11
<< QList<int>{C_PUNCTUATION} << int(CppEditor::SemanticHighlighter::AngleBracketOpen);
QTest::newRow("alias template declaration (closing angle bracket)") << 700 << 16 << 700 << 17
@@ -1163,14 +1164,14 @@ void ClangdTestHighlighting::test_data()
QTest::newRow("reference to global variable") << 764 << 5 << 764 << 14
<< QList<int>{C_GLOBAL} << 0;
QTest::newRow("nested template instantiation (namespace 1)") << 773 << 8 << 773 << 11
<< QList<int>{C_TYPE} << 0;
<< QList<int>{C_NAMESPACE} << 0;
QTest::newRow("nested template instantiation (type 1)") << 773 << 13 << 773 << 19
<< QList<int>{C_TYPE} << 0;
QTest::newRow("nested template instantiation (opening angle bracket 1)")
<< 773 << 19 << 773 << 20
<< QList<int>{C_PUNCTUATION} << int(CppEditor::SemanticHighlighter::AngleBracketOpen);
QTest::newRow("nested template instantiation (namespace 2)") << 773 << 20 << 773 << 23
<< QList<int>{C_TYPE} << 0;
<< QList<int>{C_NAMESPACE} << 0;
QTest::newRow("nested template instantiation (type 2)") << 773 << 25 << 773 << 29
<< QList<int>{C_TYPE} << 0;
QTest::newRow("nested template instantiation (opening angle bracket 2)")

View File

@@ -575,11 +575,11 @@ void ExternalToolConfig::updateItem(const QModelIndex &index)
if (!tool)
return;
tool->setDescription(m_ui.description->text());
QStringList executables = tool->executables();
FilePaths executables = tool->executables();
if (executables.size() > 0)
executables[0] = m_ui.executable->rawPath();
executables[0] = m_ui.executable->rawFilePath();
else
executables << m_ui.executable->rawPath();
executables << m_ui.executable->rawFilePath();
tool->setExecutables(executables);
tool->setArguments(m_ui.arguments->text());
tool->setWorkingDirectory(m_ui.workingDirectory->rawFilePath());
@@ -607,8 +607,8 @@ void ExternalToolConfig::showInfoForItem(const QModelIndex &index)
}
m_ui.infoWidget->setEnabled(true);
m_ui.description->setText(tool->description());
m_ui.executable->setPath(tool->executables().isEmpty() ? QString()
: tool->executables().constFirst());
m_ui.executable->setFilePath(tool->executables().isEmpty() ? FilePath()
: tool->executables().constFirst());
m_ui.arguments->setText(tool->arguments());
m_ui.workingDirectory->setFilePath(tool->workingDirectory());
m_ui.outputBehavior->setCurrentIndex(int(tool->outputHandling()));

View File

@@ -154,7 +154,7 @@ int ExternalTool::order() const
return m_order;
}
QStringList ExternalTool::executables() const
FilePaths ExternalTool::executables() const
{
return m_executables;
}
@@ -250,43 +250,36 @@ void ExternalTool::setDescription(const QString &description)
m_description = description;
}
void ExternalTool::setOutputHandling(OutputHandling handling)
{
m_outputHandling = handling;
}
void ExternalTool::setErrorHandling(OutputHandling handling)
{
m_errorHandling = handling;
}
void ExternalTool::setModifiesCurrentDocument(bool modifies)
{
m_modifiesCurrentDocument = modifies;
}
void ExternalTool::setExecutables(const QStringList &executables)
void ExternalTool::setExecutables(const FilePaths &executables)
{
m_executables = executables;
}
void ExternalTool::setArguments(const QString &arguments)
{
m_arguments = arguments;
}
void ExternalTool::setInput(const QString &input)
{
m_input = input;
}
void ExternalTool::setWorkingDirectory(const FilePath &workingDirectory)
{
m_workingDirectory = workingDirectory;
@@ -417,7 +410,7 @@ ExternalTool * ExternalTool::createFromXml(const QByteArray &xml, QString *error
}
while (reader.readNextStartElement()) {
if (reader.name() == QLatin1String(kPath)) {
tool->m_executables.append(reader.readElementText());
tool->m_executables.append(FilePath::fromString(reader.readElementText()));
} else if (reader.name() == QLatin1String(kArguments)) {
if (!tool->m_arguments.isEmpty()) {
reader.raiseError("only one <arguments> element allowed");
@@ -519,8 +512,8 @@ bool ExternalTool::save(QString *errorMessage) const
out.writeAttribute(kOutput, stringForOutputHandling(m_outputHandling));
out.writeAttribute(kError, stringForOutputHandling(m_errorHandling));
out.writeAttribute(kModifiesDocument, QLatin1String(m_modifiesCurrentDocument ? kYes : kNo));
foreach (const QString &executable, m_executables)
out.writeTextElement(kPath, executable);
for (const FilePath &executable : m_executables)
out.writeTextElement(kPath, executable.toString());
if (!m_arguments.isEmpty())
out.writeTextElement(kArguments, m_arguments);
if (!m_input.isEmpty())
@@ -608,11 +601,12 @@ bool ExternalToolRunner::resolve()
{
// executable
QStringList expandedExecutables; /* for error message */
foreach (const QString &executable, m_tool->executables()) {
QString expanded = expander->expand(executable);
FilePaths expandedExecutables; /* for error message */
const FilePaths executables = m_tool->executables();
for (const FilePath &executable : executables) {
FilePath expanded = expander->expand(executable);
expandedExecutables.append(expanded);
m_resolvedExecutable = m_resolvedEnvironment.searchInPath(expanded);
m_resolvedExecutable = m_resolvedEnvironment.searchInPath(expanded.path());
if (!m_resolvedExecutable.isEmpty())
break;
}
@@ -620,7 +614,8 @@ bool ExternalToolRunner::resolve()
m_hasError = true;
for (int i = 0; i < expandedExecutables.size(); ++i) {
m_errorString += tr("Could not find executable for \"%1\" (expanded \"%2\")")
.arg(m_tool->executables().at(i), expandedExecutables.at(i));
.arg(m_tool->executables().at(i).toUserOutput(),
expandedExecutables.at(i).toUserOutput());
m_errorString += QLatin1Char('\n');
}
if (!m_errorString.isEmpty())

View File

@@ -64,7 +64,7 @@ public:
OutputHandling errorHandling() const;
bool modifiesCurrentDocument() const;
QStringList executables() const;
Utils::FilePaths executables() const;
QString arguments() const;
QString input() const;
Utils::FilePath workingDirectory() const;
@@ -95,7 +95,7 @@ public:
void setOutputHandling(OutputHandling handling);
void setErrorHandling(OutputHandling handling);
void setModifiesCurrentDocument(bool modifies);
void setExecutables(const QStringList &executables);
void setExecutables(const Utils::FilePaths &executables);
void setArguments(const QString &arguments);
void setInput(const QString &input);
void setWorkingDirectory(const Utils::FilePath &workingDirectory);
@@ -108,7 +108,7 @@ private:
QString m_displayName;
QString m_displayCategory;
int m_order = -1;
QStringList m_executables;
Utils::FilePaths m_executables;
QString m_arguments;
QString m_input;
Utils::FilePath m_workingDirectory;

View File

@@ -298,7 +298,8 @@ static const HelpItem::Links getBestLink(const HelpItem::Links &links)
// documentation, that we only return the Qt5 link even though the Qt5 and Qt4 URLs look
// different.
QVersionNumber highestVersion;
HelpItem::Link bestLink;
// Default to first link if version extraction failed, possibly because it is not a Qt doc link
HelpItem::Link bestLink = links.front();
for (const HelpItem::Link &link : links) {
const QVersionNumber version = extractVersion(link.second).second;
if (version > highestVersion) {

View File

@@ -477,7 +477,7 @@ bool CheckSymbols::visit(NamespaceAST *ast)
if (!tok.generated()) {
int line, column;
getTokenStartPosition(ast->identifier_token, &line, &column);
Result use(line, column, tok.utf16chars(), SemanticHighlighter::TypeUse);
Result use(line, column, tok.utf16chars(), SemanticHighlighter::NamespaceUse);
addUse(use);
}
}
@@ -1221,7 +1221,15 @@ void CheckSymbols::addType(ClassOrNamespace *b, NameAST *ast)
int line, column;
getTokenStartPosition(startToken, &line, &column);
const unsigned length = tok.utf16chars();
const Result use(line, column, length, SemanticHighlighter::TypeUse);
Kind kind = SemanticHighlighter::TypeUse;
const QList<Symbol *> &symbols = b->symbols();
for (const Symbol * const s : symbols) {
if (s->isNamespace()) {
kind = SemanticHighlighter::NamespaceUse;
break;
}
}
const Result use(line, column, length, kind);
addUse(use);
}
@@ -1266,6 +1274,8 @@ bool CheckSymbols::maybeAddTypeOrStatic(const QList<LookupItem> &candidates, Nam
Kind kind = SemanticHighlighter::TypeUse;
if (c->enclosingEnum() != nullptr)
kind = SemanticHighlighter::EnumerationUse;
else if (c->isNamespace())
kind = SemanticHighlighter::NamespaceUse;
else if (c->isStatic())
// treat static variable as a field(highlighting)
kind = SemanticHighlighter::FieldUse;
@@ -1305,7 +1315,8 @@ bool CheckSymbols::maybeAddField(const QList<LookupItem> &candidates, NameAST *a
getTokenStartPosition(startToken, &line, &column);
const unsigned length = tok.utf16chars();
const Result use(line, column, length, SemanticHighlighter::FieldUse);
const Result use(line, column, length, c->isStatic()
? SemanticHighlighter::StaticFieldUse : SemanticHighlighter::FieldUse);
addUse(use);
return true;
@@ -1359,12 +1370,15 @@ bool CheckSymbols::maybeAddFunction(const QList<LookupItem> &candidates, NameAST
continue; // TODO: add diagnostic messages and color call-operators calls too?
const bool isVirtual = funTy->isVirtual();
const bool isStaticMember = funTy->isStatic() && funTy->enclosingClass();
Kind matchingKind;
if (functionKind == FunctionDeclaration) {
matchingKind = isVirtual ? SemanticHighlighter::VirtualFunctionDeclarationUse
: isStaticMember ? SemanticHighlighter::StaticMethodDeclarationUse
: SemanticHighlighter::FunctionDeclarationUse;
} else {
matchingKind = isVirtual ? SemanticHighlighter::VirtualMethodUse
: isStaticMember ? SemanticHighlighter::StaticMethodUse
: SemanticHighlighter::FunctionUse;
}
if (argumentCount < funTy->minimumArgumentCount()) {

View File

@@ -326,6 +326,20 @@ void DoxygenTest::testBasic_data()
"};\n"
);
QTest::newRow("classTemplate") << _(
"bool preventFolding;\n"
"/**|\n"
"template<typename T> class C {\n"
"};\n"
) << _(
"bool preventFolding;\n"
"/**\n"
" * @brief The C class\n"
" */\n"
"template<typename T> class C {\n"
"};\n"
);
QTest::newRow("continuation_after_text_in_first_line") << _(
"bool preventFolding;\n"
"/*! leading comment|\n"

View File

@@ -141,6 +141,9 @@ QString DoxygenGenerator::generate(QTextCursor cursor,
QString DoxygenGenerator::generate(QTextCursor cursor, DeclarationAST *decl)
{
if (const TemplateDeclarationAST * const templDecl = decl->asTemplateDeclaration())
decl = templDecl->declaration;
SpecifierAST *spec = nullptr;
DeclaratorAST *decltr = nullptr;
if (SimpleDeclarationAST *simpleDecl = decl->asSimpleDeclaration()) {

View File

@@ -316,6 +316,7 @@ void SemanticHighlighter::updateFormatMapFromFontSettings()
const FontSettings &fs = m_baseTextDocument->fontSettings();
m_formatMap[TypeUse] = fs.toTextCharFormat(C_TYPE);
m_formatMap[NamespaceUse] = fs.toTextCharFormat(C_NAMESPACE);
m_formatMap[LocalUse] = fs.toTextCharFormat(C_LOCAL);
m_formatMap[FieldUse] = fs.toTextCharFormat(C_FIELD);
m_formatMap[EnumerationUse] = fs.toTextCharFormat(C_ENUMERATION);
@@ -328,6 +329,12 @@ void SemanticHighlighter::updateFormatMapFromFontSettings()
m_formatMap[VirtualFunctionDeclarationUse] =
fs.toTextCharFormat(TextStyles::mixinStyle(C_VIRTUAL_METHOD, C_DECLARATION));
m_formatMap[PseudoKeywordUse] = fs.toTextCharFormat(C_KEYWORD);
m_formatMap[StaticFieldUse]
= fs.toTextCharFormat(TextStyles::mixinStyle(C_FIELD, C_STATIC_MEMBER));
m_formatMap[StaticMethodUse]
= fs.toTextCharFormat(TextStyles::mixinStyle(C_FUNCTION, C_STATIC_MEMBER));
m_formatMap[StaticMethodDeclarationUse] = fs.toTextCharFormat(
TextStyles::mixinStyle(C_FUNCTION, {C_DECLARATION, C_STATIC_MEMBER}));
}
} // namespace CppEditor

View File

@@ -48,6 +48,7 @@ public:
enum Kind {
Unknown = 0,
TypeUse,
NamespaceUse,
LocalUse,
FieldUse,
EnumerationUse,
@@ -58,6 +59,9 @@ public:
PseudoKeywordUse,
FunctionDeclarationUse,
VirtualFunctionDeclarationUse,
StaticFieldUse,
StaticMethodUse,
StaticMethodDeclarationUse,
AngleBracketOpen,
AngleBracketClose,
DoubleAngleBracketClose,

View File

@@ -57,8 +57,11 @@
#include <coreplugin/icore.h>
#include <coreplugin/messagebox.h>
#include <projectexplorer/taskhub.h>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtversionmanager.h>
#include <texteditor/texteditor.h>
#include <utils/checkablemessagebox.h>
#include <utils/consoleprocess.h>
#include <utils/fileutils.h>
#include <utils/hostosinfo.h>
@@ -2243,6 +2246,60 @@ static inline bool checkCommandToken(const QString &tokenPrefix, const QString &
return ok;
}
// look for Qt Core Debug module to check whether it is sdk provided
// and the pdb files are installed in a path discoverable by the debugger
void CdbEngine::checkQtSdkPdbFiles(const QString &module)
{
const QRegularExpression qtCoreModuleRegExp("(Qt\\dCored).dll");
const QRegularExpressionMatch match = qtCoreModuleRegExp.match(module);
if (!match.hasMatch())
return;
const FilePath modulePath = FilePath::fromUserInput(module).parentDir();
QtSupport::BaseQtVersion *version = QtSupport::QtVersionManager::version(
[modulePath](const QtSupport::BaseQtVersion *version) {
return version->isAutodetected() && version->binPath() == modulePath;
});
if (!version)
return;
const QString qtCoreModuleName = match.captured(1);
// Check the usual location of pdb files to avoid the more expensive part of asking cdb
const FilePath pdbPath = modulePath.pathAppended(qtCoreModuleName + ".pdb");
if (pdbPath.exists())
return;
// If there are no pdb files in the usual location, check whether the user has setup the symbol
// path in order to find the debug symbols.
// But first we need to load the symbols in order to check whether the pdb files can be found
runCommand({"ld " + qtCoreModuleName, BuiltinCommand});
DebuggerCommand cmd;
cmd.function = "lm m " + qtCoreModuleName;
cmd.callback = [this, qtName = version->displayName()](const DebuggerResponse &response) {
if (response.data.m_data.contains("private pdb symbols"))
return;
const QString message
= tr("The installed %1 is missing debug information files.\n"
"Locals and Expression might not be able to display all Qt Types in a "
"human readable format.\n\n"
"Please install the \"Qt Debug Information Files\" Package from the "
"Maintenance Tool for this Qt installation to get all relevant "
"symbols for the debugger.")
.arg(qtName);
CheckableMessageBox::doNotShowAgainInformation(
Core::ICore::dialogParent(),
tr("Missing Qt Debug Information"),
message,
Core::ICore::settings(),
"CdbQtSdkPdbHint");
showMessage("Missing Qt Debug Information Files package for " + qtName, LogMisc);
};
cmd.flags = BuiltinCommand;
runCommand(cmd);
}
void CdbEngine::parseOutputLine(QString line)
{
// The hooked output callback in the extension suppresses prompts,
@@ -2351,8 +2408,11 @@ void CdbEngine::parseOutputLine(QString line)
// output(32): ModLoad: 00007ffb 00007ffb C:\Windows\system32\KERNEL32.DLL
const QRegularExpression moduleRegExp("[0-9a-fA-F]+(`[0-9a-fA-F]+)? [0-9a-fA-F]+(`[0-9a-fA-F]+)? (.*)");
const QRegularExpressionMatch match = moduleRegExp.match(line);
if (match.hasMatch())
showStatusMessage(tr("Module loaded: %1").arg(match.captured(3).trimmed()), 3000);
if (match.hasMatch()) {
const QString module = match.captured(3).trimmed();
showStatusMessage(tr("Module loaded: %1").arg(module), 3000);
checkQtSdkPdbFiles(module);
}
} else {
showMessage(line, LogMisc);
}

View File

@@ -194,6 +194,7 @@ private:
int elapsedLogTime();
unsigned parseStackTrace(const GdbMi &data, bool sourceStepInto);
void mergeStartParametersSourcePathMap();
void checkQtSdkPdbFiles(const QString &module);
const QString m_tokenPrefix;
void handleSetupFailure(const QString &errorMessage);

View File

@@ -74,6 +74,7 @@
#include <texteditor/fontsettings.h>
#include <utils/basetreeview.h>
#include <utils/checkablemessagebox.h>
#include <utils/macroexpander.h>
#include <utils/processhandle.h>
#include <utils/qtcassert.h>
@@ -1096,7 +1097,7 @@ void DebuggerEngine::gotoLocation(const Location &loc)
showMessage("CANNOT GO TO THIS LOCATION");
return;
}
const QString file = loc.fileName().toString();
const FilePath file = loc.fileName();
const int line = loc.lineNumber();
bool newEditor = false;
IEditor *editor = EditorManager::openEditor(file,
@@ -2729,27 +2730,34 @@ Context CppDebuggerEngine::languageContext() const
void CppDebuggerEngine::validateRunParameters(DebuggerRunParameters &rp)
{
static const QString warnOnInappropriateDebuggerKey = "DebuggerWarnOnInappropriateDebugger";
QtcSettings *coreSettings = Core::ICore::settings();
const bool warnOnRelease = debuggerSettings()->warnOnReleaseBuilds.value()
&& rp.toolChainAbi.osFlavor() != Abi::AndroidLinuxFlavor;
bool warnOnInappropriateDebugger = false;
QString detailedWarning;
switch (rp.toolChainAbi.binaryFormat()) {
case Abi::PEFormat: {
QString preferredDebugger;
if (rp.toolChainAbi.osFlavor() == Abi::WindowsMSysFlavor) {
if (rp.cppEngineType == CdbEngineType)
preferredDebugger = "GDB";
} else if (rp.cppEngineType != CdbEngineType) {
// osFlavor() is MSVC, so the recommended debugger is CDB
preferredDebugger = "CDB";
}
if (!preferredDebugger.isEmpty()) {
warnOnInappropriateDebugger = true;
detailedWarning = DebuggerEngine::tr(
"The inferior is in the Portable Executable format.\n"
"Selecting %1 as debugger would improve the debugging "
"experience for this binary format.").arg(preferredDebugger);
break;
if (CheckableMessageBox::shouldAskAgain(coreSettings, warnOnInappropriateDebuggerKey)) {
QString preferredDebugger;
if (rp.toolChainAbi.osFlavor() == Abi::WindowsMSysFlavor) {
if (rp.cppEngineType == CdbEngineType)
preferredDebugger = "GDB";
} else if (rp.cppEngineType != CdbEngineType && rp.cppEngineType != LldbEngineType) {
// osFlavor() is MSVC, so the recommended debugger is still CDB,
// but don't warn for LLDB which starts to be usable, too.
preferredDebugger = "CDB";
}
if (!preferredDebugger.isEmpty()) {
warnOnInappropriateDebugger = true;
detailedWarning = DebuggerEngine::tr(
"The inferior is in the Portable Executable format.\n"
"Selecting %1 as debugger would improve the debugging "
"experience for this binary format.")
.arg(preferredDebugger);
break;
}
}
if (warnOnRelease
&& rp.cppEngineType == CdbEngineType
@@ -2771,13 +2779,15 @@ void CppDebuggerEngine::validateRunParameters(DebuggerRunParameters &rp)
break;
}
case Abi::ElfFormat: {
if (rp.cppEngineType == CdbEngineType) {
warnOnInappropriateDebugger = true;
detailedWarning = DebuggerEngine::tr(
"The inferior is in the ELF format.\n"
"Selecting GDB or LLDB as debugger would improve the debugging "
"experience for this binary format.");
break;
if (CheckableMessageBox::shouldAskAgain(coreSettings, warnOnInappropriateDebuggerKey)) {
if (rp.cppEngineType == CdbEngineType) {
warnOnInappropriateDebugger = true;
detailedWarning = DebuggerEngine::tr(
"The inferior is in the ELF format.\n"
"Selecting GDB or LLDB as debugger would improve the debugging "
"experience for this binary format.");
break;
}
}
ElfReader reader(rp.symbolFile);
@@ -2876,11 +2886,16 @@ void CppDebuggerEngine::validateRunParameters(DebuggerRunParameters &rp)
return;
}
if (warnOnInappropriateDebugger) {
AsynchronousMessageBox::information(DebuggerEngine::tr("Warning"),
DebuggerEngine::tr("The selected debugger may be inappropriate for the inferior.\n"
"Examining symbols and setting breakpoints by file name and line number "
"may fail.\n")
+ '\n' + detailedWarning);
CheckableMessageBox::doNotShowAgainInformation(
Core::ICore::dialogParent(),
DebuggerEngine::tr("Warning"),
DebuggerEngine::tr(
"The selected debugger may be inappropriate for the inferior.\n"
"Examining symbols and setting breakpoints by file name and line number "
"may fail.\n")
+ '\n' + detailedWarning,
Core::ICore::settings(),
warnOnInappropriateDebuggerKey);
} else if (warnOnRelease) {
AsynchronousMessageBox::information(DebuggerEngine::tr("Warning"),
DebuggerEngine::tr("This does not seem to be a \"Debug\" build.\n"

View File

@@ -150,7 +150,8 @@ void DebuggerItem::reinitializeFromFile(const Environment &sysEnv, QString *erro
// except for the experimental LLDB-MI which insists on --version.
QString version = "-version";
m_lastModified = m_command.lastModified();
if (m_command.baseName().toLower().contains("lldb-mi"))
if (m_command.baseName().toLower().contains("lldb-mi")
|| m_command.baseName().startsWith("LLDBFrontend")) // Comes with Android Studio
version = "--version";
// We don't need to start the uVision executable to
@@ -229,15 +230,16 @@ void DebuggerItem::reinitializeFromFile(const Environment &sysEnv, QString *erro
//! \note If unable to determine the GDB ABI, no ABI is appended to m_abis here.
return;
}
if (output.startsWith("lldb") || output.startsWith("LLDB")) {
if (output.contains("lldb") || output.startsWith("LLDB")) {
m_engineType = LldbEngineType;
m_abis = Abi::abisOfBinary(m_command);
// Version
// Self-build binaries also emit clang and llvm revision.
const QString line = output.split('\n')[0];
if (line.startsWith(("lldb version "))) { // Linux typically.
int pos1 = int(strlen("lldb version "));
const QString nonMacOSPrefix = "lldb version ";
if (line.contains(nonMacOSPrefix)) { // Linux typically, or some Windows builds.
int pos1 = line.indexOf(nonMacOSPrefix) + nonMacOSPrefix.length();
int pos2 = line.indexOf(' ', pos1);
m_version = line.mid(pos1, pos2 - pos1);
} else if (line.startsWith("lldb-") || line.startsWith("LLDB-")) { // Mac typically.

View File

@@ -58,11 +58,12 @@
#include <QJsonArray>
using namespace Core;
using namespace Utils;
namespace Debugger {
namespace Internal {
PdbEngine::PdbEngine()
PdbEngine::PdbEngine() : m_proc(ProcessMode::Writer)
{
setObjectName("PdbEngine");
setDebuggerName("PDB");
@@ -117,13 +118,10 @@ void PdbEngine::setupEngine()
m_interpreter = runParameters().interpreter;
QString bridge = ICore::resourcePath("debugger/pdbbridge.py").toString();
connect(&m_proc, &QProcess::errorOccurred, this, &PdbEngine::handlePdbError);
connect(&m_proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &PdbEngine::handlePdbFinished);
connect(&m_proc, &QProcess::readyReadStandardOutput,
this, &PdbEngine::readPdbStandardOutput);
connect(&m_proc, &QProcess::readyReadStandardError,
this, &PdbEngine::readPdbStandardError);
connect(&m_proc, &QtcProcess::errorOccurred, this, &PdbEngine::handlePdbError);
connect(&m_proc, &QtcProcess::finished, this, &PdbEngine::handlePdbFinished);
connect(&m_proc, &QtcProcess::readyReadStandardOutput, this, &PdbEngine::readPdbStandardOutput);
connect(&m_proc, &QtcProcess::readyReadStandardError, this, &PdbEngine::readPdbStandardError);
QFile scriptFile(runParameters().mainScript);
if (!scriptFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
@@ -134,10 +132,11 @@ void PdbEngine::setupEngine()
}
QStringList args = {bridge, scriptFile.fileName()};
args.append(Utils::ProcessArgs::splitArgs(runParameters().inferior.workingDirectory.path()));
args.append(ProcessArgs::splitArgs(runParameters().inferior.workingDirectory.path()));
showMessage("STARTING " + m_interpreter + ' ' + args.join(' '));
m_proc.setEnvironment(runParameters().debugger.environment.toStringList());
m_proc.start(m_interpreter, args);
m_proc.setEnvironment(runParameters().debugger.environment);
m_proc.setCommand({ FilePath::fromString(m_interpreter), args });
m_proc.start();
if (!m_proc.waitForStarted()) {
const QString msg = tr("Unable to start pdb \"%1\": %2")
@@ -346,7 +345,7 @@ void PdbEngine::refreshState(const GdbMi &reportedState)
void PdbEngine::refreshLocation(const GdbMi &reportedLocation)
{
StackFrame frame;
frame.file = Utils::FilePath::fromString(reportedLocation["file"].data());
frame.file = FilePath::fromString(reportedLocation["file"].data());
frame.line = reportedLocation["line"].toInt();
frame.usable = frame.file.isReadableFile();
if (state() == InferiorRunOk) {
@@ -435,9 +434,10 @@ QString PdbEngine::errorMessage(QProcess::ProcessError error) const
}
}
void PdbEngine::handlePdbFinished(int code, QProcess::ExitStatus type)
void PdbEngine::handlePdbFinished()
{
showMessage(QString("PDB PROCESS FINISHED, status %1, code %2").arg(type).arg(code));
showMessage(QString("PDB PROCESS FINISHED, status %1, code %2")
.arg(m_proc.exitStatus()).arg(m_proc.exitCode()));
notifyEngineSpontaneousShutdown();
}
@@ -495,10 +495,9 @@ void PdbEngine::handleOutput2(const QString &data)
const QString bpnr = line.mid(11, pos1 - 11);
const int pos2 = line.lastIndexOf(':');
QTC_ASSERT(pos2 != -1, continue);
const Utils::FilePath fileName = Utils::FilePath::fromString(
line.mid(pos1 + 4, pos2 - pos1 - 4));
const FilePath fileName = FilePath::fromString(line.mid(pos1 + 4, pos2 - pos1 - 4));
const int lineNumber = line.mid(pos2 + 1).toInt();
const Breakpoint bp = Utils::findOrDefault(breakHandler()->breakpoints(), [&](const Breakpoint &bp) {
const Breakpoint bp = findOrDefault(breakHandler()->breakpoints(), [&](const Breakpoint &bp) {
return bp->parameters().isLocatedAt(fileName, lineNumber, bp->markerFileName())
|| bp->requestedParameters().isLocatedAt(fileName, lineNumber, bp->markerFileName());
});
@@ -535,7 +534,7 @@ void PdbEngine::refreshStack(const GdbMi &stack)
for (const GdbMi &item : stack["frames"]) {
StackFrame frame;
frame.level = item["level"].data();
frame.file = Utils::FilePath::fromString(item["file"].data());
frame.file = FilePath::fromString(item["file"].data());
frame.function = item["function"].data();
frame.module = item["function"].data();
frame.line = item["line"].toInt();

View File

@@ -26,8 +26,8 @@
#pragma once
#include <debugger/debuggerengine.h>
#include <utils/qtcprocess.h>
#include <QProcess>
#include <QVariant>
namespace Debugger {
@@ -100,7 +100,7 @@ private:
QString errorMessage(QProcess::ProcessError error) const;
bool hasCapability(unsigned cap) const override;
void handlePdbFinished(int, QProcess::ExitStatus status);
void handlePdbFinished();
void handlePdbError(QProcess::ProcessError error);
void readPdbStandardOutput();
void readPdbStandardError();
@@ -111,7 +111,7 @@ private:
void updateLocals() override;
QString m_inbuffer;
QProcess m_proc;
Utils::QtcProcess m_proc;
QString m_interpreter;
};

View File

@@ -50,7 +50,12 @@ bool isIntType(const QString &type)
case 'c':
return type == "char";
case 'i':
return type == "int";
return type.startsWith("int") &&
( type == "int"
|| type == "int8_t"
|| type == "int16_t"
|| type == "int32_t"
|| type == "int64_t");
case 'l':
return type == "long"
|| type == "long int"
@@ -86,7 +91,12 @@ bool isIntType(const QString &type)
|| type == "unsigned long"
|| type == "unsigned long int"
|| type == "unsigned long long"
|| type == "unsigned long long int"));
|| type == "unsigned long long int"))
|| (type.startsWith("uint") &&
( type == "uint8_t"
|| type == "uint16_t"
|| type == "uint32_t"
|| type == "uint64_t"));
default:
return false;
}

View File

@@ -718,10 +718,10 @@ static QString formattedValue(const WatchItem *item)
// Append quoted, printable character also for decimal.
// FIXME: This is unreliable.
if (item->type.endsWith("char")) {
if (item->type.endsWith("char") || item->type.endsWith("int8_t")) {
bool ok;
const int code = item->value.toInt(&ok);
bool isUnsigned = item->type == "unsigned char" || item->type == "uchar";
bool isUnsigned = item->type == "unsigned char" || item->type == "uchar" || item->type == "uint8_t";
if (ok)
return reformatCharacter(code, 1, !isUnsigned);
} else if (item->type.endsWith("wchar_t")) {

View File

@@ -59,12 +59,12 @@
#include "fakevimtr.h"
#include <utils/optional.h>
#include <utils/qtcprocess.h>
#include <QDebug>
#include <QFile>
#include <QObject>
#include <QPointer>
#include <QProcess>
#include <QRegularExpression>
#include <QTextStream>
#include <QTimer>
@@ -866,17 +866,10 @@ static QString fromLocalEncoding(const QByteArray &data)
static QString getProcessOutput(const QString &command, const QString &input)
{
QProcess proc;
#if QT_VERSION >= QT_VERSION_CHECK(5,15,0)
QStringList arguments = QProcess::splitCommand(command);
QString executable = arguments.takeFirst();
proc.start(executable, arguments);
#else
proc.start(command);
#endif
proc.waitForStarted();
proc.write(toLocalEncoding(input));
proc.closeWriteChannel();
Utils::QtcProcess proc;
proc.setCommand(Utils::CommandLine::fromUserInput(command));
proc.setWriteData(toLocalEncoding(input));
proc.start();
// FIXME: Process should be interruptable by user.
// Solution is to create a QObject for each process and emit finished state.

View File

@@ -412,12 +412,20 @@ void SemanticTokenSupport::handleSemanticTokensDelta(
auto it = data.begin();
const auto end = data.end();
qCDebug(LOGLSPHIGHLIGHT) << "Edit Tokens for " << filePath;
qCDebug(LOGLSPHIGHLIGHT) << "Data before edit " << data;
for (const SemanticTokensEdit &edit : qAsConst(edits)) {
if (edit.start() > data.size()) // prevent edits after the previously reported data
return;
for (const auto start = data.begin() + edit.start(); it < start; ++it)
newData.append(*it);
newData.append(edit.data().value_or(QList<int>()));
const Utils::optional<QList<int>> editData = edit.data();
if (editData.has_value()) {
newData.append(editData.value());
qCDebug(LOGLSPHIGHLIGHT) << edit.start() << edit.deleteCount() << editData.value();
} else {
qCDebug(LOGLSPHIGHLIGHT) << edit.start() << edit.deleteCount();
}
int deleteCount = edit.deleteCount();
if (deleteCount > std::distance(it, end)) {
qCDebug(LOGLSPHIGHLIGHT)
@@ -434,6 +442,7 @@ void SemanticTokenSupport::handleSemanticTokensDelta(
for (; it != end; ++it)
newData.append(*it);
qCDebug(LOGLSPHIGHLIGHT) << "New Data " << newData;
tokens.setData(newData);
tokens.setResultId(tokensDelta->resultId());
} else {
@@ -478,6 +487,14 @@ void SemanticTokenSupport::highlight(const Utils::FilePath &filePath)
expandedToken.length = token.length;
expandedTokens << expandedToken;
};
if (LOGLSPHIGHLIGHT().isDebugEnabled()) {
qCDebug(LOGLSPHIGHLIGHT) << "Expanded Tokens for " << filePath;
for (const ExpandedSemanticToken &token : qAsConst(expandedTokens)) {
qCDebug(LOGLSPHIGHLIGHT)
<< token.line << token.column << token.length << token.type << token.modifiers;
}
}
m_tokensHandler(doc, expandedTokens, versionedTokens.version);
return;
}

View File

@@ -134,7 +134,6 @@ extend_qtc_plugin(QmlDesigner
modelnodeoperations.cpp modelnodeoperations.h
formatoperation.cpp formatoperation.h
navigation2d.cpp navigation2d.h
gestures.cpp gestures.h
qmldesignericonprovider.cpp qmldesignericonprovider.h
selectioncontext.cpp selectioncontext.h
theme.cpp theme.h

View File

@@ -5,7 +5,6 @@ SOURCES += addimagesdialog.cpp
SOURCES += changestyleaction.cpp
SOURCES += theme.cpp
SOURCES += findimplementation.cpp
SOURCES += gestures.cpp
SOURCES += addsignalhandlerdialog.cpp
SOURCES += layoutingridlayout.cpp
SOURCES += abstractactiongroup.cpp
@@ -27,7 +26,6 @@ HEADERS += addimagesdialog.h
HEADERS += changestyleaction.h
HEADERS += theme.h
HEADERS += findimplementation.h
HEADERS += gestures.h
HEADERS += addsignalhandlerdialog.h
HEADERS += layoutingridlayout.h
HEADERS += abstractactiongroup.h

View File

@@ -1,156 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Design Tooling
**
** 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
** 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.
**
** 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.
**
****************************************************************************/
#include "gestures.h"
#include <QWidget>
namespace QmlDesigner {
Qt::GestureType TwoFingerSwipe::m_type = static_cast<Qt::GestureType>(0);
TwoFingerSwipe::TwoFingerSwipe() {}
Qt::GestureType TwoFingerSwipe::type()
{
return m_type;
}
void TwoFingerSwipe::registerRecognizer()
{
m_type = QGestureRecognizer::registerRecognizer(new TwoFingerSwipeRecognizer());
}
QPointF TwoFingerSwipe::direction() const
{
return m_current.center() - m_last.center();
}
void TwoFingerSwipe::reset()
{
m_start = QLineF();
m_current = QLineF();
m_last = QLineF();
}
QGestureRecognizer::Result TwoFingerSwipe::begin(QTouchEvent *event)
{
Q_UNUSED(event);
return QGestureRecognizer::MayBeGesture;
}
QGestureRecognizer::Result TwoFingerSwipe::update(QTouchEvent *event)
{
if (event->touchPoints().size() != 2) {
if (state() == Qt::NoGesture)
return QGestureRecognizer::Ignore;
else
return QGestureRecognizer::FinishGesture;
}
QTouchEvent::TouchPoint p0 = event->touchPoints().at(0);
QTouchEvent::TouchPoint p1 = event->touchPoints().at(1);
QLineF line(p0.scenePos(), p1.screenPos());
if (m_start.isNull()) {
m_start = line;
m_current = line;
m_last = line;
} else {
auto deltaLength = line.length() - m_current.length();
auto deltaCenter = QLineF(line.center(), m_current.center()).length();
if (deltaLength > deltaCenter)
return QGestureRecognizer::CancelGesture;
m_last = m_current;
m_current = line;
}
setHotSpot(m_current.center());
return QGestureRecognizer::TriggerGesture;
}
QGestureRecognizer::Result TwoFingerSwipe::end(QTouchEvent *event)
{
Q_UNUSED(event);
bool finish = state() != Qt::NoGesture;
reset();
if (finish)
return QGestureRecognizer::FinishGesture;
else
return QGestureRecognizer::CancelGesture;
}
TwoFingerSwipeRecognizer::TwoFingerSwipeRecognizer()
: QGestureRecognizer()
{}
QGesture *TwoFingerSwipeRecognizer::create(QObject *target)
{
if (target && target->isWidgetType())
qobject_cast<QWidget *>(target)->setAttribute(Qt::WA_AcceptTouchEvents);
return new TwoFingerSwipe;
}
QGestureRecognizer::Result TwoFingerSwipeRecognizer::recognize(QGesture *gesture,
QObject *,
QEvent *event)
{
if (gesture->gestureType() != TwoFingerSwipe::type())
return QGestureRecognizer::Ignore;
TwoFingerSwipe *swipe = static_cast<TwoFingerSwipe *>(gesture);
QTouchEvent *touch = static_cast<QTouchEvent *>(event);
switch (event->type()) {
case QEvent::TouchBegin:
return swipe->begin(touch);
case QEvent::TouchUpdate:
return swipe->update(touch);
case QEvent::TouchEnd:
return swipe->end(touch);
default:
return QGestureRecognizer::Ignore;
}
}
void TwoFingerSwipeRecognizer::reset(QGesture *gesture)
{
if (gesture->gestureType() == TwoFingerSwipe::type()) {
TwoFingerSwipe *swipe = static_cast<TwoFingerSwipe *>(gesture);
swipe->reset();
}
QGestureRecognizer::reset(gesture);
}
} // End namespace QmlDesigner.

View File

@@ -1,72 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Design Tooling
**
** 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
** 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.
**
** 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.
**
****************************************************************************/
#pragma once
#include <QGesture>
#include <QGestureRecognizer>
#include <QLineF>
QT_FORWARD_DECLARE_CLASS(QTouchEvent)
namespace QmlDesigner {
class TwoFingerSwipe : public QGesture
{
Q_OBJECT
public:
TwoFingerSwipe();
static Qt::GestureType type();
static void registerRecognizer();
QPointF direction() const;
void reset();
QGestureRecognizer::Result begin(QTouchEvent *event);
QGestureRecognizer::Result update(QTouchEvent *event);
QGestureRecognizer::Result end(QTouchEvent *event);
private:
static Qt::GestureType m_type;
QLineF m_start;
QLineF m_current;
QLineF m_last;
};
class TwoFingerSwipeRecognizer : public QGestureRecognizer
{
public:
TwoFingerSwipeRecognizer();
QGesture *create(QObject *target) override;
QGestureRecognizer::Result recognize(QGesture *gesture, QObject *watched, QEvent *event) override;
void reset(QGesture *gesture) override;
};
} // namespace QmlDesigner

View File

@@ -23,44 +23,38 @@
**
****************************************************************************/
#include "navigation2d.h"
#include "gestures.h"
#include <QGestureEvent>
#include <QScrollBar>
#include <QWheelEvent>
#include <QMetaMethod>
#include <cmath>
namespace QmlDesigner {
Navigation2dScrollBar::Navigation2dScrollBar(QWidget *parent)
: QScrollBar(parent)
{}
bool Navigation2dScrollBar::postEvent(QEvent *event)
void Navigation2dFilter::scroll(const QPointF &direction, QScrollBar *sbx, QScrollBar *sby)
{
if (event->type() == QEvent::Wheel) {
wheelEvent(static_cast<QWheelEvent *>(event));
return true;
}
return false;
auto doScroll = [](QScrollBar *sb, float distance) {
if (sb) {
// max - min + pageStep = sceneRect.size * scale
float d1 = sb->maximum() - sb->minimum();
float d2 = d1 + sb->pageStep();
float val = (distance / d2) * d1;
sb->setValue(sb->value() - val);
}
};
doScroll(sbx, direction.x());
doScroll(sby, direction.y());
}
void Navigation2dScrollBar::wheelEvent(QWheelEvent *event)
{
if (!event->angleDelta().isNull())
QScrollBar::wheelEvent(event);
}
Navigation2dFilter::Navigation2dFilter(QWidget *parent, Navigation2dScrollBar *scrollbar)
Navigation2dFilter::Navigation2dFilter(QWidget *parent)
: QObject(parent)
, m_scrollbar(scrollbar)
{
if (parent) {
if (parent)
parent->grabGesture(Qt::PinchGesture);
if (!scrollbar)
parent->grabGesture(TwoFingerSwipe::type());
}
}
bool Navigation2dFilter::eventFilter(QObject *object, QEvent *event)
@@ -82,34 +76,39 @@ bool Navigation2dFilter::gestureEvent(QGestureEvent *event)
event->accept();
return true;
}
} else if (TwoFingerSwipe *swipe = static_cast<TwoFingerSwipe *>(
event->gesture(TwoFingerSwipe::type()))) {
emit panChanged(swipe->direction());
event->accept();
return true;
}
return false;
}
bool Navigation2dFilter::wheelEvent(QWheelEvent *event)
{
if (m_scrollbar) {
if (m_scrollbar->postEvent(event))
event->ignore();
if (event->source() == Qt::MouseEventSynthesizedBySystem) {
emit panChanged(QPointF(event->pixelDelta()));
event->accept();
return true;
} else if (event->source() == Qt::MouseEventNotSynthesized) {
if (event->modifiers().testFlag(Qt::ControlModifier)) {
if (QPointF angle = event->angleDelta(); !angle.isNull()) {
double delta = std::abs(angle.x()) > std::abs(angle.y()) ? angle.x() : angle.y();
if (delta > 0)
emit zoomIn();
else
emit zoomOut();
event->accept();
return true;
auto zoomInSignal = QMetaMethod::fromSignal(&Navigation2dFilter::zoomIn);
bool zoomInConnected = QObject::isSignalConnected(zoomInSignal);
auto zoomOutSignal = QMetaMethod::fromSignal(&Navigation2dFilter::zoomOut);
bool zoomOutConnected = QObject::isSignalConnected(zoomOutSignal);
if (zoomInConnected && zoomOutConnected) {
if (event->modifiers().testFlag(Qt::ControlModifier)) {
if (QPointF angle = event->angleDelta(); !angle.isNull()) {
double delta = std::abs(angle.x()) > std::abs(angle.y()) ? angle.x() : angle.y();
if (delta > 0)
emit zoomIn();
else
emit zoomOut();
event->accept();
return true;
}
}
}
}
return true;
return false;
}
} // End namespace QmlDesigner.

View File

@@ -24,27 +24,14 @@
****************************************************************************/
#pragma once
#include <QScrollBar>
#include <QObject>
QT_FORWARD_DECLARE_CLASS(QGestureEvent)
QT_FORWARD_DECLARE_CLASS(QScrollBar)
QT_FORWARD_DECLARE_CLASS(QWheelEvent)
namespace QmlDesigner {
class Navigation2dScrollBar : public QScrollBar
{
Q_OBJECT
public:
Navigation2dScrollBar(QWidget *parent = nullptr);
bool postEvent(QEvent *event);
protected:
void wheelEvent(QWheelEvent *event) override;
};
class Navigation2dFilter : public QObject
{
Q_OBJECT
@@ -57,7 +44,9 @@ signals:
void zoomOut();
public:
Navigation2dFilter(QWidget *parent = nullptr, Navigation2dScrollBar *scrollbar = nullptr);
static void scroll(const QPointF &direction, QScrollBar *sbx, QScrollBar *sby);
Navigation2dFilter(QWidget *parent);
protected:
bool eventFilter(QObject *obj, QEvent *event) override;
@@ -65,7 +54,6 @@ protected:
private:
bool gestureEvent(QGestureEvent *event);
bool wheelEvent(QWheelEvent *event);
Navigation2dScrollBar *m_scrollbar = nullptr;
};
} // namespace QmlDesigner

View File

@@ -32,6 +32,7 @@
#include <QDoubleSpinBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QScrollArea>
#include <QSplitter>
#include <QVBoxLayout>
@@ -40,16 +41,20 @@ namespace QmlDesigner {
CurveEditor::CurveEditor(CurveEditorModel *model, QWidget *parent)
: QWidget(parent)
, m_tree(new TreeView(model, this))
, m_view(new GraphicsView(model))
, m_view(new GraphicsView(model, this))
{
auto *splitter = new QSplitter;
splitter->addWidget(m_tree);
splitter->addWidget(m_view);
splitter->setStretchFactor(1, 2);
QScrollArea* area = new QScrollArea;
area->setWidget(splitter);
area->setWidgetResizable(true);
auto *box = new QVBoxLayout;
box->addWidget(createToolBar(model));
box->addWidget(splitter);
box->addWidget(area);
setLayout(box);
connect(m_tree, &TreeView::treeItemLocked, model, &CurveEditorModel::setLocked);

View File

@@ -45,6 +45,18 @@
namespace QmlDesigner {
template< typename T >
T* nextParentOfType(QWidget* widget)
{
auto* p = widget->parent();
while (p) {
if (T* w = qobject_cast<T*>(p))
return w;
p = p->parent();
}
return nullptr;
}
GraphicsView::GraphicsView(CurveEditorModel *model, QWidget *parent)
: QGraphicsView(parent)
, m_dragging(false)
@@ -65,7 +77,7 @@ GraphicsView::GraphicsView(CurveEditorModel *model, QWidget *parent)
setResizeAnchor(QGraphicsView::NoAnchor);
setRenderHint(QPainter::Antialiasing, true);
setTransformationAnchor(QGraphicsView::NoAnchor);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
@@ -78,12 +90,19 @@ GraphicsView::GraphicsView(CurveEditorModel *model, QWidget *parent)
connect(m_scene, &GraphicsScene::curveChanged, itemSlot);
QmlDesigner::Navigation2dFilter *filter = new QmlDesigner::Navigation2dFilter(this);
QmlDesigner::Navigation2dFilter *filter = new QmlDesigner::Navigation2dFilter(viewport());
connect(filter, &Navigation2dFilter::panChanged, [this](const QPointF &direction) {
QScrollBar* verticalBar = nullptr;
if (QScrollArea* area = nextParentOfType< QScrollArea >(this))
verticalBar = area->verticalScrollBar();
Navigation2dFilter::scroll(direction, horizontalScrollBar(), verticalBar);
});
auto zoomChanged = &QmlDesigner::Navigation2dFilter::zoomChanged;
connect(filter, zoomChanged, [this](double scale, const QPointF &pos) {
applyZoom(m_zoomX + scale, m_zoomY, mapToGlobal(pos.toPoint()));
});
installEventFilter(filter);
viewport()->installEventFilter(filter);
applyZoom(m_zoomX, m_zoomY);
update();

View File

@@ -31,7 +31,6 @@
#include <nodeinstanceview.h>
#include <designeractionmanager.h>
#include <qmldesignerplugin.h>
#include <designersettings.h>
#include <qmldesignerconstants.h>
#include <viewmanager.h>
@@ -324,10 +323,6 @@ void Edit3DView::addQuick3DImport()
} else {
model()->changeImports({import}, {});
}
// Subcomponent manager update needed to make item library entries appear
QmlDesignerPlugin::instance()->currentDesignDocument()
->updateSubcomponentManagerImport(import);
return;
}
}

View File

@@ -177,18 +177,22 @@ void Edit3DWidget::dropEvent(QDropEvent *dropEvent)
->viewManager().designerActionManager();
QHash<QString, QStringList> addedAssets = actionManager.handleExternalAssetsDrop(dropEvent->mimeData());
// add 3D assets to 3d editor (QtQuick3D import will be added if missing)
ItemLibraryInfo *itemLibInfo = m_view->model()->metaInfo().itemLibraryInfo();
view()->executeInTransaction("Edit3DWidget::dropEvent", [&] {
// add 3D assets to 3d editor (QtQuick3D import will be added if missing)
ItemLibraryInfo *itemLibInfo = m_view->model()->metaInfo().itemLibraryInfo();
const QStringList added3DAssets = addedAssets.value(ComponentCoreConstants::add3DAssetsDisplayString);
for (const QString &assetPath : added3DAssets) {
QString fileName = QFileInfo(assetPath).baseName();
fileName = fileName.at(0).toUpper() + fileName.mid(1); // capitalize first letter
QString type = QString("Quick3DAssets.%1.%1").arg(fileName);
QList<ItemLibraryEntry> entriesForType = itemLibInfo->entriesForType(type.toLatin1());
if (!entriesForType.isEmpty()) // should always be true, but just in case
QmlVisualNode::createQml3DNode(view(), entriesForType.at(0), m_canvas->activeScene()).modelNode();
}
const QStringList added3DAssets = addedAssets.value(ComponentCoreConstants::add3DAssetsDisplayString);
for (const QString &assetPath : added3DAssets) {
QString fileName = QFileInfo(assetPath).baseName();
fileName = fileName.at(0).toUpper() + fileName.mid(1); // capitalize first letter
QString type = QString("Quick3DAssets.%1.%1").arg(fileName);
QList<ItemLibraryEntry> entriesForType = itemLibInfo->entriesForType(type.toLatin1());
if (!entriesForType.isEmpty()) { // should always be true, but just in case
QmlVisualNode::createQml3DNode(view(), entriesForType.at(0),
m_canvas->activeScene(), {}, false).modelNode();
}
}
});
}
} // namespace QmlDesigner

View File

@@ -62,28 +62,12 @@ FormEditorGraphicsView::FormEditorGraphicsView(QWidget *parent)
// eventFilter method so it works also for the space scrolling case as expected
QCoreApplication::instance()->installEventFilter(this);
QmlDesigner::Navigation2dFilter *filter = new QmlDesigner::Navigation2dFilter(this);
QmlDesigner::Navigation2dFilter *filter = new QmlDesigner::Navigation2dFilter(viewport());
connect(filter, &Navigation2dFilter::zoomIn, this, &FormEditorGraphicsView::zoomIn);
connect(filter, &Navigation2dFilter::zoomOut, this, &FormEditorGraphicsView::zoomOut);
auto panChanged = &Navigation2dFilter::panChanged;
connect(filter, panChanged, [this](const QPointF &direction) {
QScrollBar *sbx = horizontalScrollBar();
QScrollBar *sby = verticalScrollBar();
// max - min + pageStep = sceneRect.size * scale
QPointF min(sbx->minimum(), sby->minimum());
QPointF max(sbx->maximum(), sby->maximum());
QPointF step(sbx->pageStep(), sby->pageStep());
QPointF d1 = max - min;
QPointF d2 = d1 + step;
QPoint val = QPointF((direction.x() / d2.x()) * d1.x(), (direction.y() / d2.y()) * d1.y())
.toPoint();
sbx->setValue(sbx->value() - val.x());
sby->setValue(sby->value() - val.y());
connect(filter, &Navigation2dFilter::panChanged, [this](const QPointF &direction) {
Navigation2dFilter::scroll(direction, horizontalScrollBar(), verticalScrollBar());
});
auto zoomChanged = &Navigation2dFilter::zoomChanged;
@@ -93,7 +77,7 @@ FormEditorGraphicsView::FormEditorGraphicsView(QWidget *parent)
emit this->zoomChanged(transform().m11());
}
});
installEventFilter(filter);
viewport()->installEventFilter(filter);
}
bool FormEditorGraphicsView::eventFilter(QObject *watched, QEvent *event)
@@ -123,8 +107,8 @@ void FormEditorGraphicsView::wheelEvent(QWheelEvent *event)
{
if (event->modifiers().testFlag(Qt::ControlModifier))
event->ignore();
else if (event->source() == Qt::MouseEventNotSynthesized)
QGraphicsView::wheelEvent(event);
QGraphicsView::wheelEvent(event);
}
void FormEditorGraphicsView::mousePressEvent(QMouseEvent *event)

View File

@@ -599,20 +599,24 @@ void FormEditorWidget::dropEvent(QDropEvent *dropEvent)
->viewManager().designerActionManager();
QHash<QString, QStringList> addedAssets = actionManager.handleExternalAssetsDrop(dropEvent->mimeData());
// Create Image components for added image assets
const QStringList addedImages = addedAssets.value(ComponentCoreConstants::addImagesDisplayString);
for (const QString &imgPath : addedImages) {
QmlItemNode::createQmlItemNodeFromImage(m_formEditorView, imgPath, {},
m_formEditorView->scene()->rootFormEditorItem()->qmlItemNode());
}
m_formEditorView->executeInTransaction("FormEditorWidget::dropEvent", [&] {
// Create Image components for added image assets
const QStringList addedImages = addedAssets.value(ComponentCoreConstants::addImagesDisplayString);
for (const QString &imgPath : addedImages) {
QmlItemNode::createQmlItemNodeFromImage(m_formEditorView, imgPath, {},
m_formEditorView->scene()->rootFormEditorItem()->qmlItemNode(),
false);
}
// Create Text components for added font assets
const QStringList addedFonts = addedAssets.value(ComponentCoreConstants::addFontsDisplayString);
for (const QString &fontPath : addedFonts) {
QString fontFamily = QFileInfo(fontPath).baseName();
QmlItemNode::createQmlItemNodeFromFont(m_formEditorView, fontFamily, rootItemRect().center(),
m_formEditorView->scene()->rootFormEditorItem()->qmlItemNode());
}
// Create Text components for added font assets
const QStringList addedFonts = addedAssets.value(ComponentCoreConstants::addFontsDisplayString);
for (const QString &fontPath : addedFonts) {
QString fontFamily = QFileInfo(fontPath).baseName();
QmlItemNode::createQmlItemNodeFromFont(m_formEditorView, fontFamily, rootItemRect().center(),
m_formEditorView->scene()->rootFormEditorItem()->qmlItemNode(),
false);
}
});
}
} // namespace QmlDesigner

View File

@@ -388,9 +388,9 @@ void DesignDocument::updateSubcomponentManager()
currentModel()->imports() + currentModel()->possibleImports());
}
void DesignDocument::updateSubcomponentManagerImport(const Import &import)
void DesignDocument::addSubcomponentManagerImport(const Import &import)
{
m_subComponentManager->updateImport(import);
m_subComponentManager->addAndParseImport(import);
}
void DesignDocument::deleteSelected()

View File

@@ -69,7 +69,7 @@ public:
void attachRewriterToModel();
void close();
void updateSubcomponentManager();
void updateSubcomponentManagerImport(const Import &import);
void addSubcomponentManagerImport(const Import &import);
bool isUndoAvailable() const;
bool isRedoAvailable() const;

View File

@@ -686,8 +686,6 @@ void ItemLibraryAssetImporter::finalizeQuick3DImport()
model->changeImports(newImportsToAdd, {});
transaction.commit();
for (const Import &import : qAsConst(newImportsToAdd))
doc->updateSubcomponentManagerImport(import);
}
} catch (const RewritingException &e) {
addError(tr("Failed to update imports: %1").arg(e.description()));

View File

@@ -132,6 +132,10 @@ void ItemLibraryView::modelAboutToBeDetached(Model *model)
void ItemLibraryView::importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports)
{
DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument();
for (const auto &import : addedImports)
document->addSubcomponentManagerImport(import);
updateImports();
// TODO: generalize the logic below to allow adding/removing any Qml component when its import is added/removed
@@ -165,6 +169,10 @@ void ItemLibraryView::importsChanged(const QList<Import> &addedImports, const QL
void ItemLibraryView::possibleImportsChanged(const QList<Import> &possibleImports)
{
DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument();
for (const auto &import : possibleImports)
document->addSubcomponentManagerImport(import);
m_widget->updatePossibleImports(possibleImports);
}

View File

@@ -357,7 +357,6 @@ void ItemLibraryWidget::handleAddImport(int index)
auto document = QmlDesignerPlugin::instance()->currentDesignDocument();
document->documentModel()->changeImports({import}, {});
document->updateSubcomponentManagerImport(import);
m_stackedWidget->setCurrentIndex(0); // switch to the Components view after import is added
updateSearch();

View File

@@ -316,7 +316,12 @@ QList<ModelNode> filteredList(const NodeListProperty &property, bool filter, boo
if (filter) {
list.append(Utils::filtered(property.toModelNodeList(), [] (const ModelNode &arg) {
return QmlItemNode::isValidQmlItemNode(arg) || NodeHints::fromModelNode(arg).visibleInNavigator();
const char auxProp[] = "showInNavigator@Internal";
if (arg.hasAuxiliaryData(auxProp))
return arg.auxiliaryData(auxProp).toBool();
const bool value = QmlItemNode::isValidQmlItemNode(arg) || NodeHints::fromModelNode(arg).visibleInNavigator();
arg.setAuxiliaryData(auxProp, value);
return value;
}));
} else {
list = property.toModelNodeList();
@@ -879,7 +884,6 @@ void NavigatorTreeModel::addImport(const QString &importName)
if (possImport.url() == import.url()) {
import = possImport;
m_view->model()->changeImports({import}, {});
QmlDesignerPlugin::instance()->currentDesignDocument()->updateSubcomponentManagerImport(import);
break;
}
}

View File

@@ -118,7 +118,7 @@ TimelineWidget::TimelineWidget(TimelineView *view)
, m_toolbar(new TimelineToolBar(this))
, m_rulerView(new QGraphicsView(this))
, m_graphicsView(new QGraphicsView(this))
, m_scrollbar(new Navigation2dScrollBar(this))
, m_scrollbar(new QScrollBar(this))
, m_statusBar(new QLabel(this))
, m_timelineView(view)
, m_graphicsScene(new TimelineGraphicsScene(this))
@@ -160,7 +160,6 @@ TimelineWidget::TimelineWidget(TimelineView *view)
m_graphicsView->setFrameShape(QFrame::NoFrame);
m_graphicsView->setFrameShadow(QFrame::Plain);
m_graphicsView->setLineWidth(0);
m_graphicsView->setVerticalScrollBar(new Navigation2dScrollBar);
m_graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
m_graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
@@ -274,13 +273,19 @@ TimelineWidget::TimelineWidget(TimelineView *view)
m_timelineView->addNewTimelineDialog();
});
Navigation2dFilter *filter = new Navigation2dFilter(this, m_scrollbar);
connect(filter, &Navigation2dFilter::zoomChanged, [this](double scale, const QPointF& pos) {
int s = static_cast<int>(std::round(scale*100.));
double ps = m_graphicsScene->mapFromScene(pos.x());
m_graphicsScene->setZoom(std::clamp(m_graphicsScene->zoom() + s, 0, 100), ps);
Navigation2dFilter *filter = new Navigation2dFilter(m_graphicsView->viewport());
connect(filter, &Navigation2dFilter::panChanged, [this](const QPointF &direction) {
Navigation2dFilter::scroll(direction, m_scrollbar, m_graphicsView->verticalScrollBar());
});
installEventFilter(filter);
connect(filter, &Navigation2dFilter::zoomChanged, [this](double scale, const QPointF &pos) {
int s = static_cast<int>(std::round(scale*100.));
int scaleFactor = std::clamp(m_graphicsScene->zoom() + s, 0, 100);
double ps = m_graphicsScene->mapFromScene(pos.x());
m_graphicsScene->setZoom(scaleFactor, ps);
m_toolbar->setScaleFactor(scaleFactor);
});
m_graphicsView->viewport()->installEventFilter(filter);
m_playbackAnimation->stop();
auto playAnimation = [this](QVariant frame) { graphicsScene()->setCurrentFrame(qRound(frame.toDouble())); };

View File

@@ -40,6 +40,7 @@ QT_FORWARD_DECLARE_CLASS(QShowEvent)
QT_FORWARD_DECLARE_CLASS(QString)
QT_FORWARD_DECLARE_CLASS(QPushButton)
QT_FORWARD_DECLARE_CLASS(QVariantAnimation)
QT_FORWARD_DECLARE_CLASS(QScrollBar)
namespace QmlDesigner {
@@ -97,7 +98,7 @@ private:
QGraphicsView *m_graphicsView = nullptr;
Navigation2dScrollBar *m_scrollbar = nullptr;
QScrollBar *m_scrollbar = nullptr;
QLabel *m_statusBar = nullptr;

View File

@@ -90,7 +90,7 @@ TransitionEditorWidget::TransitionEditorWidget(TransitionEditorView *view)
, m_toolbar(new TransitionEditorToolBar(this))
, m_rulerView(new QGraphicsView(this))
, m_graphicsView(new QGraphicsView(this))
, m_scrollbar(new Navigation2dScrollBar(this))
, m_scrollbar(new QScrollBar(this))
, m_statusBar(new QLabel(this))
, m_transitionEditorView(view)
, m_graphicsScene(new TransitionEditorGraphicsScene(this))
@@ -129,7 +129,6 @@ TransitionEditorWidget::TransitionEditorWidget(TransitionEditorView *view)
m_graphicsView->setFrameShape(QFrame::NoFrame);
m_graphicsView->setFrameShadow(QFrame::Plain);
m_graphicsView->setLineWidth(0);
m_graphicsView->setVerticalScrollBar(new Navigation2dScrollBar);
m_graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
m_graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
@@ -223,13 +222,19 @@ TransitionEditorWidget::TransitionEditorWidget(TransitionEditorView *view)
m_transitionEditorView->addNewTransition();
});
Navigation2dFilter *filter = new Navigation2dFilter(this, m_scrollbar);
connect(filter, &Navigation2dFilter::zoomChanged, [this](double scale, const QPointF& pos) {
int s = static_cast<int>(std::round(scale*100.));
double ps = m_graphicsScene->mapFromScene(pos.x());
m_graphicsScene->setZoom(std::clamp(m_graphicsScene->zoom() + s, 0, 100), ps);
Navigation2dFilter *filter = new Navigation2dFilter(m_graphicsView->viewport());
connect(filter, &Navigation2dFilter::panChanged, [this](const QPointF &direction) {
Navigation2dFilter::scroll(direction, m_scrollbar, m_graphicsView->verticalScrollBar());
});
installEventFilter(filter);
connect(filter, &Navigation2dFilter::zoomChanged, [this](double scale, const QPointF &pos) {
int s = static_cast<int>(std::round(scale*100.));
int scaleFactor = std::clamp(m_graphicsScene->zoom() + s, 0, 100);
double ps = m_graphicsScene->mapFromScene(pos.x());
m_graphicsScene->setZoom(scaleFactor, ps);
m_toolbar->setScaleFactor(scaleFactor);
});
m_graphicsView->viewport()->installEventFilter(filter);
}
void TransitionEditorWidget::setTransitionActive(bool b)

View File

@@ -40,6 +40,7 @@ QT_FORWARD_DECLARE_CLASS(QResizeEvent)
QT_FORWARD_DECLARE_CLASS(QShowEvent)
QT_FORWARD_DECLARE_CLASS(QString)
QT_FORWARD_DECLARE_CLASS(QPushButton)
QT_FORWARD_DECLARE_CLASS(QScrollBar)
namespace QmlDesigner {
@@ -47,7 +48,6 @@ class TransitionEditorView;
class TransitionEditorToolBar;
class TransitionEditorGraphicsScene;
class ModelNode;
class Navigation2dScrollBar;
class TransitionEditorWidget : public QWidget
{
@@ -88,7 +88,7 @@ private:
QGraphicsView *m_graphicsView = nullptr;
Navigation2dScrollBar *m_scrollbar = nullptr;
QScrollBar *m_scrollbar = nullptr;
QLabel *m_statusBar = nullptr;

View File

@@ -62,11 +62,14 @@ public:
{ return false; }
private:
void handleOriginalTextChanged();
TextModifier *m_originalModifier;
int m_componentStartOffset;
int m_componentEndOffset;
int m_rootStartOffset;
int m_startLength;
QString m_originalText;
};
} // namespace QmlDesigner

View File

@@ -101,8 +101,9 @@ public:
bool createInTransaction = true);
static QmlVisualNode createQml3DNode(AbstractView *view,
const ItemLibraryEntry &itemLibraryEntry,
qint32 sceneRootId = -1, const QVector3D &position = {});
const ItemLibraryEntry &itemLibraryEntry,
qint32 sceneRootId = -1, const QVector3D &position = {},
bool createInTransaction = true);
static NodeListProperty findSceneNodeProperty(AbstractView *view, qint32 sceneRootId);

View File

@@ -49,7 +49,7 @@ public:
explicit SubComponentManager(Model *model, QObject *parent = nullptr);
void update(const QUrl &fileUrl, const QList<Import> &imports);
void updateImport(const Import &import);
void addAndParseImport(const Import &import);
QStringList qmlFiles() const;
QStringList directories() const;
@@ -59,7 +59,7 @@ private: // functions
void parseFile(const QString &canonicalFilePath, bool addToLibrary, const QString&);
void parseFile(const QString &canonicalFilePath);
void addImport(const Import &import, int index = -1);
bool addImport(const Import &import, int index = -1);
void removeImport(int index);
void parseDirectories();
QFileInfoList watchedFiles(const QString &canonicalDirPath);

View File

@@ -69,16 +69,18 @@ SubComponentManager::SubComponentManager(Model *model, QObject *parent)
this, [this](const QString &path) { parseDirectory(path); });
}
void SubComponentManager::addImport(const Import &import, int index)
bool SubComponentManager::addImport(const Import &import, int index)
{
if (debug)
qDebug() << Q_FUNC_INFO << index << import.file().toUtf8();
bool importExists = false;
if (import.isFileImport()) {
QFileInfo dirInfo = QFileInfo(m_filePath.resolved(import.file()).toLocalFile());
if (dirInfo.exists() && dirInfo.isDir()) {
const QString canonicalDirPath = dirInfo.canonicalFilePath();
m_watcher.addPath(canonicalDirPath);
importExists = true;
//m_dirToQualifier.insertMulti(canonicalDirPath, import.qualifier()); ### todo: proper support for import as
}
} else {
@@ -91,16 +93,21 @@ void SubComponentManager::addImport(const Import &import, int index)
if (dirInfo.exists() && dirInfo.isDir()) {
const QString canonicalDirPath = dirInfo.canonicalFilePath();
m_watcher.addPath(canonicalDirPath);
importExists = true;
//m_dirToQualifier.insertMulti(canonicalDirPath, import.qualifier()); ### todo: proper support for import as
}
}
// TODO: QDeclarativeDomImport::Library
}
if (index == -1)
m_imports.append(import);
else
m_imports.insert(index, import);
if (importExists) {
if (index == -1)
m_imports.append(import);
else
m_imports.insert(index, import);
}
return importExists;
}
void SubComponentManager::removeImport(int index)
@@ -544,9 +551,15 @@ void SubComponentManager::update(const QUrl &filePath, const QList<Import> &impo
parseDirectories();
}
void SubComponentManager::updateImport(const Import &import)
void SubComponentManager::addAndParseImport(const Import &import)
{
addImport(import);
for (const auto &existingImport : std::as_const(m_imports)) {
if (import == existingImport)
return;
}
if (!addImport(import))
return;
if (import.isFileImport()) {
QFileInfo dirInfo = QFileInfo(m_filePath.resolved(import.file()).toLocalFile());

View File

@@ -33,10 +33,13 @@ ComponentTextModifier::ComponentTextModifier(TextModifier *originalModifier, int
m_componentEndOffset(componentEndOffset),
m_rootStartOffset(rootStartOffset)
{
connect(m_originalModifier, &TextModifier::textChanged, this, &TextModifier::textChanged);
connect(m_originalModifier, &TextModifier::textChanged,
this, &ComponentTextModifier::handleOriginalTextChanged);
connect(m_originalModifier, &TextModifier::replaced, this, &TextModifier::replaced);
connect(m_originalModifier, &TextModifier::moved, this, &TextModifier::moved);
m_originalText = m_originalModifier->text();
}
ComponentTextModifier::~ComponentTextModifier() = default;
@@ -146,3 +149,45 @@ void ComponentTextModifier::reactivateChangeSignals()
{
m_originalModifier->reactivateChangeSignals();
}
void ComponentTextModifier::handleOriginalTextChanged()
{
// Update offsets when original text changes, if necessary
// Detect and adjust for removal/addition of unrelated text before the subcomponent code,
// as that can happen even without user editing the text (e.g. whitespace removal at save time)
const QString currentText = m_originalModifier->text();
if (m_originalText.left(m_componentStartOffset) != currentText.left(m_componentStartOffset)) {
// Subcomponent item id is the only reliable indicator for adjustment
const int idIndex = m_originalText.indexOf("id:", m_componentStartOffset);
if (idIndex != -1 && idIndex < m_componentEndOffset) {
int newLineIndex = m_originalText.indexOf('\n', idIndex);
if (newLineIndex != -1) {
const QString checkLine = m_originalText.mid(idIndex, newLineIndex - idIndex);
int lineIndex = currentText.indexOf(checkLine);
if (lineIndex != -1) {
// Paranoia check - This shouldn't happen except when modifying text manually,
// but it's possible something was inserted between id and start
// of the component, which would throw off the calculation, so check that
// the first line is still correct even with new offset.
const int diff = idIndex - lineIndex;
newLineIndex = m_originalText.indexOf('\n', m_componentStartOffset);
if (newLineIndex != -1) {
const QString firstLine = m_originalText.mid(m_componentStartOffset,
newLineIndex - m_componentStartOffset);
const int newStart = m_componentStartOffset - diff;
if (firstLine == currentText.mid(newStart, firstLine.size())) {
m_componentEndOffset -= diff;
m_componentStartOffset = newStart;
m_originalText = currentText;
}
}
}
}
}
}
emit textChanged();
}

View File

@@ -74,8 +74,13 @@ void ModelToTextMerger::nodeRemoved(const ModelNode &removedNode, const NodeAbst
void ModelToTextMerger::propertiesRemoved(const QList<AbstractProperty>& propertyList)
{
foreach (const AbstractProperty &property, propertyList) {
if (isInHierarchy(property) && !property.isDefaultProperty())
// Default property that has actual binding/value should be removed
if (isInHierarchy(property) && (!property.isDefaultProperty()
|| property.isBindingProperty()
|| property.isVariantProperty()
|| property.isNodeProperty())) {
schedule(new RemovePropertyRewriteAction(property));
}
}
}

View File

@@ -174,7 +174,7 @@ QmlItemNode QmlItemNode::createQmlItemNodeFromFont(AbstractView *view,
};
if (executeInTransaction)
view->executeInTransaction("QmlItemNode::createQmlItemNodeFromImage", doCreateQmlItemNodeFromFont);
view->executeInTransaction("QmlItemNode::createQmlItemNodeFromFont", doCreateQmlItemNodeFromFont);
else
doCreateQmlItemNodeFromFont();

View File

@@ -365,14 +365,15 @@ QmlObjectNode QmlVisualNode::createQmlObjectNode(AbstractView *view,
QmlVisualNode QmlVisualNode::createQml3DNode(AbstractView *view,
const ItemLibraryEntry &itemLibraryEntry,
qint32 sceneRootId, const QVector3D &position)
qint32 sceneRootId, const QVector3D &position,
bool createInTransaction)
{
NodeAbstractProperty sceneNodeProperty = sceneRootId != -1 ? findSceneNodeProperty(view, sceneRootId)
: view->rootModelNode().defaultNodeAbstractProperty();
QTC_ASSERT(sceneNodeProperty.isValid(), return {});
return createQmlObjectNode(view, itemLibraryEntry, position, sceneNodeProperty).modelNode();
return createQmlObjectNode(view, itemLibraryEntry, position, sceneNodeProperty, createInTransaction).modelNode();
}
NodeListProperty QmlVisualNode::findSceneNodeProperty(AbstractView *view, qint32 sceneRootId)

View File

@@ -173,14 +173,27 @@ void RewriterView::propertiesAboutToBeRemoved(const QList<AbstractProperty> &pro
if (textToModelMerger()->isActive())
return;
for (const AbstractProperty &property : propertyList) {
if (!property.isDefaultProperty())
continue;
foreach (const AbstractProperty &property, propertyList) {
if (property.isDefaultProperty() && property.isNodeListProperty()) {
m_removeDefaultPropertyTransaction = beginRewriterTransaction(QByteArrayLiteral("RewriterView::propertiesAboutToBeRemoved"));
if (!m_removeDefaultPropertyTransaction.isValid()) {
m_removeDefaultPropertyTransaction = beginRewriterTransaction(
QByteArrayLiteral("RewriterView::propertiesAboutToBeRemoved"));
}
foreach (const ModelNode &node, property.toNodeListProperty().toModelNodeList()) {
modelToTextMerger()->nodeRemoved(node, property.toNodeAbstractProperty(), AbstractView::NoAdditionalChanges);
if (property.isNodeListProperty()) {
const auto nodeList = property.toNodeListProperty().toModelNodeList();
for (const ModelNode &node : nodeList) {
modelToTextMerger()->nodeRemoved(node, property.toNodeAbstractProperty(),
AbstractView::NoAdditionalChanges);
}
} else if (property.isBindingProperty() || property.isVariantProperty()
|| property.isNodeProperty()) {
// Default property that has actual binding/value should be removed.
// We need to do it here in propertiesAboutToBeRemoved, because
// type is no longer determinable after property is removed from the model.
modelToTextMerger()->propertiesRemoved({property});
}
}
}

View File

@@ -33,7 +33,6 @@
#include "generateresource.h"
#include "generatecmakelists.h"
#include "nodeinstanceview.h"
#include "gestures.h"
#include <metainfo.h>
#include <connectionview.h>
@@ -232,8 +231,6 @@ bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *e
if (QFontDatabase::addApplicationFont(fontPath) < 0)
qCWarning(qmldesignerLog) << "Could not add font " << fontPath << "to font database";
TwoFingerSwipe::registerRecognizer();
return true;
}

View File

@@ -461,8 +461,6 @@ Project {
"componentcore/findimplementation.h",
"componentcore/formatoperation.cpp",
"componentcore/formatoperation.h",
"componentcore/gestures.cpp",
"componentcore/gestures.h",
"componentcore/layoutingridlayout.cpp",
"componentcore/layoutingridlayout.h",
"componentcore/theme.cpp",

View File

@@ -177,7 +177,7 @@ public:
QtOptionsPageWidget();
~QtOptionsPageWidget();
static void linkWithQt();
static bool linkWithQt();
private:
void apply() final;
@@ -857,7 +857,16 @@ void QtOptionsPageWidget::setupLinkWithQtButton()
QString tip;
canLinkWithQt(&tip);
m_ui.linkWithQtButton->setToolTip(tip);
connect(m_ui.linkWithQtButton, &QPushButton::clicked, this, &QtOptionsPage::linkWithQt);
connect(m_ui.linkWithQtButton, &QPushButton::clicked, this, [this] {
if (linkWithQt()) {
QWidget *w = window();
// close options dialog
if (QDialog *dialog = qobject_cast<QDialog *>(w))
dialog->accept();
else
window()->close();
}
});
}
void QtOptionsPageWidget::updateCurrentQtName()
@@ -950,7 +959,7 @@ static FilePath defaultQtInstallationPath()
return FileUtils::homePath() / "Qt";
}
void QtOptionsPageWidget::linkWithQt()
bool QtOptionsPageWidget::linkWithQt()
{
const QString title = tr("Choose Qt Installation");
const QString restartText = tr("The change will take effect after restart.");
@@ -1019,8 +1028,9 @@ void QtOptionsPageWidget::linkWithQt()
}
if (askForRestart) {
Core::RestartDialog restartDialog(Core::ICore::dialogParent(), restartText);
restartDialog.exec();
return restartDialog.exec() == QDialog::Accepted;
}
return false;
}
// QtOptionsPage

View File

@@ -337,6 +337,7 @@ void CodeAssistantPrivate::displayProposal(IAssistProposal *newProposal, AssistR
if (!newProposal->hasItemsToPropose(prefix, reason)) {
if (newProposal->isCorrective(m_editorWidget))
newProposal->makeCorrection(m_editorWidget);
destroyContext();
return;
}

View File

@@ -417,6 +417,10 @@ bool FontSettings::loadColorScheme(const QString &fileName,
foreach (const FormatDescription &desc, descriptions) {
const TextStyle id = desc.id();
if (!m_scheme.contains(id)) {
if (id == C_NAMESPACE && m_scheme.contains(C_TYPE)) {
m_scheme.setFormatFor(C_NAMESPACE, m_scheme.formatFor(C_TYPE));
continue;
}
Format format;
const Format &descFormat = desc.format();
// Default fallback for background and foreground is C_TEXT, which is set through

View File

@@ -835,7 +835,7 @@ void TextDocument::cleanWhitespace(const QTextCursor &cursor)
void TextDocument::cleanWhitespace(QTextCursor &cursor, bool inEntireDocument,
bool cleanIndentation)
{
const QString fileName(filePath().fileName());
const bool removeTrailingWhitespace = d->m_storageSettings.removeTrailingWhitespace(filePath().fileName());
auto documentLayout = qobject_cast<TextDocumentLayout*>(d->m_document.documentLayout());
Q_ASSERT(cursor.visualNavigation() == false);
@@ -862,7 +862,7 @@ void TextDocument::cleanWhitespace(QTextCursor &cursor, bool inEntireDocument,
foreach (block, blocks) {
QString blockText = block.text();
if (d->m_storageSettings.removeTrailingWhitespace(fileName))
if (removeTrailingWhitespace)
TabSettings::removeTrailingWhitespace(cursor, block);
const int indent = indentations[block.blockNumber()];

View File

@@ -1572,6 +1572,7 @@ void TextEditorWidgetPrivate::slotSelectionChanged()
m_selectBlockAnchor = QTextCursor();
// Clear any link which might be showing when the selection changes
clearLink();
setClipboardSelection();
}
void TextEditorWidget::gotoBlockStart()
@@ -5244,7 +5245,6 @@ void TextEditorWidget::mouseReleaseEvent(QMouseEvent *e)
return;
QPlainTextEdit::mouseReleaseEvent(e);
d->setClipboardSelection();
}
void TextEditorWidget::mouseDoubleClickEvent(QMouseEvent *e)
@@ -5259,7 +5259,6 @@ void TextEditorWidget::mouseDoubleClickEvent(QMouseEvent *e)
}
QPlainTextEdit::mouseDoubleClickEvent(e);
d->setClipboardSelection();
}
void TextEditorWidgetPrivate::setClipboardSelection()

View File

@@ -54,6 +54,7 @@ const char *nameForStyle(TextStyle style)
case C_NUMBER: return "Number";
case C_STRING: return "String";
case C_TYPE: return "Type";
case C_NAMESPACE: return "Namespace";
case C_LOCAL: return "Local";
case C_PARAMETER: return "Parameter";
case C_GLOBAL: return "Global";
@@ -114,6 +115,7 @@ const char *nameForStyle(TextStyle style)
case C_DECLARATION: return "Declaration";
case C_FUNCTION_DEFINITION: return "FunctionDefinition";
case C_OUTPUT_ARGUMENT: return "OutputArgument";
case C_STATIC_MEMBER: return "StaticMember";
case C_LAST_STYLE_SENTINEL: return "LastStyleSentinel";
}

View File

@@ -54,6 +54,7 @@ enum TextStyle : quint8 {
C_NUMBER,
C_STRING,
C_TYPE,
C_NAMESPACE,
C_LOCAL,
C_PARAMETER,
C_GLOBAL,
@@ -114,6 +115,7 @@ enum TextStyle : quint8 {
C_DECLARATION,
C_FUNCTION_DEFINITION,
C_OUTPUT_ARGUMENT,
C_STATIC_MEMBER,
C_LAST_STYLE_SENTINEL
};

View File

@@ -160,6 +160,8 @@ FormatDescriptions TextEditorSettingsPrivate::initialFormats()
tr("Name of a primitive data type."), Qt::darkYellow);
formatDescr.emplace_back(C_TYPE, tr("Type"), tr("Name of a type."),
Qt::darkMagenta);
formatDescr.emplace_back(C_NAMESPACE, tr("Namespace"), tr("Name of a namespace."),
Qt::darkGreen);
formatDescr.emplace_back(C_LOCAL, tr("Local"),
tr("Local variables."), QColor(9, 46, 100));
formatDescr.emplace_back(C_PARAMETER, tr("Parameter"),
@@ -361,6 +363,10 @@ FormatDescriptions TextEditorSettingsPrivate::initialFormats()
tr("Writable arguments of a function call."),
outputArgumentFormat,
FormatDescription::ShowAllControls);
formatDescr.emplace_back(C_STATIC_MEMBER,
tr("Static Member"),
tr("Names of static fields or member functions."),
FormatDescription::ShowAllControls);
return formatDescr;
}

View File

@@ -36,14 +36,20 @@ struct TextStyles {
TextStyle mainStyle;
MixinTextStyles mixinStyles;
static TextStyles mixinStyle(TextStyle main, TextStyle mixin)
static TextStyles mixinStyle(TextStyle main, const QList<TextStyle> &mixins)
{
TextStyles res;
res.mainStyle = main;
res.mixinStyles.initializeElements();
res.mixinStyles.push_back(mixin);
for (TextStyle mixin : mixins)
res.mixinStyles.push_back(mixin);
return res;
}
static TextStyles mixinStyle(TextStyle main, TextStyle mixin)
{
return mixinStyle(main, QList<TextStyle>{mixin});
}
};
} // namespace TextEditor

View File

@@ -62,6 +62,7 @@ static QString useKindToString(UseKind useKind)
switch (useKind) {
CASE_STR(Unknown);
CASE_STR(TypeUse);
CASE_STR(NamespaceUse);
CASE_STR(LocalUse);
CASE_STR(FieldUse);
CASE_STR(EnumerationUse);
@@ -72,6 +73,9 @@ static QString useKindToString(UseKind useKind)
CASE_STR(FunctionUse);
CASE_STR(FunctionDeclarationUse);
CASE_STR(PseudoKeywordUse);
CASE_STR(StaticFieldUse);
CASE_STR(StaticMethodUse);
CASE_STR(StaticMethodDeclarationUse);
default:
QTest::qFail("Unknown UseKind", __FILE__, __LINE__);
return QLatin1String("Unknown UseKind");
@@ -246,8 +250,8 @@ void tst_CheckSymbols::test_checksymbols_data()
<< _("namespace N {}\n"
"using namespace N;\n")
<< (UseList()
<< Use(1, 11, 1, Highlighting::TypeUse)
<< Use(2, 17, 1, Highlighting::TypeUse));
<< Use(1, 11, 1, Highlighting::NamespaceUse)
<< Use(2, 17, 1, Highlighting::NamespaceUse));
QTest::newRow("LocalUse")
<< _("int f()\n"
@@ -361,21 +365,21 @@ void tst_CheckSymbols::test_checksymbols_data()
"}\n")
<< (UseList()
<< Use(1, 8, 5, Highlighting::TypeUse)
<< Use(3, 16, 3, Highlighting::FieldUse)
<< Use(3, 16, 3, Highlighting::StaticFieldUse)
<< Use(4, 12, 5, Highlighting::TypeUse)
<< Use(6, 9, 5, Highlighting::TypeUse)
<< Use(6, 16, 5, Highlighting::FieldUse)
<< Use(7, 14, 3, Highlighting::FunctionDeclarationUse)
<< Use(11, 5, 5, Highlighting::TypeUse)
<< Use(11, 12, 3, Highlighting::FieldUse)
<< Use(11, 12, 3, Highlighting::FieldUse) // FIXME: Should be StaticField
<< Use(13, 6, 5, Highlighting::TypeUse)
<< Use(13, 13, 5, Highlighting::TypeUse)
<< Use(13, 20, 3, Highlighting::FunctionDeclarationUse)
<< Use(15, 5, 3, Highlighting::FieldUse)
<< Use(15, 5, 3, Highlighting::StaticFieldUse)
<< Use(16, 5, 5, Highlighting::TypeUse)
<< Use(16, 12, 3, Highlighting::FieldUse)
<< Use(16, 12, 3, Highlighting::FieldUse) // FIXME: Should be StaticField
<< Use(17, 5, 5, Highlighting::FieldUse)
<< Use(17, 12, 3, Highlighting::FieldUse));
<< Use(17, 12, 3, Highlighting::StaticFieldUse));
QTest::newRow("VariableHasTheSameNameAsEnumUse")
<< _("struct Foo\n"
@@ -443,11 +447,11 @@ void tst_CheckSymbols::test_checksymbols_data()
"}\n")
<< (UseList()
<< Use(1, 8, 3, Highlighting::TypeUse)
<< Use(3, 16, 3, Highlighting::FunctionDeclarationUse)
<< Use(3, 16, 3, Highlighting::StaticMethodDeclarationUse)
<< Use(6, 6, 3, Highlighting::FunctionDeclarationUse)
<< Use(8, 9, 3, Highlighting::LocalUse)
<< Use(8, 15, 3, Highlighting::TypeUse)
<< Use(8, 20, 3, Highlighting::FunctionUse));
<< Use(8, 20, 3, Highlighting::StaticMethodUse));
QTest::newRow("8902_staticFunctionHighlightingAsMember_functionArgument")
<< _("struct Foo\n"
@@ -461,11 +465,11 @@ void tst_CheckSymbols::test_checksymbols_data()
"}\n")
<< (UseList()
<< Use(1, 8, 3, Highlighting::TypeUse)
<< Use(3, 16, 3, Highlighting::FunctionDeclarationUse)
<< Use(3, 16, 3, Highlighting::StaticMethodDeclarationUse)
<< Use(6, 6, 3, Highlighting::FunctionDeclarationUse)
<< Use(6, 14, 3, Highlighting::LocalUse)
<< Use(8, 5, 3, Highlighting::TypeUse)
<< Use(8, 10, 3, Highlighting::FunctionUse));
<< Use(8, 10, 3, Highlighting::StaticMethodUse));
QTest::newRow("8902_staticFunctionHighlightingAsMember_templateParameter")
<< _("struct Foo\n"
@@ -480,11 +484,11 @@ void tst_CheckSymbols::test_checksymbols_data()
"}\n")
<< (UseList()
<< Use(1, 8, 3, Highlighting::TypeUse)
<< Use(3, 16, 3, Highlighting::FunctionDeclarationUse)
<< Use(3, 16, 3, Highlighting::StaticMethodDeclarationUse)
<< Use(6, 17, 3, Highlighting::TypeUse)
<< Use(7, 6, 3, Highlighting::FunctionDeclarationUse)
<< Use(9, 5, 3, Highlighting::TypeUse)
<< Use(9, 10, 3, Highlighting::FunctionUse));
<< Use(9, 10, 3, Highlighting::StaticMethodUse));
QTest::newRow("staticFunctionHighlightingAsMember_struct")
<< _("struct Foo\n"
@@ -499,11 +503,11 @@ void tst_CheckSymbols::test_checksymbols_data()
"}\n")
<< (UseList()
<< Use(1, 8, 3, Highlighting::TypeUse)
<< Use(3, 16, 3, Highlighting::FunctionDeclarationUse)
<< Use(3, 16, 3, Highlighting::StaticMethodDeclarationUse)
<< Use(6, 8, 3, Highlighting::TypeUse)
<< Use(7, 6, 3, Highlighting::FunctionDeclarationUse)
<< Use(9, 5, 3, Highlighting::TypeUse)
<< Use(9, 10, 3, Highlighting::FunctionUse));
<< Use(9, 10, 3, Highlighting::StaticMethodUse));
QTest::newRow("QTCREATORBUG8890_danglingPointer")
<< _("template<class T> class QList {\n"
@@ -569,13 +573,13 @@ void tst_CheckSymbols::test_checksymbols_data()
<< Use(1, 17, 1, Highlighting::TypeUse)
<< Use(2, 7, 9, Highlighting::TypeUse)
<< Use(5, 12, 1, Highlighting::TypeUse)
<< Use(5, 15, 8, Highlighting::FunctionDeclarationUse)
<< Use(5, 15, 8, Highlighting::StaticMethodDeclarationUse)
<< Use(8, 6, 3, Highlighting::FunctionDeclarationUse)
<< Use(10, 6, 3, Highlighting::FunctionDeclarationUse);
for (int i = 0; i < 250; ++i) {
excessiveUses
<< Use(12 + i, 5, 9, Highlighting::TypeUse)
<< Use(12 + i, 28, 8, Highlighting::FunctionUse);
<< Use(12 + i, 28, 8, Highlighting::StaticMethodUse);
}
QTest::newRow("QTCREATORBUG8974_danglingPointer")
<< excessive
@@ -710,11 +714,11 @@ void tst_CheckSymbols::test_checksymbols_data()
<< Use(1, 14, 4, Highlighting::FieldUse)
<< Use(2, 6, 4, Highlighting::FunctionDeclarationUse)
<< Use(4, 8, 4, Highlighting::FieldUse)
<< Use(6, 11, 3, Highlighting::TypeUse)
<< Use(6, 11, 3, Highlighting::NamespaceUse)
<< Use(7, 16, 4, Highlighting::FieldUse)
<< Use(8, 8, 4, Highlighting::FunctionDeclarationUse)
<< Use(10, 10, 4, Highlighting::FieldUse)
<< Use(13, 11, 3, Highlighting::TypeUse)
<< Use(13, 11, 3, Highlighting::NamespaceUse)
<< Use(15, 27, 4, Highlighting::FieldUse)
<< Use(16, 10, 4, Highlighting::FunctionDeclarationUse)
<< Use(16, 19, 4, Highlighting::FieldUse)
@@ -792,9 +796,9 @@ void tst_CheckSymbols::test_checksymbols_data()
" Foo foo;\n"
"}\n")
<< (UseList()
<< Use(1, 11, 2, Highlighting::TypeUse)
<< Use(1, 11, 2, Highlighting::NamespaceUse)
<< Use(2, 7, 3, Highlighting::TypeUse)
<< Use(4, 7, 2, Highlighting::TypeUse)
<< Use(4, 7, 2, Highlighting::NamespaceUse)
<< Use(4, 11, 3, Highlighting::TypeUse)
<< Use(5, 6, 3, Highlighting::FunctionDeclarationUse)
<< Use(7, 5, 3, Highlighting::TypeUse)
@@ -812,10 +816,10 @@ void tst_CheckSymbols::test_checksymbols_data()
"}\n"
"}\n")
<< (UseList()
<< Use(1, 11, 2, Highlighting::TypeUse)
<< Use(1, 11, 2, Highlighting::NamespaceUse)
<< Use(2, 7, 3, Highlighting::TypeUse)
<< Use(4, 11, 3, Highlighting::TypeUse)
<< Use(5, 7, 2, Highlighting::TypeUse)
<< Use(4, 11, 3, Highlighting::NamespaceUse)
<< Use(5, 7, 2, Highlighting::NamespaceUse)
<< Use(5, 11, 3, Highlighting::TypeUse)
<< Use(6, 6, 3, Highlighting::FunctionDeclarationUse)
<< Use(8, 5, 3, Highlighting::TypeUse)
@@ -831,10 +835,10 @@ void tst_CheckSymbols::test_checksymbols_data()
" Foo foo;\n"
"}\n")
<< (UseList()
<< Use(1, 11, 2, Highlighting::TypeUse)
<< Use(1, 11, 2, Highlighting::NamespaceUse)
<< Use(2, 7, 3, Highlighting::TypeUse)
<< Use(4, 6, 3, Highlighting::FunctionDeclarationUse)
<< Use(6, 11, 2, Highlighting::TypeUse)
<< Use(6, 11, 2, Highlighting::NamespaceUse)
<< Use(6, 15, 3, Highlighting::TypeUse)
<< Use(7, 5, 3, Highlighting::TypeUse)
<< Use(7, 9, 3, Highlighting::LocalUse));
@@ -849,7 +853,7 @@ void tst_CheckSymbols::test_checksymbols_data()
" Foo foo;\n"
"}\n")
<< (UseList()
<< Use(1, 11, 2, Highlighting::TypeUse)
<< Use(1, 11, 2, Highlighting::NamespaceUse)
<< Use(2, 7, 3, Highlighting::TypeUse)
<< Use(5, 6, 3, Highlighting::FunctionDeclarationUse)
<< Use(7, 9, 3, Highlighting::LocalUse));
@@ -866,9 +870,9 @@ void tst_CheckSymbols::test_checksymbols_data()
"}\n"
"}\n")
<< (UseList()
<< Use(1, 11, 2, Highlighting::TypeUse)
<< Use(1, 11, 2, Highlighting::NamespaceUse)
<< Use(2, 7, 3, Highlighting::TypeUse)
<< Use(4, 11, 3, Highlighting::TypeUse)
<< Use(4, 11, 3, Highlighting::NamespaceUse)
<< Use(6, 6, 3, Highlighting::FunctionDeclarationUse)
<< Use(8, 9, 3, Highlighting::LocalUse));
@@ -882,7 +886,7 @@ void tst_CheckSymbols::test_checksymbols_data()
" Foo foo;\n"
"}\n")
<< (UseList()
<< Use(1, 11, 2, Highlighting::TypeUse)
<< Use(1, 11, 2, Highlighting::NamespaceUse)
<< Use(2, 7, 3, Highlighting::TypeUse)
<< Use(4, 6, 3, Highlighting::FunctionDeclarationUse)
<< Use(7, 9, 3, Highlighting::LocalUse));
@@ -944,14 +948,14 @@ void tst_CheckSymbols::test_checksymbols_data()
"}\n")
<< (UseList()
<< Use(1, 8, 1, Highlighting::TypeUse)
<< Use(2, 11, 3, Highlighting::TypeUse)
<< Use(2, 11, 3, Highlighting::NamespaceUse)
<< Use(4, 24, 1, Highlighting::TypeUse)
<< Use(4, 34, 10, Highlighting::TypeUse)
<< Use(6, 11, 2, Highlighting::TypeUse)
<< Use(8, 11, 3, Highlighting::TypeUse)
<< Use(6, 11, 2, Highlighting::NamespaceUse)
<< Use(8, 11, 3, Highlighting::NamespaceUse)
<< Use(8, 16, 10, Highlighting::TypeUse)
<< Use(10, 6, 3, Highlighting::FunctionDeclarationUse)
<< Use(12, 5, 2, Highlighting::TypeUse)
<< Use(12, 5, 2, Highlighting::NamespaceUse)
<< Use(12, 9, 10, Highlighting::TypeUse)
<< Use(12, 20, 1, Highlighting::TypeUse)
<< Use(12, 23, 1, Highlighting::LocalUse));
@@ -967,9 +971,9 @@ void tst_CheckSymbols::test_checksymbols_data()
" Foo foo;\n"
"}\n")
<< (QList<Use>()
<< Use(3, 15, 2, Highlighting::TypeUse)
<< Use(3, 15, 2, Highlighting::NamespaceUse)
<< Use(3, 27, 3, Highlighting::TypeUse)
<< Use(4, 11, 2, Highlighting::TypeUse)
<< Use(4, 11, 2, Highlighting::NamespaceUse)
<< Use(4, 15, 3, Highlighting::TypeUse)
<< Use(6, 6, 3, Highlighting::FunctionDeclarationUse)
<< Use(8, 5, 3, Highlighting::TypeUse)
@@ -991,12 +995,12 @@ void tst_CheckSymbols::test_checksymbols_data()
"}\n"
)
<< (QList<Use>()
<< Use(1, 11, 3, Highlighting::TypeUse)
<< Use(3, 15, 2, Highlighting::TypeUse)
<< Use(1, 11, 3, Highlighting::NamespaceUse)
<< Use(3, 15, 2, Highlighting::NamespaceUse)
<< Use(3, 27, 3, Highlighting::TypeUse)
<< Use(4, 11, 2, Highlighting::TypeUse)
<< Use(4, 11, 2, Highlighting::NamespaceUse)
<< Use(4, 15, 3, Highlighting::TypeUse)
<< Use(6, 11, 3, Highlighting::TypeUse)
<< Use(6, 11, 3, Highlighting::NamespaceUse)
<< Use(8, 10, 3, Highlighting::FunctionDeclarationUse)
<< Use(10, 13, 3, Highlighting::LocalUse)
);

View File

@@ -121,8 +121,8 @@ void ExternaltoolTest::testRead1()
QCOMPARE(tool->displayCategory(), QString::fromLatin1("Linguist"));
QCOMPARE(tool->order(), 1);
QCOMPARE(tool->executables().size(), 2);
QCOMPARE(tool->executables().at(0), QString::fromLatin1("%{QT_INSTALL_BINS}/lupdate"));
QCOMPARE(tool->executables().at(1), QString::fromLatin1("lupdate"));
QCOMPARE(tool->executables().at(0), FilePath::fromString("%{QT_INSTALL_BINS}/lupdate"));
QCOMPARE(tool->executables().at(1), FilePath::fromString("lupdate"));
QCOMPARE(tool->arguments(), QString::fromLatin1("%{CurrentProjectFilePath}"));
QCOMPARE(tool->input(), QString());
QCOMPARE(tool->workingDirectory(), FilePath::fromString("%{CurrentProjectPath}"));
@@ -143,7 +143,7 @@ void ExternaltoolTest::testRead2()
QCOMPARE(tool->displayCategory(), QString::fromLatin1("Text"));
QCOMPARE(tool->order(), -1);
QCOMPARE(tool->executables().size(), 1);
QCOMPARE(tool->executables().at(0), QString::fromLatin1("sort"));
QCOMPARE(tool->executables().at(0), FilePath::fromString("sort"));
QCOMPARE(tool->arguments(), QString());
QCOMPARE(tool->input(), QString::fromLatin1("%{CurrentSelection}"));
QCOMPARE(tool->workingDirectory(), FilePath::fromString("%{CurrentPath}"));
@@ -164,7 +164,7 @@ void ExternaltoolTest::testRead3()
QCOMPARE(tool->displayCategory(), QString::fromLatin1("Text"));
QCOMPARE(tool->order(), -1);
QCOMPARE(tool->executables().size(), 1);
QCOMPARE(tool->executables().at(0), QString::fromLatin1("xterm"));
QCOMPARE(tool->executables().at(0), FilePath::fromString("xterm"));
QVERIFY(tool->arguments().startsWith(QLatin1String("-geom %{")));
QCOMPARE(tool->input(), QString());
QCOMPARE(tool->workingDirectory(), FilePath::fromString("%{CurrentPath}"));

View File

@@ -214,7 +214,7 @@ def verifyBuildAndRun():
appOutput = logApplicationOutput()
if appOutput:
test.verify((re.search(".* exited with code \d+", str(appOutput)) or
re.search("The program has unexpectedly finished\.", str(appOutput))) and
re.search(".* crashed\.", str(appOutput))) and
re.search('[Ss]tarting.*', str(appOutput)),
"Verifying if built app started and closed successfully.")

View File

@@ -190,22 +190,19 @@ def invokeMenuItem(menu, item, *subItems):
itemObject = waitForObjectItem(objectMap.realName(menuObject), item)
waitFor("itemObject.enabled", 2000)
activateItem(itemObject)
numberedPrefix = "(&\\d \| )?"
numberedPrefix = "%d | "
for subItem in subItems:
# we might have numbered sub items (e.g. "Recent Files") - these have this special prefix
if subItem.startswith(numberedPrefix):
# TODO: Find fix for Qt 6
actions = sub.actions()
triggered = False
for i in range(actions.count()):
current = actions.at(i)
nonPrefix = subItem[len(numberedPrefix):]
matcher = re.match("%s(.*)" % numberedPrefix, str(current.text))
if matcher and matcher.group(2) == nonPrefix:
itemObject = current
for i in range(1, 10):
try:
itemObject = waitForObjectItem(itemObject, subItem % i, 1000)
activateItem(itemObject)
triggered = True
break
except:
continue
if not triggered:
test.fail("Could not trigger '%s' - item missing or code wrong?" % subItem,
"Function arguments: '%s', '%s', %s" % (menu, item, str(subItems)))

View File

@@ -199,7 +199,7 @@ def main():
recentFile = os.path.join(folder, current)
if recentFile.startswith(home) and platform.system() in ('Linux', 'Darwin'):
recentFile = recentFile.replace(home, "~", 1)
invokeMenuItem("File", "Recent Files", "(&\\d \| )?%s" % recentFile)
invokeMenuItem("File", "Recent Files", "%d | " + recentFile)
editor = getEditorForFileSuffix(current)
display = displayHintForHighlighterDefinition(current, patterns, lPatterns,
addedHaskell, addedLiterateHaskell)