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] on: [push, pull_request]
env: env:
QT_VERSION: 6.2.0 QT_VERSION: 6.2.1
CLANG_VERSION: 130 CLANG_VERSION: 130
ELFUTILS_VERSION: 0.175 ELFUTILS_VERSION: 0.175
CMAKE_VERSION: 3.21.1 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: if len(rpath) <= 0:
return return
# remove previous Qt RPATH # remove previous Qt RPATH
new_rpath = list(filter(lambda path: not path.startswith(qt_install_prefix) and not path.startswith(qt_install_libs), new_rpath = [path for path in rpath if not path.startswith(qt_install_prefix)
rpath)) and not path.startswith(qt_install_libs)]
# check for Qt linking # check for Qt linking
lddOutput = subprocess.check_output(['ldd', filepath]) lddOutput = subprocess.check_output(['ldd', filepath])
lddDecodedOutput = lddOutput.decode(encoding) if encoding else lddOutput 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 # add Qt RPATH if necessary
relative_path = os.path.relpath(qt_deploy_path, os.path.dirname(filepath)) relative_path = os.path.relpath(qt_deploy_path, os.path.dirname(filepath))
if relative_path == '.': if relative_path == '.':

View File

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

View File

@@ -140,25 +140,6 @@ Section {
ExpandingSpacer {} 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 { PropertyLabel {
text: qsTr("Style name") text: qsTr("Style name")
tooltip: qsTr("Font's style.") tooltip: qsTr("Font's style.")
@@ -267,7 +248,30 @@ Section {
supportGradient: false 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 { FontStyleButtons {
bold: root.boldStyle bold: root.boldStyle

View File

@@ -35,6 +35,7 @@
<style name="String" foreground="#636363"/> <style name="String" foreground="#636363"/>
<style name="Text" foreground="#000000" background="#ffffff"/> <style name="Text" foreground="#000000" background="#ffffff"/>
<style name="Type"/> <style name="Type"/>
<style name="Namespace"/>
<style name="VirtualMethod" italic="true"/> <style name="VirtualMethod" italic="true"/>
<style name="Occurrences.Unused" underlineColor="#8F8F8F" underlineStyle="SingleUnderline"/> <style name="Occurrences.Unused" underlineColor="#8F8F8F" underlineStyle="SingleUnderline"/>
<style name="Warning" underlineColor="#505050" 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)); 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 void ModuleApiInfo::addToHash(QCryptographicHash &hash) const
{ {

View File

@@ -256,7 +256,8 @@ public:
Document::Ptr document(const QString &fileName) const; Document::Ptr document(const QString &fileName) const;
QList<Document::Ptr> documentsInDirectory(const QString &path) 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, Document::MutablePtr documentFromSource(const QString &code,
const QString &fileName, const QString &fileName,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -47,7 +47,8 @@ public:
AndroidRunnerWorker(ProjectExplorer::RunWorker *runner, const QString &packageName); AndroidRunnerWorker(ProjectExplorer::RunWorker *runner, const QString &packageName);
~AndroidRunnerWorker() override; ~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); void adbKill(qint64 pid);
QStringList selector() const; QStringList selector() const;
void forceStop(); void forceStop();

View File

@@ -1302,15 +1302,25 @@ void ClangdClient::findUsages(TextDocument *document, const QTextCursor &cursor,
const Utils::optional<QString> &replacement) const Utils::optional<QString> &replacement)
{ {
// Quick check: Are we even on anything searchable? // Quick check: Are we even on anything searchable?
if (d->searchTermFromCursor(cursor).isEmpty()) const QString searchTerm = d->searchTermFromCursor(cursor);
if (searchTerm.isEmpty())
return; 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. // search widget.
const TextDocumentIdentifier docId(DocumentUri::fromFilePath(document->filePath())); const TextDocumentIdentifier docId(DocumentUri::fromFilePath(document->filePath()));
const TextDocumentPositionParams params(docId, Range(cursor).start()); const TextDocumentPositionParams params(docId, Range(cursor).start());
SymbolInfoRequest symReq(params); SymbolInfoRequest symReq(params);
const bool categorize = CppEditor::codeModelSettings()->categorizeFindReferences();
symReq.setResponseCallback([this, doc = QPointer(document), cursor, replacement, categorize] symReq.setResponseCallback([this, doc = QPointer(document), cursor, replacement, categorize]
(const SymbolInfoRequest::Response &response) { (const SymbolInfoRequest::Response &response) {
if (!doc) if (!doc)
@@ -2442,7 +2452,7 @@ static void semanticHighlighter(QFutureInterface<HighlightingResult> &future,
} else if (token.type == "comment") { // "comment" means code disabled via the preprocessor } else if (token.type == "comment") { // "comment" means code disabled via the preprocessor
styles.mainStyle = C_DISABLED_CODE; styles.mainStyle = C_DISABLED_CODE;
} else if (token.type == "namespace") { } else if (token.type == "namespace") {
styles.mainStyle = C_TYPE; styles.mainStyle = C_NAMESPACE;
} else if (token.type == "property") { } else if (token.type == "property") {
styles.mainStyle = C_FIELD; styles.mainStyle = C_FIELD;
} else if (token.type == "enum") { } else if (token.type == "enum") {
@@ -2463,6 +2473,8 @@ static void semanticHighlighter(QFutureInterface<HighlightingResult> &future,
} }
if (token.modifiers.contains("declaration")) if (token.modifiers.contains("declaration"))
styles.mixinStyles.push_back(C_DECLARATION); styles.mixinStyles.push_back(C_DECLARATION);
if (token.modifiers.contains("static"))
styles.mixinStyles.push_back(C_STATIC_MEMBER);
if (isOutputParameter(token)) if (isOutputParameter(token))
styles.mixinStyles.push_back(C_OUTPUT_ARGUMENT); styles.mixinStyles.push_back(C_OUTPUT_ARGUMENT);
qCDebug(clangdLogHighlight) << "adding highlighting result" qCDebug(clangdLogHighlight) << "adding highlighting result"

View File

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

View File

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

View File

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

View File

@@ -64,7 +64,7 @@ public:
OutputHandling errorHandling() const; OutputHandling errorHandling() const;
bool modifiesCurrentDocument() const; bool modifiesCurrentDocument() const;
QStringList executables() const; Utils::FilePaths executables() const;
QString arguments() const; QString arguments() const;
QString input() const; QString input() const;
Utils::FilePath workingDirectory() const; Utils::FilePath workingDirectory() const;
@@ -95,7 +95,7 @@ public:
void setOutputHandling(OutputHandling handling); void setOutputHandling(OutputHandling handling);
void setErrorHandling(OutputHandling handling); void setErrorHandling(OutputHandling handling);
void setModifiesCurrentDocument(bool modifies); void setModifiesCurrentDocument(bool modifies);
void setExecutables(const QStringList &executables); void setExecutables(const Utils::FilePaths &executables);
void setArguments(const QString &arguments); void setArguments(const QString &arguments);
void setInput(const QString &input); void setInput(const QString &input);
void setWorkingDirectory(const Utils::FilePath &workingDirectory); void setWorkingDirectory(const Utils::FilePath &workingDirectory);
@@ -108,7 +108,7 @@ private:
QString m_displayName; QString m_displayName;
QString m_displayCategory; QString m_displayCategory;
int m_order = -1; int m_order = -1;
QStringList m_executables; Utils::FilePaths m_executables;
QString m_arguments; QString m_arguments;
QString m_input; QString m_input;
Utils::FilePath m_workingDirectory; 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 // documentation, that we only return the Qt5 link even though the Qt5 and Qt4 URLs look
// different. // different.
QVersionNumber highestVersion; 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) { for (const HelpItem::Link &link : links) {
const QVersionNumber version = extractVersion(link.second).second; const QVersionNumber version = extractVersion(link.second).second;
if (version > highestVersion) { if (version > highestVersion) {

View File

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

View File

@@ -326,6 +326,20 @@ void DoxygenTest::testBasic_data()
"};\n" "};\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") << _( QTest::newRow("continuation_after_text_in_first_line") << _(
"bool preventFolding;\n" "bool preventFolding;\n"
"/*! leading comment|\n" "/*! leading comment|\n"

View File

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

View File

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

View File

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

View File

@@ -57,8 +57,11 @@
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <coreplugin/messagebox.h> #include <coreplugin/messagebox.h>
#include <projectexplorer/taskhub.h> #include <projectexplorer/taskhub.h>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtversionmanager.h>
#include <texteditor/texteditor.h> #include <texteditor/texteditor.h>
#include <utils/checkablemessagebox.h>
#include <utils/consoleprocess.h> #include <utils/consoleprocess.h>
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
@@ -2243,6 +2246,60 @@ static inline bool checkCommandToken(const QString &tokenPrefix, const QString &
return ok; 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) void CdbEngine::parseOutputLine(QString line)
{ {
// The hooked output callback in the extension suppresses prompts, // 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 // 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 QRegularExpression moduleRegExp("[0-9a-fA-F]+(`[0-9a-fA-F]+)? [0-9a-fA-F]+(`[0-9a-fA-F]+)? (.*)");
const QRegularExpressionMatch match = moduleRegExp.match(line); const QRegularExpressionMatch match = moduleRegExp.match(line);
if (match.hasMatch()) if (match.hasMatch()) {
showStatusMessage(tr("Module loaded: %1").arg(match.captured(3).trimmed()), 3000); const QString module = match.captured(3).trimmed();
showStatusMessage(tr("Module loaded: %1").arg(module), 3000);
checkQtSdkPdbFiles(module);
}
} else { } else {
showMessage(line, LogMisc); showMessage(line, LogMisc);
} }

View File

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

View File

@@ -74,6 +74,7 @@
#include <texteditor/fontsettings.h> #include <texteditor/fontsettings.h>
#include <utils/basetreeview.h> #include <utils/basetreeview.h>
#include <utils/checkablemessagebox.h>
#include <utils/macroexpander.h> #include <utils/macroexpander.h>
#include <utils/processhandle.h> #include <utils/processhandle.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -1096,7 +1097,7 @@ void DebuggerEngine::gotoLocation(const Location &loc)
showMessage("CANNOT GO TO THIS LOCATION"); showMessage("CANNOT GO TO THIS LOCATION");
return; return;
} }
const QString file = loc.fileName().toString(); const FilePath file = loc.fileName();
const int line = loc.lineNumber(); const int line = loc.lineNumber();
bool newEditor = false; bool newEditor = false;
IEditor *editor = EditorManager::openEditor(file, IEditor *editor = EditorManager::openEditor(file,
@@ -2729,27 +2730,34 @@ Context CppDebuggerEngine::languageContext() const
void CppDebuggerEngine::validateRunParameters(DebuggerRunParameters &rp) void CppDebuggerEngine::validateRunParameters(DebuggerRunParameters &rp)
{ {
static const QString warnOnInappropriateDebuggerKey = "DebuggerWarnOnInappropriateDebugger";
QtcSettings *coreSettings = Core::ICore::settings();
const bool warnOnRelease = debuggerSettings()->warnOnReleaseBuilds.value() const bool warnOnRelease = debuggerSettings()->warnOnReleaseBuilds.value()
&& rp.toolChainAbi.osFlavor() != Abi::AndroidLinuxFlavor; && rp.toolChainAbi.osFlavor() != Abi::AndroidLinuxFlavor;
bool warnOnInappropriateDebugger = false; bool warnOnInappropriateDebugger = false;
QString detailedWarning; QString detailedWarning;
switch (rp.toolChainAbi.binaryFormat()) { switch (rp.toolChainAbi.binaryFormat()) {
case Abi::PEFormat: { case Abi::PEFormat: {
QString preferredDebugger; if (CheckableMessageBox::shouldAskAgain(coreSettings, warnOnInappropriateDebuggerKey)) {
if (rp.toolChainAbi.osFlavor() == Abi::WindowsMSysFlavor) { QString preferredDebugger;
if (rp.cppEngineType == CdbEngineType) if (rp.toolChainAbi.osFlavor() == Abi::WindowsMSysFlavor) {
preferredDebugger = "GDB"; if (rp.cppEngineType == CdbEngineType)
} else if (rp.cppEngineType != CdbEngineType) { preferredDebugger = "GDB";
// osFlavor() is MSVC, so the recommended debugger is CDB } else if (rp.cppEngineType != CdbEngineType && rp.cppEngineType != LldbEngineType) {
preferredDebugger = "CDB"; // osFlavor() is MSVC, so the recommended debugger is still CDB,
} // but don't warn for LLDB which starts to be usable, too.
if (!preferredDebugger.isEmpty()) { preferredDebugger = "CDB";
warnOnInappropriateDebugger = true; }
detailedWarning = DebuggerEngine::tr( if (!preferredDebugger.isEmpty()) {
"The inferior is in the Portable Executable format.\n" warnOnInappropriateDebugger = true;
"Selecting %1 as debugger would improve the debugging " detailedWarning = DebuggerEngine::tr(
"experience for this binary format.").arg(preferredDebugger); "The inferior is in the Portable Executable format.\n"
break; "Selecting %1 as debugger would improve the debugging "
"experience for this binary format.")
.arg(preferredDebugger);
break;
}
} }
if (warnOnRelease if (warnOnRelease
&& rp.cppEngineType == CdbEngineType && rp.cppEngineType == CdbEngineType
@@ -2771,13 +2779,15 @@ void CppDebuggerEngine::validateRunParameters(DebuggerRunParameters &rp)
break; break;
} }
case Abi::ElfFormat: { case Abi::ElfFormat: {
if (rp.cppEngineType == CdbEngineType) { if (CheckableMessageBox::shouldAskAgain(coreSettings, warnOnInappropriateDebuggerKey)) {
warnOnInappropriateDebugger = true; if (rp.cppEngineType == CdbEngineType) {
detailedWarning = DebuggerEngine::tr( warnOnInappropriateDebugger = true;
"The inferior is in the ELF format.\n" detailedWarning = DebuggerEngine::tr(
"Selecting GDB or LLDB as debugger would improve the debugging " "The inferior is in the ELF format.\n"
"experience for this binary format."); "Selecting GDB or LLDB as debugger would improve the debugging "
break; "experience for this binary format.");
break;
}
} }
ElfReader reader(rp.symbolFile); ElfReader reader(rp.symbolFile);
@@ -2876,11 +2886,16 @@ void CppDebuggerEngine::validateRunParameters(DebuggerRunParameters &rp)
return; return;
} }
if (warnOnInappropriateDebugger) { if (warnOnInappropriateDebugger) {
AsynchronousMessageBox::information(DebuggerEngine::tr("Warning"), CheckableMessageBox::doNotShowAgainInformation(
DebuggerEngine::tr("The selected debugger may be inappropriate for the inferior.\n" Core::ICore::dialogParent(),
"Examining symbols and setting breakpoints by file name and line number " DebuggerEngine::tr("Warning"),
"may fail.\n") DebuggerEngine::tr(
+ '\n' + detailedWarning); "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) { } else if (warnOnRelease) {
AsynchronousMessageBox::information(DebuggerEngine::tr("Warning"), AsynchronousMessageBox::information(DebuggerEngine::tr("Warning"),
DebuggerEngine::tr("This does not seem to be a \"Debug\" build.\n" 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. // except for the experimental LLDB-MI which insists on --version.
QString version = "-version"; QString version = "-version";
m_lastModified = m_command.lastModified(); 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"; version = "--version";
// We don't need to start the uVision executable to // 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. //! \note If unable to determine the GDB ABI, no ABI is appended to m_abis here.
return; return;
} }
if (output.startsWith("lldb") || output.startsWith("LLDB")) { if (output.contains("lldb") || output.startsWith("LLDB")) {
m_engineType = LldbEngineType; m_engineType = LldbEngineType;
m_abis = Abi::abisOfBinary(m_command); m_abis = Abi::abisOfBinary(m_command);
// Version // Version
// Self-build binaries also emit clang and llvm revision. // Self-build binaries also emit clang and llvm revision.
const QString line = output.split('\n')[0]; const QString line = output.split('\n')[0];
if (line.startsWith(("lldb version "))) { // Linux typically. const QString nonMacOSPrefix = "lldb version ";
int pos1 = int(strlen("lldb version ")); if (line.contains(nonMacOSPrefix)) { // Linux typically, or some Windows builds.
int pos1 = line.indexOf(nonMacOSPrefix) + nonMacOSPrefix.length();
int pos2 = line.indexOf(' ', pos1); int pos2 = line.indexOf(' ', pos1);
m_version = line.mid(pos1, pos2 - pos1); m_version = line.mid(pos1, pos2 - pos1);
} else if (line.startsWith("lldb-") || line.startsWith("LLDB-")) { // Mac typically. } else if (line.startsWith("lldb-") || line.startsWith("LLDB-")) { // Mac typically.

View File

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

View File

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

View File

@@ -50,7 +50,12 @@ bool isIntType(const QString &type)
case 'c': case 'c':
return type == "char"; return type == "char";
case 'i': 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': case 'l':
return type == "long" return type == "long"
|| type == "long int" || type == "long int"
@@ -86,7 +91,12 @@ bool isIntType(const QString &type)
|| type == "unsigned long" || type == "unsigned long"
|| type == "unsigned long int" || type == "unsigned long int"
|| type == "unsigned long long" || 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: default:
return false; return false;
} }

View File

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

View File

@@ -59,12 +59,12 @@
#include "fakevimtr.h" #include "fakevimtr.h"
#include <utils/optional.h> #include <utils/optional.h>
#include <utils/qtcprocess.h>
#include <QDebug> #include <QDebug>
#include <QFile> #include <QFile>
#include <QObject> #include <QObject>
#include <QPointer> #include <QPointer>
#include <QProcess>
#include <QRegularExpression> #include <QRegularExpression>
#include <QTextStream> #include <QTextStream>
#include <QTimer> #include <QTimer>
@@ -866,17 +866,10 @@ static QString fromLocalEncoding(const QByteArray &data)
static QString getProcessOutput(const QString &command, const QString &input) static QString getProcessOutput(const QString &command, const QString &input)
{ {
QProcess proc; Utils::QtcProcess proc;
#if QT_VERSION >= QT_VERSION_CHECK(5,15,0) proc.setCommand(Utils::CommandLine::fromUserInput(command));
QStringList arguments = QProcess::splitCommand(command); proc.setWriteData(toLocalEncoding(input));
QString executable = arguments.takeFirst(); proc.start();
proc.start(executable, arguments);
#else
proc.start(command);
#endif
proc.waitForStarted();
proc.write(toLocalEncoding(input));
proc.closeWriteChannel();
// FIXME: Process should be interruptable by user. // FIXME: Process should be interruptable by user.
// Solution is to create a QObject for each process and emit finished state. // 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(); auto it = data.begin();
const auto end = data.end(); const auto end = data.end();
qCDebug(LOGLSPHIGHLIGHT) << "Edit Tokens for " << filePath;
qCDebug(LOGLSPHIGHLIGHT) << "Data before edit " << data;
for (const SemanticTokensEdit &edit : qAsConst(edits)) { for (const SemanticTokensEdit &edit : qAsConst(edits)) {
if (edit.start() > data.size()) // prevent edits after the previously reported data if (edit.start() > data.size()) // prevent edits after the previously reported data
return; return;
for (const auto start = data.begin() + edit.start(); it < start; ++it) for (const auto start = data.begin() + edit.start(); it < start; ++it)
newData.append(*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(); int deleteCount = edit.deleteCount();
if (deleteCount > std::distance(it, end)) { if (deleteCount > std::distance(it, end)) {
qCDebug(LOGLSPHIGHLIGHT) qCDebug(LOGLSPHIGHLIGHT)
@@ -434,6 +442,7 @@ void SemanticTokenSupport::handleSemanticTokensDelta(
for (; it != end; ++it) for (; it != end; ++it)
newData.append(*it); newData.append(*it);
qCDebug(LOGLSPHIGHLIGHT) << "New Data " << newData;
tokens.setData(newData); tokens.setData(newData);
tokens.setResultId(tokensDelta->resultId()); tokens.setResultId(tokensDelta->resultId());
} else { } else {
@@ -478,6 +487,14 @@ void SemanticTokenSupport::highlight(const Utils::FilePath &filePath)
expandedToken.length = token.length; expandedToken.length = token.length;
expandedTokens << expandedToken; 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); m_tokensHandler(doc, expandedTokens, versionedTokens.version);
return; return;
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -45,6 +45,18 @@
namespace QmlDesigner { 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) GraphicsView::GraphicsView(CurveEditorModel *model, QWidget *parent)
: QGraphicsView(parent) : QGraphicsView(parent)
, m_dragging(false) , m_dragging(false)
@@ -65,7 +77,7 @@ GraphicsView::GraphicsView(CurveEditorModel *model, QWidget *parent)
setResizeAnchor(QGraphicsView::NoAnchor); setResizeAnchor(QGraphicsView::NoAnchor);
setRenderHint(QPainter::Antialiasing, true); setRenderHint(QPainter::Antialiasing, true);
setTransformationAnchor(QGraphicsView::NoAnchor); setTransformationAnchor(QGraphicsView::NoAnchor);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
setViewportUpdateMode(QGraphicsView::FullViewportUpdate); setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
@@ -78,12 +90,19 @@ GraphicsView::GraphicsView(CurveEditorModel *model, QWidget *parent)
connect(m_scene, &GraphicsScene::curveChanged, itemSlot); 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; auto zoomChanged = &QmlDesigner::Navigation2dFilter::zoomChanged;
connect(filter, zoomChanged, [this](double scale, const QPointF &pos) { connect(filter, zoomChanged, [this](double scale, const QPointF &pos) {
applyZoom(m_zoomX + scale, m_zoomY, mapToGlobal(pos.toPoint())); applyZoom(m_zoomX + scale, m_zoomY, mapToGlobal(pos.toPoint()));
}); });
installEventFilter(filter); viewport()->installEventFilter(filter);
applyZoom(m_zoomX, m_zoomY); applyZoom(m_zoomX, m_zoomY);
update(); update();

View File

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

View File

@@ -177,18 +177,22 @@ void Edit3DWidget::dropEvent(QDropEvent *dropEvent)
->viewManager().designerActionManager(); ->viewManager().designerActionManager();
QHash<QString, QStringList> addedAssets = actionManager.handleExternalAssetsDrop(dropEvent->mimeData()); QHash<QString, QStringList> addedAssets = actionManager.handleExternalAssetsDrop(dropEvent->mimeData());
// add 3D assets to 3d editor (QtQuick3D import will be added if missing) view()->executeInTransaction("Edit3DWidget::dropEvent", [&] {
ItemLibraryInfo *itemLibInfo = m_view->model()->metaInfo().itemLibraryInfo(); // 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); const QStringList added3DAssets = addedAssets.value(ComponentCoreConstants::add3DAssetsDisplayString);
for (const QString &assetPath : added3DAssets) { for (const QString &assetPath : added3DAssets) {
QString fileName = QFileInfo(assetPath).baseName(); QString fileName = QFileInfo(assetPath).baseName();
fileName = fileName.at(0).toUpper() + fileName.mid(1); // capitalize first letter fileName = fileName.at(0).toUpper() + fileName.mid(1); // capitalize first letter
QString type = QString("Quick3DAssets.%1.%1").arg(fileName); QString type = QString("Quick3DAssets.%1.%1").arg(fileName);
QList<ItemLibraryEntry> entriesForType = itemLibInfo->entriesForType(type.toLatin1()); QList<ItemLibraryEntry> entriesForType = itemLibInfo->entriesForType(type.toLatin1());
if (!entriesForType.isEmpty()) // should always be true, but just in case if (!entriesForType.isEmpty()) { // should always be true, but just in case
QmlVisualNode::createQml3DNode(view(), entriesForType.at(0), m_canvas->activeScene()).modelNode(); QmlVisualNode::createQml3DNode(view(), entriesForType.at(0),
} m_canvas->activeScene(), {}, false).modelNode();
}
}
});
} }
} // namespace QmlDesigner } // 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 // eventFilter method so it works also for the space scrolling case as expected
QCoreApplication::instance()->installEventFilter(this); 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::zoomIn, this, &FormEditorGraphicsView::zoomIn);
connect(filter, &Navigation2dFilter::zoomOut, this, &FormEditorGraphicsView::zoomOut); connect(filter, &Navigation2dFilter::zoomOut, this, &FormEditorGraphicsView::zoomOut);
auto panChanged = &Navigation2dFilter::panChanged; connect(filter, &Navigation2dFilter::panChanged, [this](const QPointF &direction) {
connect(filter, panChanged, [this](const QPointF &direction) { Navigation2dFilter::scroll(direction, horizontalScrollBar(), verticalScrollBar());
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());
}); });
auto zoomChanged = &Navigation2dFilter::zoomChanged; auto zoomChanged = &Navigation2dFilter::zoomChanged;
@@ -93,7 +77,7 @@ FormEditorGraphicsView::FormEditorGraphicsView(QWidget *parent)
emit this->zoomChanged(transform().m11()); emit this->zoomChanged(transform().m11());
} }
}); });
installEventFilter(filter); viewport()->installEventFilter(filter);
} }
bool FormEditorGraphicsView::eventFilter(QObject *watched, QEvent *event) bool FormEditorGraphicsView::eventFilter(QObject *watched, QEvent *event)
@@ -123,8 +107,8 @@ void FormEditorGraphicsView::wheelEvent(QWheelEvent *event)
{ {
if (event->modifiers().testFlag(Qt::ControlModifier)) if (event->modifiers().testFlag(Qt::ControlModifier))
event->ignore(); event->ignore();
else if (event->source() == Qt::MouseEventNotSynthesized)
QGraphicsView::wheelEvent(event); QGraphicsView::wheelEvent(event);
} }
void FormEditorGraphicsView::mousePressEvent(QMouseEvent *event) void FormEditorGraphicsView::mousePressEvent(QMouseEvent *event)

View File

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

View File

@@ -388,9 +388,9 @@ void DesignDocument::updateSubcomponentManager()
currentModel()->imports() + currentModel()->possibleImports()); 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() void DesignDocument::deleteSelected()

View File

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

View File

@@ -686,8 +686,6 @@ void ItemLibraryAssetImporter::finalizeQuick3DImport()
model->changeImports(newImportsToAdd, {}); model->changeImports(newImportsToAdd, {});
transaction.commit(); transaction.commit();
for (const Import &import : qAsConst(newImportsToAdd))
doc->updateSubcomponentManagerImport(import);
} }
} catch (const RewritingException &e) { } catch (const RewritingException &e) {
addError(tr("Failed to update imports: %1").arg(e.description())); 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) 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(); updateImports();
// TODO: generalize the logic below to allow adding/removing any Qml component when its import is added/removed // 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) void ItemLibraryView::possibleImportsChanged(const QList<Import> &possibleImports)
{ {
DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument();
for (const auto &import : possibleImports)
document->addSubcomponentManagerImport(import);
m_widget->updatePossibleImports(possibleImports); m_widget->updatePossibleImports(possibleImports);
} }

View File

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

View File

@@ -316,7 +316,12 @@ QList<ModelNode> filteredList(const NodeListProperty &property, bool filter, boo
if (filter) { if (filter) {
list.append(Utils::filtered(property.toModelNodeList(), [] (const ModelNode &arg) { 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 { } else {
list = property.toModelNodeList(); list = property.toModelNodeList();
@@ -879,7 +884,6 @@ void NavigatorTreeModel::addImport(const QString &importName)
if (possImport.url() == import.url()) { if (possImport.url() == import.url()) {
import = possImport; import = possImport;
m_view->model()->changeImports({import}, {}); m_view->model()->changeImports({import}, {});
QmlDesignerPlugin::instance()->currentDesignDocument()->updateSubcomponentManagerImport(import);
break; break;
} }
} }

View File

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

View File

@@ -90,7 +90,7 @@ TransitionEditorWidget::TransitionEditorWidget(TransitionEditorView *view)
, m_toolbar(new TransitionEditorToolBar(this)) , m_toolbar(new TransitionEditorToolBar(this))
, m_rulerView(new QGraphicsView(this)) , m_rulerView(new QGraphicsView(this))
, m_graphicsView(new QGraphicsView(this)) , m_graphicsView(new QGraphicsView(this))
, m_scrollbar(new Navigation2dScrollBar(this)) , m_scrollbar(new QScrollBar(this))
, m_statusBar(new QLabel(this)) , m_statusBar(new QLabel(this))
, m_transitionEditorView(view) , m_transitionEditorView(view)
, m_graphicsScene(new TransitionEditorGraphicsScene(this)) , m_graphicsScene(new TransitionEditorGraphicsScene(this))
@@ -129,7 +129,6 @@ TransitionEditorWidget::TransitionEditorWidget(TransitionEditorView *view)
m_graphicsView->setFrameShape(QFrame::NoFrame); m_graphicsView->setFrameShape(QFrame::NoFrame);
m_graphicsView->setFrameShadow(QFrame::Plain); m_graphicsView->setFrameShadow(QFrame::Plain);
m_graphicsView->setLineWidth(0); m_graphicsView->setLineWidth(0);
m_graphicsView->setVerticalScrollBar(new Navigation2dScrollBar);
m_graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); m_graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
m_graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
@@ -223,13 +222,19 @@ TransitionEditorWidget::TransitionEditorWidget(TransitionEditorView *view)
m_transitionEditorView->addNewTransition(); m_transitionEditorView->addNewTransition();
}); });
Navigation2dFilter *filter = new Navigation2dFilter(this, m_scrollbar); Navigation2dFilter *filter = new Navigation2dFilter(m_graphicsView->viewport());
connect(filter, &Navigation2dFilter::zoomChanged, [this](double scale, const QPointF& pos) { connect(filter, &Navigation2dFilter::panChanged, [this](const QPointF &direction) {
int s = static_cast<int>(std::round(scale*100.)); Navigation2dFilter::scroll(direction, m_scrollbar, m_graphicsView->verticalScrollBar());
double ps = m_graphicsScene->mapFromScene(pos.x());
m_graphicsScene->setZoom(std::clamp(m_graphicsScene->zoom() + s, 0, 100), ps);
}); });
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) 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(QShowEvent)
QT_FORWARD_DECLARE_CLASS(QString) QT_FORWARD_DECLARE_CLASS(QString)
QT_FORWARD_DECLARE_CLASS(QPushButton) QT_FORWARD_DECLARE_CLASS(QPushButton)
QT_FORWARD_DECLARE_CLASS(QScrollBar)
namespace QmlDesigner { namespace QmlDesigner {
@@ -47,7 +48,6 @@ class TransitionEditorView;
class TransitionEditorToolBar; class TransitionEditorToolBar;
class TransitionEditorGraphicsScene; class TransitionEditorGraphicsScene;
class ModelNode; class ModelNode;
class Navigation2dScrollBar;
class TransitionEditorWidget : public QWidget class TransitionEditorWidget : public QWidget
{ {
@@ -88,7 +88,7 @@ private:
QGraphicsView *m_graphicsView = nullptr; QGraphicsView *m_graphicsView = nullptr;
Navigation2dScrollBar *m_scrollbar = nullptr; QScrollBar *m_scrollbar = nullptr;
QLabel *m_statusBar = nullptr; QLabel *m_statusBar = nullptr;

View File

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

View File

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

View File

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

View File

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

View File

@@ -33,10 +33,13 @@ ComponentTextModifier::ComponentTextModifier(TextModifier *originalModifier, int
m_componentEndOffset(componentEndOffset), m_componentEndOffset(componentEndOffset),
m_rootStartOffset(rootStartOffset) 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::replaced, this, &TextModifier::replaced);
connect(m_originalModifier, &TextModifier::moved, this, &TextModifier::moved); connect(m_originalModifier, &TextModifier::moved, this, &TextModifier::moved);
m_originalText = m_originalModifier->text();
} }
ComponentTextModifier::~ComponentTextModifier() = default; ComponentTextModifier::~ComponentTextModifier() = default;
@@ -146,3 +149,45 @@ void ComponentTextModifier::reactivateChangeSignals()
{ {
m_originalModifier->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) void ModelToTextMerger::propertiesRemoved(const QList<AbstractProperty>& propertyList)
{ {
foreach (const AbstractProperty &property, 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)); schedule(new RemovePropertyRewriteAction(property));
}
} }
} }

View File

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

View File

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

View File

@@ -173,14 +173,27 @@ void RewriterView::propertiesAboutToBeRemoved(const QList<AbstractProperty> &pro
if (textToModelMerger()->isActive()) if (textToModelMerger()->isActive())
return; return;
for (const AbstractProperty &property : propertyList) {
if (!property.isDefaultProperty())
continue;
foreach (const AbstractProperty &property, propertyList) { if (!m_removeDefaultPropertyTransaction.isValid()) {
if (property.isDefaultProperty() && property.isNodeListProperty()) { m_removeDefaultPropertyTransaction = beginRewriterTransaction(
m_removeDefaultPropertyTransaction = beginRewriterTransaction(QByteArrayLiteral("RewriterView::propertiesAboutToBeRemoved")); QByteArrayLiteral("RewriterView::propertiesAboutToBeRemoved"));
}
foreach (const ModelNode &node, property.toNodeListProperty().toModelNodeList()) { if (property.isNodeListProperty()) {
modelToTextMerger()->nodeRemoved(node, property.toNodeAbstractProperty(), AbstractView::NoAdditionalChanges); 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 "generateresource.h"
#include "generatecmakelists.h" #include "generatecmakelists.h"
#include "nodeinstanceview.h" #include "nodeinstanceview.h"
#include "gestures.h"
#include <metainfo.h> #include <metainfo.h>
#include <connectionview.h> #include <connectionview.h>
@@ -232,8 +231,6 @@ bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *e
if (QFontDatabase::addApplicationFont(fontPath) < 0) if (QFontDatabase::addApplicationFont(fontPath) < 0)
qCWarning(qmldesignerLog) << "Could not add font " << fontPath << "to font database"; qCWarning(qmldesignerLog) << "Could not add font " << fontPath << "to font database";
TwoFingerSwipe::registerRecognizer();
return true; return true;
} }

View File

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

View File

@@ -177,7 +177,7 @@ public:
QtOptionsPageWidget(); QtOptionsPageWidget();
~QtOptionsPageWidget(); ~QtOptionsPageWidget();
static void linkWithQt(); static bool linkWithQt();
private: private:
void apply() final; void apply() final;
@@ -857,7 +857,16 @@ void QtOptionsPageWidget::setupLinkWithQtButton()
QString tip; QString tip;
canLinkWithQt(&tip); canLinkWithQt(&tip);
m_ui.linkWithQtButton->setToolTip(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() void QtOptionsPageWidget::updateCurrentQtName()
@@ -950,7 +959,7 @@ static FilePath defaultQtInstallationPath()
return FileUtils::homePath() / "Qt"; return FileUtils::homePath() / "Qt";
} }
void QtOptionsPageWidget::linkWithQt() bool QtOptionsPageWidget::linkWithQt()
{ {
const QString title = tr("Choose Qt Installation"); const QString title = tr("Choose Qt Installation");
const QString restartText = tr("The change will take effect after restart."); const QString restartText = tr("The change will take effect after restart.");
@@ -1019,8 +1028,9 @@ void QtOptionsPageWidget::linkWithQt()
} }
if (askForRestart) { if (askForRestart) {
Core::RestartDialog restartDialog(Core::ICore::dialogParent(), restartText); Core::RestartDialog restartDialog(Core::ICore::dialogParent(), restartText);
restartDialog.exec(); return restartDialog.exec() == QDialog::Accepted;
} }
return false;
} }
// QtOptionsPage // QtOptionsPage

View File

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

View File

@@ -417,6 +417,10 @@ bool FontSettings::loadColorScheme(const QString &fileName,
foreach (const FormatDescription &desc, descriptions) { foreach (const FormatDescription &desc, descriptions) {
const TextStyle id = desc.id(); const TextStyle id = desc.id();
if (!m_scheme.contains(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; Format format;
const Format &descFormat = desc.format(); const Format &descFormat = desc.format();
// Default fallback for background and foreground is C_TEXT, which is set through // 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, void TextDocument::cleanWhitespace(QTextCursor &cursor, bool inEntireDocument,
bool cleanIndentation) 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()); auto documentLayout = qobject_cast<TextDocumentLayout*>(d->m_document.documentLayout());
Q_ASSERT(cursor.visualNavigation() == false); Q_ASSERT(cursor.visualNavigation() == false);
@@ -862,7 +862,7 @@ void TextDocument::cleanWhitespace(QTextCursor &cursor, bool inEntireDocument,
foreach (block, blocks) { foreach (block, blocks) {
QString blockText = block.text(); QString blockText = block.text();
if (d->m_storageSettings.removeTrailingWhitespace(fileName)) if (removeTrailingWhitespace)
TabSettings::removeTrailingWhitespace(cursor, block); TabSettings::removeTrailingWhitespace(cursor, block);
const int indent = indentations[block.blockNumber()]; const int indent = indentations[block.blockNumber()];

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -214,7 +214,7 @@ def verifyBuildAndRun():
appOutput = logApplicationOutput() appOutput = logApplicationOutput()
if appOutput: if appOutput:
test.verify((re.search(".* exited with code \d+", str(appOutput)) or 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)), re.search('[Ss]tarting.*', str(appOutput)),
"Verifying if built app started and closed successfully.") "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) itemObject = waitForObjectItem(objectMap.realName(menuObject), item)
waitFor("itemObject.enabled", 2000) waitFor("itemObject.enabled", 2000)
activateItem(itemObject) activateItem(itemObject)
numberedPrefix = "(&\\d \| )?" numberedPrefix = "%d | "
for subItem in subItems: for subItem in subItems:
# we might have numbered sub items (e.g. "Recent Files") - these have this special prefix # we might have numbered sub items (e.g. "Recent Files") - these have this special prefix
if subItem.startswith(numberedPrefix): if subItem.startswith(numberedPrefix):
# TODO: Find fix for Qt 6
actions = sub.actions()
triggered = False triggered = False
for i in range(actions.count()): for i in range(1, 10):
current = actions.at(i) try:
nonPrefix = subItem[len(numberedPrefix):] itemObject = waitForObjectItem(itemObject, subItem % i, 1000)
matcher = re.match("%s(.*)" % numberedPrefix, str(current.text))
if matcher and matcher.group(2) == nonPrefix:
itemObject = current
activateItem(itemObject) activateItem(itemObject)
triggered = True triggered = True
break break
except:
continue
if not triggered: if not triggered:
test.fail("Could not trigger '%s' - item missing or code wrong?" % subItem, test.fail("Could not trigger '%s' - item missing or code wrong?" % subItem,
"Function arguments: '%s', '%s', %s" % (menu, item, str(subItems))) "Function arguments: '%s', '%s', %s" % (menu, item, str(subItems)))

View File

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