diff options
author | Eike Ziller <eike.ziller@qt.io> | 2020-03-04 08:15:50 +0100 |
---|---|---|
committer | Eike Ziller <eike.ziller@qt.io> | 2020-03-04 08:15:50 +0100 |
commit | 995ba78fae1faafdf76bf1449a593342896a4845 (patch) | |
tree | 5ebec6505595d0c28d3a0374abb1310efca003dc /src/plugins | |
parent | 3bb44dc1c34e27e83790bfbcf219d24424f939ee (diff) | |
parent | 6959618d7b2d9efc8f5f668489523d1833d4b396 (diff) |
Merge remote-tracking branch 'origin/4.12'
Conflicts:
src/plugins/cmakeprojectmanager/tealeafreader.cpp
src/plugins/cmakeprojectmanager/tealeafreader.h
src/plugins/projectexplorer/miniprojecttargetselector.cpp
Change-Id: I88d85be3903f57a55fddb7901e771a4822db1b85
Diffstat (limited to 'src/plugins')
210 files changed, 1864 insertions, 718 deletions
diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index f18739e2ceb..9daf1d0bf21 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -100,6 +100,7 @@ namespace { const QLatin1String SettingsGroup("AndroidConfigurations"); const QLatin1String SDKLocationKey("SDKLocation"); + const QLatin1String CustomNdkLocationsKey("CustomNdkLocations"); const QLatin1String SdkFullyConfiguredKey("AllEssentialsInstalled"); const QLatin1String SDKManagerToolArgsKey("SDKManagerToolArgs"); const QLatin1String OpenJDKLocationKey("OpenJDKLocation"); @@ -235,6 +236,7 @@ void AndroidConfig::load(const QSettings &settings) // user settings m_partitionSize = settings.value(PartitionSizeKey, 1024).toInt(); m_sdkLocation = FilePath::fromString(settings.value(SDKLocationKey).toString()); + m_customNdkList = settings.value(CustomNdkLocationsKey).toStringList(); m_sdkManagerToolArgs = settings.value(SDKManagerToolArgsKey).toStringList(); m_openJDKLocation = FilePath::fromString(settings.value(OpenJDKLocationKey).toString()); m_keystoreLocation = FilePath::fromString(settings.value(KeystoreLocationKey).toString()); @@ -246,12 +248,14 @@ void AndroidConfig::load(const QSettings &settings) && settings.value(changeTimeStamp).toInt() != QFileInfo(sdkSettingsFileName()).lastModified().toMSecsSinceEpoch() / 1000) { // persisten settings m_sdkLocation = FilePath::fromString(reader.restoreValue(SDKLocationKey, m_sdkLocation.toString()).toString()); + m_customNdkList = reader.restoreValue(CustomNdkLocationsKey).toStringList(); m_sdkManagerToolArgs = reader.restoreValue(SDKManagerToolArgsKey, m_sdkManagerToolArgs).toStringList(); m_openJDKLocation = FilePath::fromString(reader.restoreValue(OpenJDKLocationKey, m_openJDKLocation.toString()).toString()); m_automaticKitCreation = reader.restoreValue(AutomaticKitCreationKey, m_automaticKitCreation).toBool(); m_sdkFullyConfigured = reader.restoreValue(SdkFullyConfiguredKey, m_sdkFullyConfigured).toBool(); // persistent settings } + m_customNdkList.removeAll(""); parseDependenciesJson(); } @@ -263,6 +267,7 @@ void AndroidConfig::save(QSettings &settings) const // user settings settings.setValue(SDKLocationKey, m_sdkLocation.toString()); + settings.setValue(CustomNdkLocationsKey, m_customNdkList); settings.setValue(SDKManagerToolArgsKey, m_sdkManagerToolArgs); settings.setValue(OpenJDKLocationKey, m_openJDKLocation.toString()); settings.setValue(KeystoreLocationKey, m_keystoreLocation.toString()); @@ -353,6 +358,22 @@ QVector<int> AndroidConfig::availableNdkPlatforms(const BaseQtVersion *qtVersion return availableNdkPlatforms; } +QStringList AndroidConfig::getCustomNdkList() const +{ + return m_customNdkList; +} + +void AndroidConfig::addCustomNdk(const QString &customNdk) +{ + if (!m_customNdkList.contains(customNdk)) + m_customNdkList.append(customNdk); +} + +void AndroidConfig::removeCustomNdk(const QString &customNdk) +{ + m_customNdkList.removeAll(customNdk); +} + QStringList AndroidConfig::apiLevelNamesFor(const SdkPlatformList &platforms) { return Utils::transform(platforms, AndroidConfig::apiLevelNameFor); @@ -415,9 +436,9 @@ FilePath AndroidConfig::aaptToolPath() const return aaptToolPath.pathAppended(toolPath); } -FilePath AndroidConfig::toolchainPath(const BaseQtVersion *qtVersion) const +FilePath AndroidConfig::toolchainPathFromNdk(const Utils::FilePath &ndkLocation) const { - const FilePath toolchainPath = ndkLocation(qtVersion).pathAppended("toolchains/llvm/prebuilt/"); + const FilePath toolchainPath = ndkLocation.pathAppended("toolchains/llvm/prebuilt/"); // detect toolchain host QStringList hostPatterns; @@ -443,23 +464,41 @@ FilePath AndroidConfig::toolchainPath(const BaseQtVersion *qtVersion) const return {}; } -FilePath AndroidConfig::clangPath(const BaseQtVersion *qtVersion) const +FilePath AndroidConfig::toolchainPath(const BaseQtVersion *qtVersion) const +{ + return toolchainPathFromNdk(ndkLocation(qtVersion)); +} + +FilePath AndroidConfig::clangPathFromNdk(const Utils::FilePath &ndkLocation) const { - const FilePath path = toolchainPath(qtVersion); + const FilePath path = toolchainPathFromNdk(ndkLocation); if (path.isEmpty()) return {}; return path.pathAppended(HostOsInfo::withExecutableSuffix("bin/clang")); } +FilePath AndroidConfig::clangPath(const BaseQtVersion *qtVersion) const +{ + return clangPathFromNdk(ndkLocation(qtVersion)); +} + FilePath AndroidConfig::gdbPath(const ProjectExplorer::Abi &abi, const BaseQtVersion *qtVersion) const { - const FilePath path = ndkLocation(qtVersion).pathAppended( - QString("prebuilt/%1/bin/gdb%2").arg(toolchainHost(qtVersion), QTC_HOST_EXE_SUFFIX)); + return gdbPathFromNdk(abi, ndkLocation(qtVersion)); +} + +FilePath AndroidConfig::gdbPathFromNdk(const Abi &abi, const FilePath &ndkLocation) const +{ + const FilePath path = ndkLocation.pathAppended( + QString("prebuilt/%1/bin/gdb%2").arg(toolchainHostFromNdk(ndkLocation), QTC_HOST_EXE_SUFFIX)); if (path.exists()) return path; // fallback for old NDKs (e.g. 10e) - return ndkLocation(qtVersion).pathAppended(QString("toolchains/%1-4.9/prebuilt/%2/bin/%3-gdb%4") - .arg(toolchainPrefix(abi), toolchainHost(qtVersion), toolsPrefix(abi), QTC_HOST_EXE_SUFFIX)); + return ndkLocation.pathAppended(QString("toolchains/%1-4.9/prebuilt/%2/bin/%3-gdb%4") + .arg(toolchainPrefix(abi), + toolchainHostFromNdk(ndkLocation), + toolsPrefix(abi), + QTC_HOST_EXE_SUFFIX)); } FilePath AndroidConfig::makePath(const BaseQtVersion *qtVersion) const @@ -733,6 +772,16 @@ bool AndroidConfig::useNativeUiTools() const return !version.isNull() && version <= QVersionNumber(25, 3 ,0); } +bool AndroidConfig::isValidNdk(const QString &ndkLocation) const +{ + auto ndkPath = Utils::FilePath::fromUserInput(ndkLocation); + const Utils::FilePath ndkPlatformsDir = ndkPath.pathAppended("platforms"); + + return ndkPath.exists() && ndkPath.pathAppended("toolchains").exists() + && ndkPlatformsDir.exists() && !ndkPlatformsDir.toString().contains(' ') + && !ndkVersion(ndkPath).isNull(); +} + QString AndroidConfig::bestNdkPlatformMatch(int target, const BaseQtVersion *qtVersion) const { target = std::max(AndroidManager::apiLevelRange().first, target); @@ -1076,10 +1125,53 @@ void AndroidConfigurations::registerNewToolChains() const QList<ToolChain *> existingAndroidToolChains = ToolChainManager::toolChains(Utils::equal(&ToolChain::typeId, Core::Id(Constants::ANDROID_TOOLCHAIN_TYPEID))); - const QList<ToolChain *> newToolchains - = AndroidToolChainFactory::autodetectToolChainsForNdk(existingAndroidToolChains); + QList<ToolChain *> newToolchains = AndroidToolChainFactory::autodetectToolChains( + existingAndroidToolChains); + foreach (ToolChain *tc, newToolchains) ToolChainManager::registerToolChain(tc); + + registerCustomToolChainsAndDebuggers(); +} + +void AndroidConfigurations::registerCustomToolChainsAndDebuggers() +{ + const QList<ToolChain *> existingAndroidToolChains = ToolChainManager::toolChains( + Utils::equal(&ToolChain::typeId, Core::Id(Constants::ANDROID_TOOLCHAIN_TYPEID))); + QList<FilePath> customNdks = Utils::transform(currentConfig().getCustomNdkList(), + FilePath::fromString); + QList<ToolChain *> customToolchains + = AndroidToolChainFactory::autodetectToolChainsFromNdks(existingAndroidToolChains, + customNdks, + true); + for (ToolChain *tc : customToolchains) { + ToolChainManager::registerToolChain(tc); + + const FilePath ndk = static_cast<AndroidToolChain *>(tc)->ndkLocation(); + const FilePath command = AndroidConfigurations::currentConfig() + .gdbPathFromNdk(tc->targetAbi(), ndk); + + const Debugger::DebuggerItem *existing = Debugger::DebuggerItemManager::findByCommand( + command); + QString abiStr + = static_cast<AndroidToolChain *>(tc)->platformLinkerFlags().at(1).split('-').first(); + Abi abi = Abi::abiFromTargetTriplet(abiStr); + if (existing && existing->abis().contains(abi)) + continue; + + Debugger::DebuggerItem debugger; + debugger.setCommand(command); + debugger.setEngineType(Debugger::GdbEngineType); + debugger.setUnexpandedDisplayName( + AndroidConfigurations::tr("Custom Android Debugger (%1, NDK %2)") + .arg(abiStr, + AndroidConfigurations::currentConfig().ndkVersion(ndk).toString())); + debugger.setAutoDetected(true); + debugger.setAbi(abi); + debugger.reinitializeFromFile(); + + Debugger::DebuggerItemManager::registerDebugger(debugger); + } } void AndroidConfigurations::removeOldToolChains() @@ -1090,22 +1182,75 @@ void AndroidConfigurations::removeOldToolChains() } } -static QVariant findOrRegisterDebugger(ToolChain *tc, const BaseQtVersion *qtVersion) +void AndroidConfigurations::removeUnusedDebuggers() { - const FilePath command = AndroidConfigurations::currentConfig().gdbPath(tc->targetAbi(), qtVersion); + QList<FilePath> uniqueNdks; + const QList<QtSupport::BaseQtVersion *> qtVersions + = QtSupport::QtVersionManager::versions([](const QtSupport::BaseQtVersion *v) { + return v->type() == Constants::ANDROIDQT; + }); + + for (const QtSupport::BaseQtVersion *qt : qtVersions) { + FilePath ndkLocation = currentConfig().ndkLocation(qt); + if (!uniqueNdks.contains(ndkLocation)) + uniqueNdks.append(ndkLocation); + } + + uniqueNdks.append(Utils::transform(currentConfig().getCustomNdkList(), FilePath::fromString)); + + const QList<Debugger::DebuggerItem> allDebuggers = Debugger::DebuggerItemManager::debuggers(); + for (const Debugger::DebuggerItem &debugger : allDebuggers) { + if (!debugger.displayName().contains("Android")) + continue; + + bool isChildOfNdk = false; + for (const FilePath &path : uniqueNdks) { + if (debugger.command().isChildOf(path)) { + isChildOfNdk = true; + break; + } + } + + if (!isChildOfNdk && debugger.isAutoDetected()) + Debugger::DebuggerItemManager::deregisterDebugger(debugger.id()); + } +} + +static QVariant findOrRegisterDebugger(ToolChain *tc, + const QStringList &abisList, + const BaseQtVersion *qtVersion) +{ + const FilePath command = AndroidConfigurations::currentConfig().gdbPath(tc->targetAbi(), + qtVersion); // check if the debugger is already registered, but ignoring the display name const Debugger::DebuggerItem *existing = Debugger::DebuggerItemManager::findByCommand(command); + + QList<Abi> abis = Utils::transform(abisList, Abi::abiFromTargetTriplet); + + auto containsAbis = [abis](const Abis &secondAbis) { + for (const Abi &abi : secondAbis) { + if (!abis.contains(abi)) + return false; + } + return true; + }; + if (existing && existing->engineType() == Debugger::GdbEngineType && existing->isAutoDetected() - && existing->abis() == Abis{tc->targetAbi()}) + && containsAbis(existing->abis())) { + // update debugger info with new return existing->id(); + } + // debugger not found, register a new one Debugger::DebuggerItem debugger; debugger.setCommand(command); debugger.setEngineType(Debugger::GdbEngineType); debugger.setUnexpandedDisplayName( - AndroidConfigurations::tr("Android Debugger for %1").arg(tc->displayName())); + AndroidConfigurations::tr("Android Debugger (%1, NDK %2)") + .arg(abisList.join(", "), + AndroidConfigurations::currentConfig().ndkVersion(qtVersion).toString())); debugger.setAutoDetected(true); - debugger.setAbi(tc->targetAbi()); + debugger.setAbis(abis.toVector()); debugger.reinitializeFromFile(); return Debugger::DebuggerItemManager::registerDebugger(debugger); } @@ -1136,6 +1281,8 @@ void AndroidConfigurations::updateAutomaticKitList() return false; }); + removeUnusedDebuggers(); + QHash<Abi, QList<const QtSupport::BaseQtVersion *> > qtVersionsForArch; const QList<QtSupport::BaseQtVersion *> qtVersions = QtSupport::QtVersionManager::versions([](const QtSupport::BaseQtVersion *v) { @@ -1199,10 +1346,11 @@ void AndroidConfigurations::updateAutomaticKitList() ToolChainKitAspect::setToolChain(k, tc); QtSupport::QtKitAspect::setQtVersion(k, qt); DeviceKitAspect::setDevice(k, device); - Debugger::DebuggerKitAspect::setDebugger(k, findOrRegisterDebugger(tc, QtKitAspect::qtVersion(k))); + QStringList abis = static_cast<const AndroidQtVersion *>(qt)->androidAbis(); + Debugger::DebuggerKitAspect::setDebugger(k, findOrRegisterDebugger(tc, abis, QtKitAspect::qtVersion(k))); k->makeSticky(); k->setUnexpandedDisplayName(tr("Android for %1 (Clang %2)") - .arg(static_cast<const AndroidQtVersion *>(qt)->androidAbis().join(",")) + .arg(abis.join(",")) .arg(qt->displayName())); k->setValueSilently(Constants::ANDROID_KIT_NDK, currentConfig().ndkLocation(qt).toString()); k->setValueSilently(Constants::ANDROID_KIT_SDK, currentConfig().sdkLocation().toString()); diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index 4a4217e3a2c..f793ed78c3f 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -160,9 +160,12 @@ public: Utils::FilePath aaptToolPath() const; Utils::FilePath toolchainPath(const QtSupport::BaseQtVersion *qtVersion) const; + Utils::FilePath toolchainPathFromNdk(const Utils::FilePath &ndkLocation) const; Utils::FilePath clangPath(const QtSupport::BaseQtVersion *qtVersion) const; + Utils::FilePath clangPathFromNdk(const Utils::FilePath &ndkLocation) const; Utils::FilePath gdbPath(const ProjectExplorer::Abi &abi, const QtSupport::BaseQtVersion *qtVersion) const; + Utils::FilePath gdbPathFromNdk(const ProjectExplorer::Abi &abi, const Utils::FilePath &ndkLocation) const; Utils::FilePath makePath(const QtSupport::BaseQtVersion *qtVersion) const; Utils::FilePath makePathFromNdk(const Utils::FilePath &ndkLocation) const; @@ -188,6 +191,11 @@ public: bool sdkFullyConfigured() const { return m_sdkFullyConfigured; }; void setSdkFullyConfigured(bool allEssentialsInstalled) { m_sdkFullyConfigured = allEssentialsInstalled; }; + bool isValidNdk(const QString &ndkLocation) const; + QStringList getCustomNdkList() const; + void addCustomNdk(const QString &customNdk); + void removeCustomNdk(const QString &customNdk); + private: static QString getDeviceProperty(const Utils::FilePath &adbToolPath, const QString &device, const QString &property); @@ -216,6 +224,7 @@ private: QStringList m_commonEssentialPkgs; SdkForQtVersions m_defaultSdkDepends; QList<SdkForQtVersions> m_specificQtVersions; + QStringList m_customNdkList; bool m_sdkFullyConfigured = false; //caches @@ -237,6 +246,8 @@ public: static QString defaultDevice(ProjectExplorer::Project *project, const QString &abi); // serial number or avd name static void clearDefaultDevices(ProjectExplorer::Project *project); static void registerNewToolChains(); + static void registerCustomToolChainsAndDebuggers(); + static void removeUnusedDebuggers(); static void removeOldToolChains(); static void updateAutomaticKitList(); static bool force32bitEmulator(); diff --git a/src/plugins/android/androidmanifesteditorwidget.cpp b/src/plugins/android/androidmanifesteditorwidget.cpp index bc80a84ba75..2eee4515e07 100644 --- a/src/plugins/android/androidmanifesteditorwidget.cpp +++ b/src/plugins/android/androidmanifesteditorwidget.cpp @@ -240,6 +240,18 @@ void AndroidManifestEditorWidget::initializePage() m_targetLineEdit->installEventFilter(this); formLayout->addRow(tr("Run:"), m_targetLineEdit); + m_styleExtractMethod = new QComboBox(applicationGroupBox); + formLayout->addRow(tr("Style extraction:"), m_styleExtractMethod); + const QList<QStringList> styleMethodsMap = { + {"default", "In most cases this will be the same as \"full\", but it can also be something else if needed, e.g. for compatibility reasons."}, + {"full", "Useful for Qt Widgets & Qt Quick Controls 1 apps."}, + {"minimal", "Useful for Qt Quick Controls 2 apps, it is much faster than \"full\"."}, + {"none", "Useful for apps that don't use Qt Widgets, Qt Quick Controls 1 or Qt Quick Controls 2."}}; + for (int i = 0; i <styleMethodsMap.size(); ++i) { + m_styleExtractMethod->addItem(styleMethodsMap.at(i).first()); + m_styleExtractMethod->setItemData(i, styleMethodsMap.at(i).at(1), Qt::ToolTipRole); + } + auto iconLayout = new QHBoxLayout(); createDPIButton(iconLayout, @@ -297,6 +309,9 @@ void AndroidManifestEditorWidget::initializePage() this, setDirtyFunc); connect(m_targetLineEdit, &QComboBox::currentTextChanged, this, setDirtyFunc); + connect(m_styleExtractMethod, + QOverload<int>::of(&QComboBox::currentIndexChanged), + this, setDirtyFunc); connect(m_masterIconButton, &QAbstractButton::clicked, this, &AndroidManifestEditorWidget::setMasterIcon); @@ -331,17 +346,6 @@ void AndroidManifestEditorWidget::initializePage() m_defaultFeaturesCheckBox->setText(tr("Include default features for Qt modules.")); layout->addWidget(m_defaultFeaturesCheckBox, 1, 0); - m_permissionsModel = new PermissionsModel(this); - - m_permissionsListView = new QListView(permissionsGroupBox); - m_permissionsListView->setModel(m_permissionsModel); - m_permissionsListView->setMinimumSize(QSize(0, 200)); - layout->addWidget(m_permissionsListView, 2, 0, 3, 1); - - m_removePermissionButton = new QPushButton(permissionsGroupBox); - m_removePermissionButton->setText(tr("Remove")); - layout->addWidget(m_removePermissionButton, 2, 1); - m_permissionsComboBox = new QComboBox(permissionsGroupBox); m_permissionsComboBox->insertItems(0, QStringList() << QLatin1String("android.permission.ACCESS_CHECKIN_PROPERTIES") @@ -476,11 +480,22 @@ void AndroidManifestEditorWidget::initializePage() << QLatin1String("android.permission.WRITE_USER_DICTIONARY") ); m_permissionsComboBox->setEditable(true); - layout->addWidget(m_permissionsComboBox, 6, 0); + layout->addWidget(m_permissionsComboBox, 2, 0); m_addPermissionButton = new QPushButton(permissionsGroupBox); m_addPermissionButton->setText(tr("Add")); - layout->addWidget(m_addPermissionButton, 6, 1); + layout->addWidget(m_addPermissionButton, 2, 1); + + m_permissionsModel = new PermissionsModel(this); + + m_permissionsListView = new QListView(permissionsGroupBox); + m_permissionsListView->setModel(m_permissionsModel); + m_permissionsListView->setMinimumSize(QSize(0, 200)); + layout->addWidget(m_permissionsListView, 3, 0, 3, 1); + + m_removePermissionButton = new QPushButton(permissionsGroupBox); + m_removePermissionButton->setText(tr("Remove")); + layout->addWidget(m_removePermissionButton, 3, 1); permissionsGroupBox->setLayout(layout); @@ -804,11 +819,21 @@ void AndroidManifestEditorWidget::syncToWidgets(const QDomDocument &doc) QDomElement metadataElem = activityElem.firstChildElement(QLatin1String("meta-data")); + const int parseItemsCount = 2; + int counter = 0; while (!metadataElem.isNull()) { if (metadataElem.attribute(QLatin1String("android:name")) == QLatin1String("android.app.lib_name")) { m_targetLineEdit->setEditText(metadataElem.attribute(QLatin1String("android:value"))); - break; + ++counter; + } else if (metadataElem.attribute(QLatin1String("android:name")) + == QLatin1String("android.app.extract_android_style")) { + m_styleExtractMethod->setCurrentText( + metadataElem.attribute(QLatin1String("android:value"))); + ++counter; } + + if (counter == parseItemsCount) + break; metadataElem = metadataElem.nextSiblingElement(QLatin1String("meta-data")); } @@ -1093,15 +1118,24 @@ bool AndroidManifestEditorWidget::parseMetaData(QXmlStreamReader &reader, QXmlSt { Q_ASSERT(reader.isStartElement()); - bool found = false; + const int parseItemsCount = 2; + int counter = 0; QXmlStreamAttributes attributes = reader.attributes(); QXmlStreamAttributes result; + QStringList keys; + QStringList values; if (attributes.value(QLatin1String("android:name")) == QLatin1String("android.app.lib_name")) { - QStringList keys = QStringList("android:value"); - QStringList values = QStringList(m_targetLineEdit->currentText()); + keys = QStringList("android:value"); + values = QStringList(m_targetLineEdit->currentText()); + result = modifyXmlStreamAttributes(attributes, keys, values); + ++counter; + } else if (attributes.value(QLatin1String("android:name")) + == QLatin1String("android.app.extract_android_style")) { + keys = QStringList("android:value"); + values = QStringList(m_styleExtractMethod->currentText()); result = modifyXmlStreamAttributes(attributes, keys, values); - found = true; + ++counter; } else { result = attributes; } @@ -1114,7 +1148,7 @@ bool AndroidManifestEditorWidget::parseMetaData(QXmlStreamReader &reader, QXmlSt while (!reader.atEnd()) { if (reader.isEndElement()) { writer.writeCurrentToken(reader); - return found; + return counter == parseItemsCount; } else if (reader.isStartElement()) { parseUnknownElement(reader, writer); } else { @@ -1122,7 +1156,7 @@ bool AndroidManifestEditorWidget::parseMetaData(QXmlStreamReader &reader, QXmlSt } reader.readNext(); } - return found; // should never be reached + return counter == parseItemsCount; // should never be reached } void AndroidManifestEditorWidget::parseUsesSdk(QXmlStreamReader &reader, QXmlStreamWriter & writer) diff --git a/src/plugins/android/androidmanifesteditorwidget.h b/src/plugins/android/androidmanifesteditorwidget.h index efbc2b529a4..8e38773cd69 100644 --- a/src/plugins/android/androidmanifesteditorwidget.h +++ b/src/plugins/android/androidmanifesteditorwidget.h @@ -189,6 +189,7 @@ private: QLineEdit *m_appNameLineEdit; QLineEdit *m_activityNameLineEdit; QComboBox *m_targetLineEdit; + QComboBox *m_styleExtractMethod; QToolButton *m_masterIconButton; QToolButton *m_lIconButton; QToolButton *m_lIconClearButton; diff --git a/src/plugins/android/androidplugin.cpp b/src/plugins/android/androidplugin.cpp index 1fcdd9bd720..2e02d516492 100644 --- a/src/plugins/android/androidplugin.cpp +++ b/src/plugins/android/androidplugin.cpp @@ -177,8 +177,8 @@ void AndroidPlugin::kitsRestored() &AndroidPlugin::askUserAboutAndroidSetup, Qt::QueuedConnection); } - AndroidConfigurations::updateAutomaticKitList(); AndroidConfigurations::registerNewToolChains(); + AndroidConfigurations::updateAutomaticKitList(); connect(QtSupport::QtVersionManager::instance(), &QtSupport::QtVersionManager::qtVersionsChanged, AndroidConfigurations::instance(), &AndroidConfigurations::updateAutomaticKitList); disconnect(KitManager::instance(), &KitManager::kitsLoaded, diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index 5cb44faeb5d..42511b893c3 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -133,6 +133,7 @@ private: bool sdkToolsOk() const; Utils::FilePath getDefaultSdkPath(); void showEvent(QShowEvent *event) override; + void addCustomNdkItem(); Ui_AndroidSettingsWidget *m_ui; AndroidSdkManagerWidget *m_sdkManagerWidget = nullptr; @@ -342,7 +343,7 @@ void AndroidSettingsWidget::showEvent(QShowEvent *event) // Reloading SDK packages (force) is still synchronous. Use zero timer // to let settings dialog open first. QTimer::singleShot(0, std::bind(&AndroidSdkManager::reloadPackages, - m_sdkManager.get(), true)); + m_sdkManager.get(), false)); m_isInitialReloadDone = true; } } @@ -352,6 +353,22 @@ void AndroidSettingsWidget::updateNdkList() m_ui->ndkListComboBox->clear(); for (const Ndk *ndk : m_sdkManager->installedNdkPackages()) m_ui->ndkListComboBox->addItem(ndk->installedLocation().toString()); + + for (const QString &ndk : m_androidConfig.getCustomNdkList()) { + if (m_androidConfig.isValidNdk(ndk)) + m_ui->ndkListComboBox->addItem(ndk); + else + m_androidConfig.removeCustomNdk(ndk); + } +} + +void AndroidSettingsWidget::addCustomNdkItem() +{ + const QString ndkPath = QDir::toNativeSeparators(m_ui->customNdkPathChooser->rawPath()); + m_androidConfig.addCustomNdk(ndkPath); + if (m_ui->ndkListComboBox->findData(ndkPath) == -1) + m_ui->ndkListComboBox->addItem(ndkPath); + m_ui->ndkListComboBox->setCurrentText(ndkPath); } AndroidSettingsWidget::AndroidSettingsWidget() @@ -435,8 +452,23 @@ AndroidSettingsWidget::AndroidSettingsWidget() connect(m_ui->SDKLocationPathChooser, &Utils::PathChooser::rawPathChanged, this, &AndroidSettingsWidget::onSdkPathChanged); - connect(m_ui->ndkListComboBox, QOverload<const QString &>::of(&QComboBox::currentIndexChanged), - [this](const QString) { validateNdk(); }); + connect(m_ui->ndkListComboBox, + QOverload<const QString &>::of(&QComboBox::currentIndexChanged), + [this](const QString &ndk) { + validateNdk(); + m_ui->removeCustomNdkButton->setEnabled(m_androidConfig.getCustomNdkList().contains(ndk)); + }); + connect(m_ui->customNdkPathChooser, &Utils::PathChooser::rawPathChanged, this, [this]() { + const QString ndkPath = m_ui->customNdkPathChooser->rawPath(); + m_ui->addCustomNdkButton->setEnabled(m_androidConfig.isValidNdk(ndkPath)); + }); + connect(m_ui->addCustomNdkButton, &QPushButton::clicked, this, + &AndroidSettingsWidget::addCustomNdkItem); + connect(m_ui->removeCustomNdkButton, &QPushButton::clicked, this, [this]() { + m_androidConfig.removeCustomNdk(m_ui->ndkListComboBox->currentText()); + m_ui->ndkListComboBox->removeItem(m_ui->ndkListComboBox->currentIndex()); + }); + connect(&m_virtualDevicesWatcher, &QFutureWatcherBase::finished, this, &AndroidSettingsWidget::updateAvds); connect(m_ui->AVDRefreshPushButton, &QAbstractButton::clicked, diff --git a/src/plugins/android/androidsettingswidget.ui b/src/plugins/android/androidsettingswidget.ui index 5d149dddcf5..6d8272b7dfa 100644 --- a/src/plugins/android/androidsettingswidget.ui +++ b/src/plugins/android/androidsettingswidget.ui @@ -93,7 +93,7 @@ <item row="0" column="0"> <widget class="QLabel" name="SDKLocationLabel"> <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> @@ -106,21 +106,24 @@ </property> </widget> </item> - <item row="0" column="4"> - <widget class="QToolButton" name="downloadSDKToolButton"> - <property name="toolTip"> - <string>Download Android SDK</string> + <item row="1" column="0"> + <widget class="QLabel" name="customNdkLabel"> + <property name="text"> + <string>Add custom NDK:</string> </property> </widget> </item> - <item row="1" column="0"> - <widget class="QLabel" name="ndkComboBoxLabel"> + <item row="1" column="6"> + <widget class="QToolButton" name="downloadNDKToolButton"> <property name="text"> - <string>Android NDK list:</string> + <string/> </property> </widget> </item> - <item row="0" column="3"> + <item row="0" column="1" colspan="4"> + <widget class="Utils::PathChooser" name="SDKLocationPathChooser" native="true"/> + </item> + <item row="0" column="5"> <widget class="QToolButton" name="sdkToolsAutoDownloadButton"> <property name="toolTip"> <string>Automatically download Android SDK Tools to selected location.</string> @@ -130,29 +133,74 @@ </property> </widget> </item> - <item row="2" column="0" colspan="5"> + <item row="3" column="0" colspan="7"> <widget class="Utils::DetailsWidget" name="androidDetailsWidget" native="true"/> </item> - <item row="1" column="4"> - <widget class="QToolButton" name="downloadNDKToolButton"> + <item row="2" column="0"> + <widget class="QLabel" name="ndkComboBoxLabel"> <property name="text"> - <string/> + <string>Android NDK list:</string> </property> </widget> </item> - <item row="0" column="2"> - <widget class="Utils::PathChooser" name="SDKLocationPathChooser" native="true"> + <item row="0" column="6"> + <widget class="QToolButton" name="downloadSDKToolButton"> + <property name="toolTip"> + <string>Download Android SDK</string> + </property> + </widget> + </item> + <item row="1" column="1" colspan="3"> + <widget class="Utils::PathChooser" name="customNdkPathChooser" native="true"> + <property name="minimumSize"> + <size> + <width>20</width> + <height>0</height> + </size> + </property> + </widget> + </item> + <item row="1" column="4"> + <widget class="QPushButton" name="addCustomNdkButton"> + <property name="enabled"> + <bool>false</bool> + </property> <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> + <property name="toolTip"> + <string>Add the selected custom NDK. The toolchains and debuggers will be created automatically.</string> + </property> + <property name="text"> + <string>Add</string> + </property> </widget> </item> - <item row="1" column="2"> + <item row="2" column="1" colspan="3"> <widget class="QComboBox" name="ndkListComboBox"/> </item> + <item row="2" column="4"> + <widget class="QPushButton" name="removeCustomNdkButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Remove the selected custom NDK.</string> + </property> + <property name="text"> + <string>Remove</string> + </property> + </widget> + </item> </layout> </widget> </item> @@ -351,6 +399,10 @@ <extends>QWidget</extends> <header location="global">utils/pathchooser.h</header> <container>1</container> + <slots> + <signal>editingFinished()</signal> + <signal>browsingFinished()</signal> + </slots> </customwidget> <customwidget> <class>Utils::DetailsWidget</class> diff --git a/src/plugins/android/androidtoolchain.cpp b/src/plugins/android/androidtoolchain.cpp index 18523300189..84aa82f4c97 100644 --- a/src/plugins/android/androidtoolchain.cpp +++ b/src/plugins/android/androidtoolchain.cpp @@ -93,14 +93,22 @@ AndroidToolChain::~AndroidToolChain() = default; bool AndroidToolChain::isValid() const { + if (m_ndkLocation.isEmpty()) { + QStringList ndkParts(compilerCommand().toString().split("toolchains/llvm/prebuilt/")); + if (ndkParts.size() > 1) { + QString ndkLocation(ndkParts.first()); + if (ndkLocation.endsWith('/')) + ndkLocation.chop(1); + m_ndkLocation = FilePath::fromString(ndkLocation); + } + } + const bool isChildofNdk = compilerCommand().isChildOf(m_ndkLocation); - // If we're restoring a toolchain we set NDK path ourselves so it's enough to check against SDK const bool isChildofSdk = compilerCommand().isChildOf( AndroidConfigurations::currentConfig().sdkLocation()); return ClangToolChain::isValid() && typeId() == Constants::ANDROID_TOOLCHAIN_TYPEID - && targetAbi().isValid() - && (isChildofNdk || isChildofSdk) + && targetAbi().isValid() && (isChildofNdk || isChildofSdk) && !originalTargetTriple().isEmpty(); } @@ -163,7 +171,7 @@ AndroidToolChainFactory::AndroidToolChainFactory() ToolChainList AndroidToolChainFactory::autoDetect(const ToolChainList &alreadyKnown) { - return autodetectToolChainsForNdk(alreadyKnown); + return autodetectToolChains(alreadyKnown); } static FilePath clangPlusPlusPath(const FilePath &clangPath) @@ -173,7 +181,7 @@ static FilePath clangPlusPlusPath(const FilePath &clangPath) QFileInfo(clangPath.toString()).baseName() + "++")); } -static QList<QtSupport::BaseQtVersion *> androidQtVersionsWithUniqueNdk() +static QList<FilePath> uniqueNdksForCurrentQtVersions() { AndroidConfig config = AndroidConfigurations::currentConfig(); @@ -182,36 +190,40 @@ static QList<QtSupport::BaseQtVersion *> androidQtVersionsWithUniqueNdk() return v->targetDeviceTypes().contains(Android::Constants::ANDROID_DEVICE_TYPE); }); - auto shouldRemove = [config](const QtSupport::BaseQtVersion *first, - const QtSupport::BaseQtVersion *second) { - return config.ndkLocation(first) == config.ndkLocation(second); - }; + QList<FilePath> uniqueNdks; + for (const QtSupport::BaseQtVersion *version : androidQtVersions) { + FilePath ndk = config.ndkLocation(version); + if (!uniqueNdks.contains(ndk)) + uniqueNdks.append(ndk); + } - QList<QtSupport::BaseQtVersion *>::iterator it = std::unique(androidQtVersions.begin(), - androidQtVersions.end(), - shouldRemove); - androidQtVersions.erase(it, androidQtVersions.end()); + return uniqueNdks; +} - return androidQtVersions; +ToolChainList AndroidToolChainFactory::autodetectToolChains(const ToolChainList &alreadyKnown) +{ + const QList<Utils::FilePath> uniqueNdks = uniqueNdksForCurrentQtVersions(); + return autodetectToolChainsFromNdks(alreadyKnown, uniqueNdks); } -ToolChainList AndroidToolChainFactory::autodetectToolChainsForNdk(const ToolChainList &alreadyKnown) +ToolChainList AndroidToolChainFactory::autodetectToolChainsFromNdks( + const ToolChainList &alreadyKnown, + const QList<Utils::FilePath> &ndkLocations, + const bool isCustom) { QList<ToolChain *> result; - const QList<QtSupport::BaseQtVersion *> androidQtVersions = androidQtVersionsWithUniqueNdk(); const AndroidConfig config = AndroidConfigurations::currentConfig(); - for (const QtSupport::BaseQtVersion *qtVersion : androidQtVersions) { - FilePath clangPath = config.clangPath(qtVersion); + for (const Utils::FilePath &ndkLocation : ndkLocations) { + qCDebug(androidTCLog) << "Detecting toolchains from Android NDK:" << ndkLocation; + + FilePath clangPath = config.clangPathFromNdk(ndkLocation); if (!clangPath.exists()) { qCDebug(androidTCLog) << "Clang toolchains detection fails. Can not find Clang" << clangPath; - return result; + continue; } - qCDebug(androidTCLog) << "Detecting toolchains from Android NDK:" - << config.ndkLocation(qtVersion); - for (const Core::Id &lang : LanguageIds) { FilePath compilerCommand = clangPath; if (lang == ProjectExplorer::Constants::CXX_LANGUAGE_ID) @@ -229,10 +241,11 @@ ToolChainList AndroidToolChainFactory::autodetectToolChainsForNdk(const ToolChai const QString target = targetItr.key(); ToolChain *tc = findToolChain(compilerCommand, lang, target, alreadyKnown); - const QString displayName(QString("Android Clang (%1, %2, NDK %3)") + QLatin1String customStr = isCustom ? QLatin1String("Custom ") : QLatin1String(); + const QString displayName(customStr + QString("Android Clang (%1, %2, NDK %3)") .arg(ToolChainManager::displayNameOfLanguageId(lang), AndroidConfig::displayName(abi), - config.ndkVersion(qtVersion).toString())); + config.ndkVersion(ndkLocation).toString())); if (tc) { qCDebug(androidTCLog) << "Tool chain already known" << abi.toString() << lang; // make sure to update the toolchain with current name format @@ -241,7 +254,7 @@ ToolChainList AndroidToolChainFactory::autodetectToolChainsForNdk(const ToolChai } else { qCDebug(androidTCLog) << "New Clang toolchain found" << abi.toString() << lang; auto atc = new AndroidToolChain(); - atc->setNdkLocation(config.ndkLocation(qtVersion)); + atc->setNdkLocation(ndkLocation); atc->setOriginalTargetTriple(target); atc->setLanguage(lang); atc->setTargetAbi(ClangTargets[target]); diff --git a/src/plugins/android/androidtoolchain.h b/src/plugins/android/androidtoolchain.h index 087e488125e..0624892aab8 100644 --- a/src/plugins/android/androidtoolchain.h +++ b/src/plugins/android/androidtoolchain.h @@ -59,7 +59,7 @@ private: friend class AndroidToolChainFactory; - Utils::FilePath m_ndkLocation; + mutable Utils::FilePath m_ndkLocation; }; class AndroidToolChainFactory : public ProjectExplorer::ToolChainFactory @@ -78,7 +78,10 @@ public: QString version; }; - static ToolChainList autodetectToolChainsForNdk(const ToolChainList &alreadyKnown); + static ToolChainList autodetectToolChains(const ToolChainList &alreadyKnown); + static ToolChainList autodetectToolChainsFromNdks(const ToolChainList &alreadyKnown, + const QList<Utils::FilePath> &ndkLocations, + const bool isCustom = false); }; } // namespace Internal diff --git a/src/plugins/android/javaeditor.cpp b/src/plugins/android/javaeditor.cpp index b280977c89f..e984dbcf8ed 100644 --- a/src/plugins/android/javaeditor.cpp +++ b/src/plugins/android/javaeditor.cpp @@ -29,7 +29,6 @@ #include <texteditor/codeassist/keywordscompletionassist.h> #include <coreplugin/editormanager/ieditorfactory.h> -#include <texteditor/normalindenter.h> #include <texteditor/textdocument.h> #include <texteditor/texteditoractionhandler.h> #include <texteditor/texteditorconstants.h> diff --git a/src/plugins/autotest/quick/quicktestvisitors.cpp b/src/plugins/autotest/quick/quicktestvisitors.cpp index 486356f13b2..598b16afec7 100644 --- a/src/plugins/autotest/quick/quicktestvisitors.cpp +++ b/src/plugins/autotest/quick/quicktestvisitors.cpp @@ -33,6 +33,8 @@ #include <utils/algorithm.h> #include <utils/qtcassert.h> +#include <QDebug> + namespace Autotest { namespace Internal { @@ -177,6 +179,11 @@ bool TestQmlVisitor::visit(QmlJS::AST::StringLiteral *ast) return false; } +void TestQmlVisitor::throwRecursionDepthError() +{ + qWarning("Warning: Hit maximum recursion depth while visiting AST in TestQmlVisitor"); +} + /************************************** QuickTestAstVisitor *************************************/ QuickTestAstVisitor::QuickTestAstVisitor(CPlusPlus::Document::Ptr doc, diff --git a/src/plugins/autotest/quick/quicktestvisitors.h b/src/plugins/autotest/quick/quicktestvisitors.h index e4af8661c2f..5aff62f4581 100644 --- a/src/plugins/autotest/quick/quicktestvisitors.h +++ b/src/plugins/autotest/quick/quicktestvisitors.h @@ -65,6 +65,8 @@ public: bool visit(QmlJS::AST::FunctionDeclaration *ast) override; bool visit(QmlJS::AST::StringLiteral *ast) override; + void throwRecursionDepthError() override; + QVector<QuickTestCaseSpec> testCases() const { return m_testCases; } bool isValid() const { return !m_testCases.isEmpty(); } diff --git a/src/plugins/autotoolsprojectmanager/autotoolsbuildsystem.cpp b/src/plugins/autotoolsprojectmanager/autotoolsbuildsystem.cpp index 2345a890768..a6cacabaa26 100644 --- a/src/plugins/autotoolsprojectmanager/autotoolsbuildsystem.cpp +++ b/src/plugins/autotoolsprojectmanager/autotoolsbuildsystem.cpp @@ -110,7 +110,7 @@ void AutotoolsBuildSystem::makefileParsingFinished() m_files.clear(); - QVector<Utils::FilePath> filesToWatch; + QSet<Utils::FilePath> filesToWatch; // Apply sources to m_files, which are returned at AutotoolsBuildSystem::files() const QFileInfo fileInfo = projectFilePath().toFileInfo(); @@ -127,7 +127,7 @@ void AutotoolsBuildSystem::makefileParsingFinished() m_files.append(absMakefile); - filesToWatch.append(Utils::FilePath::fromString(absMakefile)); + filesToWatch.insert(Utils::FilePath::fromString(absMakefile)); } // Add configure.ac file to project and watch for changes. @@ -137,7 +137,7 @@ void AutotoolsBuildSystem::makefileParsingFinished() const QString absConfigureAc = dir.absoluteFilePath(configureAc); m_files.append(absConfigureAc); - filesToWatch.append(Utils::FilePath::fromString(absConfigureAc)); + filesToWatch.insert(Utils::FilePath::fromString(absConfigureAc)); } auto newRoot = std::make_unique<ProjectNode>(project()->projectDirectory()); diff --git a/src/plugins/clangtools/clangtoolruncontrol.cpp b/src/plugins/clangtools/clangtoolruncontrol.cpp index a80acd64719..3932d5b4402 100644 --- a/src/plugins/clangtools/clangtoolruncontrol.cpp +++ b/src/plugins/clangtools/clangtoolruncontrol.cpp @@ -61,6 +61,7 @@ #include <utils/algorithm.h> #include <utils/hostosinfo.h> #include <utils/qtcprocess.h> +#include <utils/stringutils.h> #include <QAction> #include <QLoggingCategory> @@ -344,11 +345,8 @@ void ClangToolRunWorker::stop() reportStopped(); // Print elapsed time since start - const QTime format = QTime(0, 0, 0, 0).addMSecs(m_elapsed.elapsed() + 500); - QString time = format.toString("h:mm:ss"); - if (time.startsWith("0:")) - time.remove(0, 2); // Don't display zero hours - appendMessage(tr("Elapsed time: %1.") .arg(time), NormalMessageFormat); + const QString elapsedTime = Utils::formatElapsedTime(m_elapsed.elapsed()); + appendMessage(elapsedTime, NormalMessageFormat); } void ClangToolRunWorker::analyzeNextFile() diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.cpp b/src/plugins/cmakeprojectmanager/builddirmanager.cpp index d4d90a7a941..75790bee87e 100644 --- a/src/plugins/cmakeprojectmanager/builddirmanager.cpp +++ b/src/plugins/cmakeprojectmanager/builddirmanager.cpp @@ -390,7 +390,7 @@ void BuildDirManager::parse() reparseParameters & REPARSE_FORCE_CONFIGURATION); } -QVector<FilePath> BuildDirManager::takeProjectFilesToWatch() +QSet<FilePath> BuildDirManager::projectFilesToWatch() const { QTC_ASSERT(!m_isHandlingError, return {}); QTC_ASSERT(m_reader, return {}); @@ -398,7 +398,7 @@ QVector<FilePath> BuildDirManager::takeProjectFilesToWatch() Utils::FilePath sourceDir = m_parameters.sourceDirectory; Utils::FilePath buildDir = m_parameters.workDirectory; - return Utils::filtered(m_reader->takeProjectFilesToWatch(), + return Utils::filtered(m_reader->projectFilesToWatch(), [&sourceDir, &buildDir](const Utils::FilePath &p) { return p.isChildOf(sourceDir) diff --git a/src/plugins/cmakeprojectmanager/builddirmanager.h b/src/plugins/cmakeprojectmanager/builddirmanager.h index 00085952a33..3138b24a813 100644 --- a/src/plugins/cmakeprojectmanager/builddirmanager.h +++ b/src/plugins/cmakeprojectmanager/builddirmanager.h @@ -89,7 +89,7 @@ public: bool isFilesystemScanRequested() const; void parse(); - QVector<Utils::FilePath> takeProjectFilesToWatch(); + QSet<Utils::FilePath> projectFilesToWatch() const; std::unique_ptr<CMakeProjectNode> generateProjectTree(const QList<const ProjectExplorer::FileNode *> &allFiles, QString &errorMessage) const; ProjectExplorer::RawProjectParts createRawProjectParts(QString &errorMessage) const; diff --git a/src/plugins/cmakeprojectmanager/builddirreader.h b/src/plugins/cmakeprojectmanager/builddirreader.h index bd04f5676d2..71b5edb974f 100644 --- a/src/plugins/cmakeprojectmanager/builddirreader.h +++ b/src/plugins/cmakeprojectmanager/builddirreader.h @@ -63,7 +63,7 @@ public: virtual bool isParsing() const = 0; - virtual QVector<Utils::FilePath> takeProjectFilesToWatch() = 0; + virtual QSet<Utils::FilePath> projectFilesToWatch() const = 0; virtual QList<CMakeBuildTarget> takeBuildTargets(QString &errorMessage) = 0; virtual CMakeConfig takeParsedConfiguration(QString &errorMessage) = 0; virtual std::unique_ptr<CMakeProjectNode> generateProjectTree( diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index bbad42f18ff..9d6da30f235 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -294,11 +294,6 @@ void CMakeBuildConfiguration::clearError(ForceEnabledChanged fec) } } -void CMakeBuildConfiguration::emitBuildTypeChanged() -{ - emit buildTypeChanged(); -} - static CMakeConfig removeDuplicates(const CMakeConfig &config) { CMakeConfig result; diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h index d267cc098d6..a45b871f852 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h @@ -51,8 +51,6 @@ class CMakeBuildConfiguration final : public ProjectExplorer::BuildConfiguration ~CMakeBuildConfiguration() final; public: - void emitBuildTypeChanged(); - CMakeConfig configurationForCMake() const; CMakeConfig configurationFromCMake() const; diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 493939dd89a..c346e368ef0 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -204,7 +204,7 @@ CMakeBuildSystem::CMakeBuildSystem(CMakeBuildConfiguration *bc) }); connect(project(), &Project::projectFileIsDirty, this, [this]() { - if (m_buildConfiguration->isActive()) { + if (m_buildConfiguration->isActive() && !isParsing()) { const auto cmake = CMakeKitAspect::cmakeTool(m_buildConfiguration->target()->kit()); if (cmake && cmake->isAutoRun()) { qCDebug(cmakeBuildSystemLog) << "Requesting parse due to dirty project file"; @@ -235,9 +235,20 @@ CMakeBuildSystem::~CMakeBuildSystem() void CMakeBuildSystem::triggerParsing() { qCDebug(cmakeBuildSystemLog) << "Parsing has been triggered"; - m_currentGuard = guardParsingRun(); - QTC_ASSERT(m_currentGuard.guardsProject(), return ); + auto guard = guardParsingRun(); + + if (!guard.guardsProject()) { + // This can legitimately trigger if e.g. Build->Run CMake + // is selected while this here is already running. + + // FIXME: Instead of aborting the second run here we could try to + // cancel the first one in the Build->Run CMake handler and then + // continue to here normally. This here could then be an Assert. + return; + } + + m_currentGuard = std::move(guard); if (m_allFiles.isEmpty()) m_buildDirManager.requestFilesystemScan(); @@ -398,7 +409,7 @@ void CMakeBuildSystem::updateProjectData() QTC_ASSERT(m_treeScanner.isFinished() && !m_buildDirManager.isParsing(), return); - m_buildConfiguration->project()->setExtraProjectFiles(m_buildDirManager.takeProjectFilesToWatch()); + m_buildConfiguration->project()->setExtraProjectFiles(m_buildDirManager.projectFilesToWatch()); CMakeConfig patchedConfig = m_buildConfiguration->configurationFromCMake(); { @@ -486,7 +497,7 @@ void CMakeBuildSystem::updateProjectData() updateQmlJSCodeModel(); } - emit m_buildConfiguration->emitBuildTypeChanged(); + emit m_buildConfiguration->buildTypeChanged(); m_buildDirManager.resetData(); diff --git a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp index 0effbb97db7..2c603d7331d 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp @@ -35,9 +35,11 @@ #include <utils/algorithm.h> #include <utils/fileutils.h> +#include <utils/stringutils.h> #include <QDir> #include <QObject> +#include <QTime> #include <QTimer> namespace CMakeProjectManager { @@ -149,6 +151,7 @@ void CMakeProcess::run(const BuildDirParameters ¶meters, const QStringList & process->setCommand(commandLine); emit started(); + m_elapsed.start(); process->start(); m_process = std::move(process); @@ -234,6 +237,9 @@ void CMakeProcess::handleProcessFinished(int code, QProcess::ExitStatus status) m_future->reportFinished(); emit finished(code, status); + + const QString elapsedTime = Utils::formatElapsedTime(m_elapsed.elapsed()); + Core::MessageManager::write(elapsedTime); } void CMakeProcess::checkForCancelled() diff --git a/src/plugins/cmakeprojectmanager/cmakeprocess.h b/src/plugins/cmakeprojectmanager/cmakeprocess.h index 6d03d1ab832..d71a56629f5 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprocess.h +++ b/src/plugins/cmakeprojectmanager/cmakeprocess.h @@ -31,6 +31,7 @@ #include <utils/qtcprocess.h> +#include <QElapsedTimer> #include <QFutureInterface> #include <QTimer> @@ -73,6 +74,7 @@ private: std::unique_ptr<QFutureInterface<void>> m_future; bool m_processWasCanceled = false; QTimer m_cancelTimer; + QElapsedTimer m_elapsed; }; } // namespace Internal diff --git a/src/plugins/cmakeprojectmanager/fileapireader.cpp b/src/plugins/cmakeprojectmanager/fileapireader.cpp index 83a81f2a70e..089354dc805 100644 --- a/src/plugins/cmakeprojectmanager/fileapireader.cpp +++ b/src/plugins/cmakeprojectmanager/fileapireader.cpp @@ -164,9 +164,9 @@ bool FileApiReader::isParsing() const return m_isParsing; } -QVector<FilePath> FileApiReader::takeProjectFilesToWatch() +QSet<FilePath> FileApiReader::projectFilesToWatch() const { - return QVector<FilePath>::fromList(Utils::toList(m_cmakeFiles)); + return m_cmakeFiles; } QList<CMakeBuildTarget> FileApiReader::takeBuildTargets(QString &errorMessage){ diff --git a/src/plugins/cmakeprojectmanager/fileapireader.h b/src/plugins/cmakeprojectmanager/fileapireader.h index 2d0c1a5809a..560aafc779a 100644 --- a/src/plugins/cmakeprojectmanager/fileapireader.h +++ b/src/plugins/cmakeprojectmanager/fileapireader.h @@ -62,7 +62,7 @@ public: bool isParsing() const final; - QVector<Utils::FilePath> takeProjectFilesToWatch() final; + QSet<Utils::FilePath> projectFilesToWatch() const final; QList<CMakeBuildTarget> takeBuildTargets(QString &errorMessage) final; CMakeConfig takeParsedConfiguration(QString &errorMessage) final; std::unique_ptr<CMakeProjectNode> generateProjectTree( diff --git a/src/plugins/cmakeprojectmanager/servermodereader.h b/src/plugins/cmakeprojectmanager/servermodereader.h index dbf91b25296..3910df1778f 100644 --- a/src/plugins/cmakeprojectmanager/servermodereader.h +++ b/src/plugins/cmakeprojectmanager/servermodereader.h @@ -55,7 +55,7 @@ public: bool isParsing() const final; - QVector<Utils::FilePath> takeProjectFilesToWatch() final { return {}; }; + QSet<Utils::FilePath> projectFilesToWatch() const final { return {}; }; QList<CMakeBuildTarget> takeBuildTargets(QString &errorMessage) final; CMakeConfig takeParsedConfiguration(QString &errorMessage) final; std::unique_ptr<CMakeProjectNode> generateProjectTree( diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp index 1f60fd0fe36..c373e5d58a6 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.cpp @@ -38,12 +38,10 @@ #include <projectexplorer/gcctoolchain.h> #include <projectexplorer/headerpath.h> #include <projectexplorer/kitinformation.h> -#include <projectexplorer/kitmanager.h> #include <projectexplorer/namedwidget.h> #include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/projectnodes.h> #include <projectexplorer/target.h> -#include <projectexplorer/toolchainconfigwidget.h> #include <projectexplorer/toolchainmanager.h> #include <texteditor/textdocument.h> @@ -439,12 +437,7 @@ CompilationDatabaseProject::CompilationDatabaseProject(const Utils::FilePath &pr setId(Constants::COMPILATIONDATABASEPROJECT_ID); setProjectLanguages(Core::Context(ProjectExplorer::Constants::CXX_LANGUAGE_ID)); setDisplayName(projectDirectory().fileName()); - setBuildSystemCreator([](Target *t) { return new CompilationDatabaseBuildSystem(t); }); - - m_kit.reset(KitManager::defaultKit()->clone()); - addTargetForKit(m_kit.get()); - setExtraProjectFiles( {projectFile.stringAppended(Constants::COMPILATIONDATABASEPROJECT_FILES_SUFFIX)}); } diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h index 40ed930366d..14adde037cb 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseproject.h @@ -55,14 +55,7 @@ class CompilationDatabaseProject : public ProjectExplorer::Project public: explicit CompilationDatabaseProject(const Utils::FilePath &filename); - - bool needsConfiguration() const override { return false; } - Utils::FilePath rootPathFromSettings() const; - ProjectExplorer::Kit *kit() const { return m_kit.get(); } - -private: - std::unique_ptr<ProjectExplorer::Kit> m_kit; }; class CompilationDatabaseBuildSystem : public ProjectExplorer::BuildSystem diff --git a/src/plugins/coreplugin/editormanager/editorview.cpp b/src/plugins/coreplugin/editormanager/editorview.cpp index 9d2fe45ba70..67bbf228322 100644 --- a/src/plugins/coreplugin/editormanager/editorview.cpp +++ b/src/plugins/coreplugin/editormanager/editorview.cpp @@ -746,6 +746,7 @@ void SplitterOrView::split(Qt::Orientation orientation, bool activateView) editorView->setCloseSplitEnabled(true); // might have been disabled for root view m_view = nullptr; IEditor *e = editorView->currentEditor(); + const QByteArray state = e ? e->saveState() : QByteArray(); SplitterOrView *view = nullptr; SplitterOrView *otherView = nullptr; @@ -766,6 +767,14 @@ void SplitterOrView::split(Qt::Orientation orientation, bool activateView) otherView->view()->setCloseSplitIcon(Utils::Icons::CLOSE_SPLIT_BOTTOM.icon()); } + if (orientation == Qt::Vertical) { + // give the editor(s) the chance to adapt to the new layout, given the old state + if (duplicate) + duplicate->restoreState(state); + if (e) + e->restoreState(state); + } + if (activateView) EditorManagerPrivate::activateView(otherView->view()); emit splitStateChanged(); diff --git a/src/plugins/coreplugin/find/highlightscrollbarcontroller.cpp b/src/plugins/coreplugin/find/highlightscrollbarcontroller.cpp index f68739f1e22..4f2657fba87 100644 --- a/src/plugins/coreplugin/find/highlightscrollbarcontroller.cpp +++ b/src/plugins/coreplugin/find/highlightscrollbarcontroller.cpp @@ -122,8 +122,8 @@ void HighlightScrollBarOverlay::paintEvent(QPaintEvent *paintEvent) const QRect &gRect = overlayRect(); const QRect &hRect = handleRect(); - const int marginX = 3; - const int marginH = -2 * marginX + 1; + constexpr int marginX = 3; + constexpr int marginH = -2 * marginX + 1; const QRect aboveHandleRect = QRect(gRect.x() + marginX, gRect.y(), gRect.width() + marginH, diff --git a/src/plugins/coreplugin/generalsettings.cpp b/src/plugins/coreplugin/generalsettings.cpp index 296de7fa0ba..1b58e05eb84 100644 --- a/src/plugins/coreplugin/generalsettings.cpp +++ b/src/plugins/coreplugin/generalsettings.cpp @@ -85,7 +85,7 @@ GeneralSettingsWidget::GeneralSettingsWidget(GeneralSettings *q) m_ui.showShortcutsInContextMenus->setText( tr("Show keyboard shortcuts in context menus (default: %1)") - .arg(QLatin1String(q->m_defaultShowShortcutsInContextMenu ? "on" : "off"))); + .arg(q->m_defaultShowShortcutsInContextMenu ? tr("on") : tr("off"))); m_ui.showShortcutsInContextMenus->setChecked(q->showShortcutsInContextMenu()); #if (QT_VERSION < QT_VERSION_CHECK(5, 13, 0)) m_ui.showShortcutsInContextMenus->setVisible(false); diff --git a/src/plugins/coreplugin/iversioncontrol.cpp b/src/plugins/coreplugin/iversioncontrol.cpp index 34c9adb1ae6..fcc861b5ee4 100644 --- a/src/plugins/coreplugin/iversioncontrol.cpp +++ b/src/plugins/coreplugin/iversioncontrol.cpp @@ -194,6 +194,10 @@ QString IVersionControl::TopicCache::topic(const QString &topLevel) return data.topic = refreshTopic(topLevel); } +void IVersionControl::fillLinkContextMenu(QMenu *, const QString &, const QString &) +{ +} + } // namespace Core #if defined(WITH_TESTS) diff --git a/src/plugins/coreplugin/iversioncontrol.h b/src/plugins/coreplugin/iversioncontrol.h index 113dcf84b2d..17e471e0281 100644 --- a/src/plugins/coreplugin/iversioncontrol.h +++ b/src/plugins/coreplugin/iversioncontrol.h @@ -36,6 +36,8 @@ #include <QObject> #include <QString> +QT_FORWARD_DECLARE_CLASS(QMenu); + namespace Core { class ShellCommand; @@ -226,6 +228,10 @@ public: const QString &localName, const QStringList &extraArgs); + virtual void fillLinkContextMenu(QMenu *menu, + const QString &workingDirectory, + const QString &reference); + class CORE_EXPORT RepoUrl { public: RepoUrl(const QString &location); diff --git a/src/plugins/cpptools/builtinindexingsupport.cpp b/src/plugins/cpptools/builtinindexingsupport.cpp index 484c3adcd58..9673a995f3f 100644 --- a/src/plugins/cpptools/builtinindexingsupport.cpp +++ b/src/plugins/cpptools/builtinindexingsupport.cpp @@ -42,6 +42,7 @@ #include <cplusplus/LookupContext.h> #include <utils/qtcassert.h> #include <utils/runextensions.h> +#include <utils/stringutils.h> #include <utils/temporarydirectory.h> #include <QCoreApplication> @@ -173,9 +174,8 @@ void indexFindErrors(QFutureInterface<void> &indexingFuture, indexingFuture.setProgressValue(files.size() - (files.size() - (i + 1))); } - const QTime format = QTime(0, 0, 0, 0).addMSecs(timer.elapsed() + 500); - const QString time = format.toString(QLatin1String("hh:mm:ss")); - qDebug("FindErrorsIndexing: Finished after %s.", qPrintable(time)); + const QString elapsedTime = Utils::formatElapsedTime(timer.elapsed()); + qDebug("FindErrorsIndexing: %s", qPrintable(elapsedTime)); } void index(QFutureInterface<void> &indexingFuture, diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 8608d947e1c..377abba60f7 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -3598,6 +3598,7 @@ GitRemote::GitRemote(const QString &location) : Core::IVersionControl::RepoUrl(l void GitClient::addChangeActions(QMenu *menu, const QString &workingDir, const QString &change) { + QTC_ASSERT(!change.isEmpty(), return); menu->addAction(tr("Cherr&y-Pick Change %1").arg(change), [workingDir, change] { m_instance->synchronousCherryPick(workingDir, change); }); @@ -3611,9 +3612,11 @@ void GitClient::addChangeActions(QMenu *menu, const QString &workingDir, const Q &QAction::triggered, [workingDir, change] { GitPlugin::startRebaseFromCommit(workingDir, change); }); - menu->addAction(tr("&Log for Change %1").arg(change), [workingDir, change] { + QAction *logAction = menu->addAction(tr("&Log for Change %1").arg(change), [workingDir, change] { m_instance->log(workingDir, QString(), false, {change}); }); + if (change.contains("..")) + menu->setDefaultAction(logAction); menu->addAction(tr("Add &Tag for Change %1...").arg(change), [workingDir, change] { QString output; QString errorMessage; diff --git a/src/plugins/git/giteditor.cpp b/src/plugins/git/giteditor.cpp index 36463955963..d243c53f90b 100644 --- a/src/plugins/git/giteditor.cpp +++ b/src/plugins/git/giteditor.cpp @@ -27,7 +27,6 @@ #include "annotationhighlighter.h" #include "branchadddialog.h" -#include "gitplugin.h" #include "gitclient.h" #include "gitsettings.h" #include "gitsubmiteditorwidget.h" diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp index be99e377d26..d3d93267b36 100644 --- a/src/plugins/git/gitplugin.cpp +++ b/src/plugins/git/gitplugin.cpp @@ -83,6 +83,7 @@ #include <QAction> #include <QApplication> +#include <QClipboard> #include <QFileDialog> #include <QMenu> #include <QVBoxLayout> @@ -256,6 +257,18 @@ public: const QString &localName, const QStringList &extraArgs) final; + void fillLinkContextMenu(QMenu *menu, + const QString &workingDirectory, + const QString &reference) final + { + menu->addAction(tr("&Copy \"%1\"").arg(reference), + [reference] { QApplication::clipboard()->setText(reference); }); + QAction *action = menu->addAction(tr("&Describe Change %1").arg(reference), + [=] { describe(workingDirectory, reference); }); + menu->setDefaultAction(action); + GitClient::addChangeActions(menu, workingDirectory, reference); + } + RepoUrl getRepoUrl(const QString &location) const override; QStringList additionalToolsPath() const final; diff --git a/src/plugins/languageclient/CMakeLists.txt b/src/plugins/languageclient/CMakeLists.txt index abddb9cd968..9d04e7df1b7 100644 --- a/src/plugins/languageclient/CMakeLists.txt +++ b/src/plugins/languageclient/CMakeLists.txt @@ -19,5 +19,6 @@ add_qtc_plugin(LanguageClient languageclientutils.cpp languageclientutils.h languageclient_global.h locatorfilter.cpp locatorfilter.h + lsplogger.cpp lsplogger.h semantichighlightsupport.cpp semantichighlightsupport.h ) diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index bb74a7bcab3..80b156216d5 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -262,6 +262,9 @@ void Client::initialize() }); // directly send data otherwise the state check would fail; initRequest.registerResponseHandler(&m_responseHandlers); + LanguageClientManager::logBaseMessage(LspLogMessage::ClientMessage, + name(), + initRequest.toBaseMessage()); m_clientInterface->sendMessage(initRequest.toBaseMessage()); m_state = InitializeRequested; } @@ -334,6 +337,9 @@ void Client::sendContent(const IContent &content) QString error; if (!QTC_GUARD(content.isValid(&error))) Core::MessageManager::write(error); + LanguageClientManager::logBaseMessage(LspLogMessage::ClientMessage, + name(), + content.toBaseMessage()); m_clientInterface->sendMessage(content.toBaseMessage()); } @@ -931,6 +937,7 @@ void Client::setError(const QString &message) void Client::handleMessage(const BaseMessage &message) { + LanguageClientManager::logBaseMessage(LspLogMessage::ServerMessage, name(), message); if (auto handler = m_contentHandler[message.mimeType]) { QString parseError; handler(message.content, message.codec, parseError, diff --git a/src/plugins/languageclient/documentsymbolcache.cpp b/src/plugins/languageclient/documentsymbolcache.cpp index 21494a66936..218758b66f7 100644 --- a/src/plugins/languageclient/documentsymbolcache.cpp +++ b/src/plugins/languageclient/documentsymbolcache.cpp @@ -66,7 +66,7 @@ void DocumentSymbolCache::requestSymbolsImpl() auto entry = m_cache.find(uri); if (entry != m_cache.end()) { emit gotSymbols(uri, entry.value()); - return; + continue; } const DocumentSymbolParams params((TextDocumentIdentifier(uri))); @@ -78,6 +78,7 @@ void DocumentSymbolCache::requestSymbolsImpl() }); m_client->sendContent(request); } + m_compressedUris.clear(); } void DocumentSymbolCache::handleResponse(const DocumentUri &uri, diff --git a/src/plugins/languageclient/languageclient.pro b/src/plugins/languageclient/languageclient.pro index 5db41008d1c..f6a2930d71a 100644 --- a/src/plugins/languageclient/languageclient.pro +++ b/src/plugins/languageclient/languageclient.pro @@ -19,6 +19,7 @@ HEADERS += \ languageclientsettings.h \ languageclientutils.h \ locatorfilter.h \ + lsplogger.h \ semantichighlightsupport.h @@ -38,6 +39,7 @@ SOURCES += \ languageclientsettings.cpp \ languageclientutils.cpp \ locatorfilter.cpp \ + lsplogger.cpp \ semantichighlightsupport.cpp RESOURCES += \ diff --git a/src/plugins/languageclient/languageclient.qbs b/src/plugins/languageclient/languageclient.qbs index ce1583381de..0502921b9ef 100644 --- a/src/plugins/languageclient/languageclient.qbs +++ b/src/plugins/languageclient/languageclient.qbs @@ -46,6 +46,8 @@ QtcPlugin { "languageclientutils.h", "locatorfilter.cpp", "locatorfilter.h", + "lsplogger.cpp", + "lsplogger.h", "semantichighlightsupport.cpp", "semantichighlightsupport.h", ] diff --git a/src/plugins/languageclient/languageclientcompletionassist.cpp b/src/plugins/languageclient/languageclientcompletionassist.cpp index 54b9740809c..8b5aa94dba1 100644 --- a/src/plugins/languageclient/languageclientcompletionassist.cpp +++ b/src/plugins/languageclient/languageclientcompletionassist.cpp @@ -35,7 +35,6 @@ #include <texteditor/codeassist/genericproposal.h> #include <texteditor/codeassist/genericproposalmodel.h> #include <utils/algorithm.h> -#include <utils/executeondestruction.h> #include <utils/textutils.h> #include <utils/utilsicons.h> @@ -362,19 +361,18 @@ void LanguageClientCompletionAssistProcessor::cancel() void LanguageClientCompletionAssistProcessor::handleCompletionResponse( const CompletionRequest::Response &response) { - LanguageClientCompletionProposal *proposal = nullptr; // We must report back to the code assistant under all circumstances - Utils::ExecuteOnDestruction eod([this, proposal]() { setAsyncProposalAvailable(proposal); }); qCDebug(LOGLSPCOMPLETION) << QTime::currentTime() << " : got completions"; m_currentRequest = MessageId(); - QTC_ASSERT(m_client, return); - if (auto error = response.error()) { + QTC_ASSERT(m_client, setAsyncProposalAvailable(nullptr); return); + if (auto error = response.error()) m_client->log(error.value()); - return; - } + const Utils::optional<CompletionResult> &result = response.result(); - if (!result || Utils::holds_alternative<std::nullptr_t>(*result)) + if (!result || Utils::holds_alternative<std::nullptr_t>(*result)) { + setAsyncProposalAvailable(nullptr); return; + } QList<CompletionItem> items; if (Utils::holds_alternative<CompletionList>(*result)) { @@ -387,11 +385,12 @@ void LanguageClientCompletionAssistProcessor::handleCompletionResponse( model->loadContent(Utils::transform(items, [](const CompletionItem &item){ return static_cast<AssistProposalItemInterface *>(new LanguageClientCompletionItem(item)); })); - proposal = new LanguageClientCompletionProposal(m_pos, model); + LanguageClientCompletionProposal *proposal = new LanguageClientCompletionProposal(m_pos, model); proposal->m_document = m_document; proposal->m_pos = m_pos; proposal->setFragile(true); proposal->setSupportsPrefix(false); + setAsyncProposalAvailable(proposal); qCDebug(LOGLSPCOMPLETION) << QTime::currentTime() << " : " << items.count() << " completions handled"; } diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 27e74683132..b2c65f511b7 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -340,6 +340,20 @@ void LanguageClientManager::reOpenDocumentWithClient(TextEditor::TextDocument *d client->activateDocument(document); } +void LanguageClientManager::logBaseMessage(const LspLogMessage::MessageSender sender, + const QString &clientName, + const BaseMessage &message) +{ + instance()->m_logger.log(sender, clientName, message); +} + +void LanguageClientManager::showLogger() +{ + QWidget *loggerWidget = instance()->m_logger.createWidget(); + loggerWidget->setAttribute(Qt::WA_DeleteOnClose); + loggerWidget->show(); +} + QVector<Client *> LanguageClientManager::reachableClients() { return Utils::filtered(m_clients, &Client::reachable); diff --git a/src/plugins/languageclient/languageclientmanager.h b/src/plugins/languageclient/languageclientmanager.h index fbf5322f1cc..ae30540f44b 100644 --- a/src/plugins/languageclient/languageclientmanager.h +++ b/src/plugins/languageclient/languageclientmanager.h @@ -29,6 +29,7 @@ #include "languageclient_global.h" #include "languageclientsettings.h" #include "locatorfilter.h" +#include "lsplogger.h" #include <coreplugin/id.h> @@ -84,6 +85,11 @@ public: static Client *clientForUri(const LanguageServerProtocol::DocumentUri &uri); static void reOpenDocumentWithClient(TextEditor::TextDocument *document, Client *client); + static void logBaseMessage(const LspLogMessage::MessageSender sender, + const QString &clientName, + const LanguageServerProtocol::BaseMessage &message); + static void showLogger(); + signals: void shutdownFinished(); @@ -118,5 +124,6 @@ private: WorkspaceLocatorFilter m_workspaceLocatorFilter; WorkspaceClassLocatorFilter m_workspaceClassLocatorFilter; WorkspaceMethodLocatorFilter m_workspaceMethodLocatorFilter; + LspLogger m_logger; }; } // namespace LanguageClient diff --git a/src/plugins/languageclient/languageclientoutline.cpp b/src/plugins/languageclient/languageclientoutline.cpp index 550e391dda4..96555092294 100644 --- a/src/plugins/languageclient/languageclientoutline.cpp +++ b/src/plugins/languageclient/languageclientoutline.cpp @@ -299,6 +299,8 @@ OutlineComboBox::OutlineComboBox(Client *client, TextEditor::BaseTextEditor *edi connect(m_editorWidget, &TextEditor::TextEditorWidget::cursorPositionChanged, this, &OutlineComboBox::updateEntry); connect(this, QOverload<int>::of(&QComboBox::activated), this, &OutlineComboBox::activateEntry); + + requestSymbols(); } void OutlineComboBox::updateModel(const DocumentUri &resultUri, const DocumentSymbolsResult &result) diff --git a/src/plugins/languageclient/languageclientutils.cpp b/src/plugins/languageclient/languageclientutils.cpp index 9cc1ad488fa..72bb0157576 100644 --- a/src/plugins/languageclient/languageclientutils.cpp +++ b/src/plugins/languageclient/languageclientutils.cpp @@ -239,6 +239,9 @@ void updateEditorToolBar(Core::IEditor *editor) QObject::connect(action, &QAction::triggered, reopen); } menu->addActions(clientsGroup->actions()); + menu->addAction("Language Client Logs", []() { + LanguageClientManager::showLogger(); + }); menu->addAction("Manage...", []() { Core::ICore::showOptionsDialog(Constants::LANGUAGECLIENT_SETTINGS_PAGE); }); diff --git a/src/plugins/languageclient/lsplogger.cpp b/src/plugins/languageclient/lsplogger.cpp new file mode 100644 index 00000000000..76a50a138fe --- /dev/null +++ b/src/plugins/languageclient/lsplogger.cpp @@ -0,0 +1,364 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** 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 "lsplogger.h" + +#include <coreplugin/icore.h> +#include <coreplugin/minisplitter.h> +#include <languageserverprotocol/jsonkeys.h> +#include <languageserverprotocol/jsonrpcmessages.h> +#include <utils/jsontreeitem.h> +#include <utils/listmodel.h> + +#include <QDialog> +#include <QDialogButtonBox> +#include <QFileDialog> +#include <QFormLayout> +#include <QGroupBox> +#include <QHeaderView> +#include <QLabel> +#include <QListWidget> +#include <QPlainTextEdit> +#include <QSplitter> +#include <QStyledItemDelegate> +#include <QTextCodec> +#include <QTreeView> + +using namespace LanguageServerProtocol; + +namespace LanguageClient { + +class MessageDetailWidget : public QGroupBox +{ +public: + MessageDetailWidget(); + + void setMessage(const BaseMessage &message); + void clear(); + +private: + QLabel *m_contentLength = nullptr; + QLabel *m_mimeType = nullptr; +}; + +class LspLoggerWidget : public QDialog +{ + Q_DECLARE_TR_FUNCTIONS(LspLoggerWidget) +public: + explicit LspLoggerWidget(LspLogger *logger); + +private: + void addMessage(const QString &clientName, const LspLogMessage &message); + void setCurrentClient(const QString &clientName); + void currentMessageChanged(const QModelIndex &index); + void selectMatchingMessage(LspLogMessage::MessageSender sender, const QJsonValue &id); + void saveLog(); + + LspLogger *m_logger = nullptr; + QListWidget *m_clients = nullptr; + MessageDetailWidget *m_clientDetails = nullptr; + QListView *m_messages = nullptr; + MessageDetailWidget *m_serverDetails = nullptr; + Utils::ListModel<LspLogMessage> m_model; +}; + +QWidget *LspLogger::createWidget() +{ + return new LspLoggerWidget(this); +} + +void LspLogger::log(const LspLogMessage::MessageSender sender, + const QString &clientName, + const BaseMessage &message) +{ + QLinkedList<LspLogMessage> &clientLog = m_logs[clientName]; + auto delta = clientLog.size() - m_logSize + 1; + if (delta > 0) + clientLog.erase(clientLog.begin(), clientLog.begin() + delta); + m_logs[clientName].append({sender, QTime::currentTime(), message}); + emit newMessage(clientName, m_logs[clientName].last()); +} + +QLinkedList<LspLogMessage> LspLogger::messages(const QString &clientName) const +{ + return m_logs[clientName]; +} + +QList<QString> LspLogger::clients() const +{ + return m_logs.keys(); +} + +static QVariant messageData(const LspLogMessage &message, int, int role) +{ + if (role == Qt::DisplayRole) { + QString result = message.time.toString("hh:mm:ss.zzz") + '\n'; + if (message.message.mimeType == JsonRpcMessageHandler::jsonRpcMimeType()) { + QString error; + auto json = JsonRpcMessageHandler::toJsonObject(message.message.content, + message.message.codec, + error); + result += json.value(QString{methodKey}).toString(json.value(QString{idKey}).toString()); + } else { + result += message.message.codec->toUnicode(message.message.content); + } + return result; + } + if (role == Qt::TextAlignmentRole) + return message.sender == LspLogMessage::ClientMessage ? Qt::AlignLeft : Qt::AlignRight; + return {}; +} + +LspLoggerWidget::LspLoggerWidget(LspLogger *logger) + : m_logger(logger) +{ + setWindowTitle(tr("Language Client Log")); + + connect(logger, &LspLogger::newMessage, this, &LspLoggerWidget::addMessage); + connect(Core::ICore::instance(), &Core::ICore::coreAboutToClose, this, &QWidget::close); + + m_clients = new QListWidget; + m_clients->addItems(logger->clients()); + connect(m_clients, &QListWidget::currentTextChanged, this, &LspLoggerWidget::setCurrentClient); + m_clients->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::MinimumExpanding); + + m_clientDetails = new MessageDetailWidget; + m_clientDetails->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + m_clientDetails->setTitle(tr("Client Message")); + m_serverDetails = new MessageDetailWidget; + m_serverDetails->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + m_serverDetails->setTitle(tr("Server Message")); + + m_model.setDataAccessor(&messageData); + m_messages = new QListView; + m_messages->setModel(&m_model); + m_messages->setAlternatingRowColors(true); + m_model.setHeader({tr("Messages")}); + connect(m_messages->selectionModel(), + &QItemSelectionModel::currentChanged, + this, + &LspLoggerWidget::currentMessageChanged); + m_messages->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Expanding); + m_messages->setSelectionMode(QAbstractItemView::MultiSelection); + + auto layout = new QVBoxLayout; + setLayout(layout); + auto splitter = new Core::MiniSplitter; + splitter->setOrientation(Qt::Horizontal); + splitter->addWidget(m_clients); + splitter->addWidget(m_clientDetails); + splitter->addWidget(m_messages); + splitter->addWidget(m_serverDetails); + splitter->setStretchFactor(0, 0); + splitter->setStretchFactor(1, 1); + splitter->setStretchFactor(2, 1); + splitter->setStretchFactor(3, 1); + layout->addWidget(splitter); + + auto buttonBox = new QDialogButtonBox(this); + buttonBox->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Close); + layout->addWidget(buttonBox); + + // save + connect(buttonBox, &QDialogButtonBox::accepted, this, &LspLoggerWidget::saveLog); + + // close + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + resize(1024, 768); +} + +void LspLoggerWidget::addMessage(const QString &clientName, const LspLogMessage &message) +{ + if (m_clients->findItems(clientName, Qt::MatchExactly).isEmpty()) + m_clients->addItem(clientName); + if (clientName != m_clients->currentItem()->text()) + return; + m_model.appendItem(message); +} + +void LspLoggerWidget::setCurrentClient(const QString &clientName) +{ + m_model.clear(); + for (const LspLogMessage &message : m_logger->messages(clientName)) + m_model.appendItem(message); +} + +void LspLoggerWidget::currentMessageChanged(const QModelIndex &index) +{ + m_messages->clearSelection(); + if (!index.isValid()) + return; + LspLogMessage selectedMessage = m_model.itemAt(index.row())->itemData; + BaseMessage message = selectedMessage.message; + if (selectedMessage.sender == LspLogMessage::ClientMessage) + m_clientDetails->setMessage(message); + else + m_serverDetails->setMessage(message); + if (message.mimeType == JsonRpcMessageHandler::jsonRpcMimeType()) { + QString error; + QJsonValue id = JsonRpcMessageHandler::toJsonObject(message.content, message.codec, error) + .value(idKey); + if (!id.isUndefined()) { + selectMatchingMessage(selectedMessage.sender == LspLogMessage::ClientMessage + ? LspLogMessage::ServerMessage + : LspLogMessage::ClientMessage, + id); + } + } +} + +static bool matches(LspLogMessage::MessageSender sender, + const QJsonValue &id, + const LspLogMessage &message) +{ + if (message.sender != sender) + return false; + if (message.message.mimeType != JsonRpcMessageHandler::jsonRpcMimeType()) + return false; + QString error; + auto json = JsonRpcMessageHandler::toJsonObject(message.message.content, + message.message.codec, + error); + return json.value(QString{idKey}) == id; +} + +void LspLoggerWidget::selectMatchingMessage(LspLogMessage::MessageSender sender, + const QJsonValue &id) +{ + LspLogMessage *matchingMessage = m_model.findData( + [&](const LspLogMessage &message) { return matches(sender, id, message); }); + if (!matchingMessage) + return; + auto item = m_model.findItemByData( + [&](const LspLogMessage &message) { return &message == matchingMessage; }); + + m_messages->selectionModel()->select(m_model.indexForItem(item), QItemSelectionModel::Select); + if (matchingMessage->sender == LspLogMessage::ServerMessage) + m_serverDetails->setMessage(matchingMessage->message); + else + m_clientDetails->setMessage(matchingMessage->message); +} + +void LspLoggerWidget::saveLog() +{ + QString contents; + QTextStream stream(&contents); + m_model.forItems([&](const LspLogMessage &message) { + stream << message.time.toString("hh:mm:ss.zzz") << ' '; + stream << (message.sender == LspLogMessage::ClientMessage ? QString{"Client"} + : QString{"Server"}); + stream << '\n'; + stream << message.message.codec->toUnicode(message.message.content); + stream << "\n\n"; + }); + + const QString fileName = QFileDialog::getSaveFileName(this, tr("Log File")); + if (fileName.isEmpty()) + return; + Utils::FileSaver saver(fileName, QIODevice::Text); + saver.write(contents.toUtf8()); + if (!saver.finalize(this)) + saveLog(); +} + +MessageDetailWidget::MessageDetailWidget() +{ + auto layout = new QFormLayout; + setLayout(layout); + + m_contentLength = new QLabel; + m_mimeType = new QLabel; + + layout->addRow("Content Length:", m_contentLength); + layout->addRow("MIME Type:", m_mimeType); +} + +class JsonTreeItemDelegate : public QStyledItemDelegate +{ +public: + QString displayText(const QVariant &value, const QLocale &) const override + { + QString result = value.toString(); + if (result.size() == 1) { + switch (result.at(0).toLatin1()) { + case '\n': + return QString("\\n"); + case '\t': + return QString("\\t"); + case '\r': + return QString("\\r"); + } + } + return result; + } +}; + +void MessageDetailWidget::setMessage(const BaseMessage &message) +{ + m_contentLength->setText(QString::number(message.contentLength)); + m_mimeType->setText(QString::fromLatin1(message.mimeType)); + + QWidget *newContentWidget = nullptr; + if (message.mimeType == JsonRpcMessageHandler::jsonRpcMimeType()) { + QString error; + auto json = JsonRpcMessageHandler::toJsonObject(message.content, message.codec, error); + if (json.isEmpty()) { + newContentWidget = new QLabel(error); + } else { + auto root = new Utils::JsonTreeItem("content", json); + if (root->canFetchMore()) + root->fetchMore(); + + auto model = new Utils::TreeModel<Utils::JsonTreeItem>(root); + model->setHeader({{"Name"}, {"Value"}, {"Type"}}); + auto view = new QTreeView; + view->setModel(model); + view->setAlternatingRowColors(true); + view->header()->setSectionResizeMode(QHeaderView::ResizeToContents); + view->setItemDelegate(new JsonTreeItemDelegate); + newContentWidget = view; + } + } else { + auto edit = new QPlainTextEdit(); + edit->setReadOnly(true); + edit->setPlainText(message.codec->toUnicode(message.content)); + newContentWidget = edit; + } + auto formLayout = static_cast<QFormLayout *>(layout()); + if (formLayout->rowCount() > 2) + formLayout->removeRow(2); + formLayout->setWidget(2, QFormLayout::SpanningRole, newContentWidget); +} + +void MessageDetailWidget::clear() +{ + m_contentLength->setText({}); + m_mimeType->setText({}); + auto formLayout = static_cast<QFormLayout *>(layout()); + if (formLayout->rowCount() > 2) + formLayout->removeRow(2); +} + +} // namespace LanguageClient diff --git a/src/plugins/texteditor/normalindenter.h b/src/plugins/languageclient/lsplogger.h index 5a53caa4a31..0cb85967c48 100644 --- a/src/plugins/texteditor/normalindenter.h +++ b/src/plugins/languageclient/lsplogger.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -25,19 +25,43 @@ #pragma once -#include "textindenter.h" +#include <QLinkedList> +#include <QTime> +#include <QWidget> -namespace TextEditor { +#include <languageserverprotocol/basemessage.h> -class TEXTEDITOR_EXPORT NormalIndenter : public TextIndenter +namespace LanguageClient { + +struct LspLogMessage { + enum MessageSender { ClientMessage, ServerMessage } sender; + QTime time; + LanguageServerProtocol::BaseMessage message; +}; + +class LspLogger : public QObject +{ + Q_OBJECT public: - explicit NormalIndenter(QTextDocument *doc); - ~NormalIndenter() override = default; + LspLogger() {} + + QWidget *createWidget(); + + + void log(const LspLogMessage::MessageSender sender, + const QString &clientName, + const LanguageServerProtocol::BaseMessage &message); + + QLinkedList<LspLogMessage> messages(const QString &clientName) const; + QList<QString> clients() const; + +signals: + void newMessage(const QString &clientName, const LspLogMessage &message); - int indentFor(const QTextBlock &block, - const TabSettings &tabSettings, - int cursorPositionInEditor = -1) override; +private: + QMap<QString, QLinkedList<LspLogMessage>> m_logs; + int m_logSize = 100; // default log size if no widget is currently visible }; -} // namespace TextEditor +} // namespace LanguageClient diff --git a/src/plugins/mcusupport/mcusupport.qrc b/src/plugins/mcusupport/mcusupport.qrc index c38ede5929c..b45fb8ccc31 100644 --- a/src/plugins/mcusupport/mcusupport.qrc +++ b/src/plugins/mcusupport/mcusupport.qrc @@ -7,6 +7,7 @@ <file>wizards/icon.png</file> <file>wizards/icon@2x.png</file> <file>wizards/application/CMakeLists.txt</file> + <file>wizards/application/project.qmlproject.tpl</file> <file>wizards/application/main.qml.tpl</file> <file>wizards/application/wizard.json</file> </qresource> diff --git a/src/plugins/mcusupport/mcusupportoptions.cpp b/src/plugins/mcusupport/mcusupportoptions.cpp index 8b514534c82..d13e2e018d8 100644 --- a/src/plugins/mcusupport/mcusupportoptions.cpp +++ b/src/plugins/mcusupport/mcusupportoptions.cpp @@ -195,12 +195,101 @@ void McuPackage::updateStatus() m_infoLabel->setText(statusText); } +McuToolChainPackage::McuToolChainPackage(const QString &label, const QString &defaultPath, + const QString &detectionPath, const QString &settingsKey, + McuToolChainPackage::Type type) + : McuPackage(label, defaultPath, detectionPath, settingsKey) + , m_type(type) +{ +} + +McuToolChainPackage::Type McuToolChainPackage::type() const +{ + return m_type; +} + +static ProjectExplorer::ToolChain* armGccToolChain(const Utils::FilePath &path, Core::Id language) +{ + using namespace ProjectExplorer; + + ToolChain *toolChain = ToolChainManager::toolChain([&path, language](const ToolChain *t){ + return t->compilerCommand() == path && t->language() == language; + }); + if (!toolChain) { + ToolChainFactory *gccFactory = + Utils::findOrDefault(ToolChainFactory::allToolChainFactories(), [](ToolChainFactory *f){ + return f->supportedToolChainType() == ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID; + }); + if (gccFactory) { + const QList<ToolChain*> detected = gccFactory->detectForImport({path, language}); + if (!detected.isEmpty()) { + toolChain = detected.first(); + toolChain->setDetection(ToolChain::ManualDetection); + toolChain->setDisplayName("Arm GCC"); + ToolChainManager::registerToolChain(toolChain); + } + } + } + + return toolChain; +} + +ProjectExplorer::ToolChain *McuToolChainPackage::toolChain(Core::Id language) const +{ + const QLatin1String compilerName( + language == ProjectExplorer::Constants::C_LANGUAGE_ID ? "gcc" : "g++"); + const Utils::FilePath compiler = Utils::FilePath::fromUserInput( + Utils::HostOsInfo::withExecutableSuffix( + path() + ( + m_type == TypeArmGcc + ? "/bin/arm-none-eabi-%1" : m_type == TypeIAR + ? "/foo/bar-iar-%1" : "/bar/foo-keil-%1")).arg(compilerName)); + + ProjectExplorer::ToolChain *tc = armGccToolChain(compiler, language); + return tc; +} + +QString McuToolChainPackage::cmakeToolChainFileName() const +{ + return QLatin1String(m_type == TypeArmGcc + ? "armgcc.cmake" : m_type == McuToolChainPackage::TypeIAR + ? "iar.cmake" : "keil.cmake"); +} + +QVariant McuToolChainPackage::debuggerId() const +{ + using namespace Debugger; + + const Utils::FilePath command = Utils::FilePath::fromUserInput( + Utils::HostOsInfo::withExecutableSuffix(path() + ( + m_type == TypeArmGcc + ? "/bin/arm-none-eabi-gdb-py" : m_type == TypeIAR + ? "/foo/bar-iar-gdb" : "/bar/foo-keil-gdb"))); + const DebuggerItem *debugger = DebuggerItemManager::findByCommand(command); + QVariant debuggerId; + if (!debugger) { + DebuggerItem newDebugger; + newDebugger.setCommand(command); + const QString displayName = + m_type == TypeArmGcc + ? tr("Arm GDB at %1") : m_type == TypeIAR + ? QLatin1String("/foo/bar-iar-gdb") : QLatin1String("/bar/foo-keil-gdb"); + newDebugger.setUnexpandedDisplayName(displayName.arg(command.toUserOutput())); + debuggerId = DebuggerItemManager::registerDebugger(newDebugger); + } else { + debuggerId = debugger->id(); + } + return debuggerId; +} + McuTarget::McuTarget(const QString &vendor, const QString &platform, - const QVector<McuPackage*> &packages) + const QVector<McuPackage *> &packages, McuToolChainPackage *toolChainPackage) : m_vendor(vendor) , m_qulPlatform(platform) , m_packages(packages) + , m_toolChainPackage(toolChainPackage) { + QTC_CHECK(m_toolChainPackage == nullptr || m_packages.contains(m_toolChainPackage)); } QString McuTarget::vendor() const @@ -213,14 +302,9 @@ QVector<McuPackage *> McuTarget::packages() const return m_packages; } -void McuTarget::setToolChainFile(const QString &toolChainFile) +McuToolChainPackage *McuTarget::toolChainPackage() const { - m_toolChainFile = toolChainFile; -} - -QString McuTarget::toolChainFile() const -{ - return m_toolChainFile; + return m_toolChainPackage; } QString McuTarget::qulPlatform() const @@ -269,7 +353,7 @@ static McuPackage *createQtForMCUsPackage() return result; } -static McuPackage *createArmGccPackage() +static McuToolChainPackage *createArmGccPackage() { const char envVar[] = "ARMGCC_DIR"; @@ -290,11 +374,12 @@ static McuPackage *createArmGccPackage() if (defaultPath.isEmpty()) defaultPath = QDir::homePath(); - auto result = new McuPackage( + auto result = new McuToolChainPackage( McuPackage::tr("GNU Arm Embedded Toolchain"), defaultPath, Utils::HostOsInfo::withExecutableSuffix("bin/arm-none-eabi-g++"), - "GNUArmEmbeddedToolchain"); + "GNUArmEmbeddedToolchain", + McuToolChainPackage::TypeArmGcc); result->setDownloadUrl( "https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads"); result->setEnvironmentVariableName(envVar); @@ -368,19 +453,19 @@ static McuPackage *createSeggerJLinkPackage() McuSupportOptions::McuSupportOptions(QObject *parent) : QObject(parent) + , qtForMCUsSdkPackage(createQtForMCUsPackage()) { - qtForMCUsSdkPackage = createQtForMCUsPackage(); - armGccPackage = createArmGccPackage(); + McuToolChainPackage* armGccPackage = createArmGccPackage(); McuPackage* stm32CubeFwF7SdkPackage = createStm32CubeFwF7SdkPackage(); McuPackage* stm32CubeProgrammerPackage = createStm32CubeProgrammerPackage(); McuPackage* evkbImxrt1050SdkPackage = createEvkbImxrt1050SdkPackage(); McuPackage* seggerJLinkPackage = createSeggerJLinkPackage(); - auto stmEvalPackages = { + QVector<McuPackage*> stmEvalPackages = { armGccPackage, stm32CubeProgrammerPackage, qtForMCUsSdkPackage}; - auto nxpEvalPackages = { + QVector<McuPackage*> nxpEvalPackages = { armGccPackage, seggerJLinkPackage, qtForMCUsSdkPackage}; - auto desktopPackages = { + QVector<McuPackage*> desktopPackages = { qtForMCUsSdkPackage}; packages = { armGccPackage, stm32CubeFwF7SdkPackage, stm32CubeProgrammerPackage, evkbImxrt1050SdkPackage, @@ -390,30 +475,25 @@ McuSupportOptions::McuSupportOptions(QObject *parent) const QString vendorNxp = "NXP"; const QString vendorQt = "Qt"; - const QString armGccToochainFile = "CMake/toolchain/armgcc.cmake"; - // STM - auto mcuTarget = new McuTarget(vendorStm, "STM32F7508-DISCOVERY", stmEvalPackages); - mcuTarget->setToolChainFile(armGccToochainFile); + auto mcuTarget = new McuTarget(vendorStm, "STM32F7508-DISCOVERY", stmEvalPackages, + armGccPackage); mcuTarget->setColorDepth(32); mcuTargets.append(mcuTarget); - mcuTarget = new McuTarget(vendorStm, "STM32F7508-DISCOVERY", stmEvalPackages); - mcuTarget->setToolChainFile(armGccToochainFile); + mcuTarget = new McuTarget(vendorStm, "STM32F7508-DISCOVERY", stmEvalPackages, armGccPackage); mcuTarget->setColorDepth(16); mcuTargets.append(mcuTarget); - mcuTarget = new McuTarget(vendorStm, "STM32F769I-DISCOVERY", stmEvalPackages); - mcuTarget->setToolChainFile(armGccToochainFile); + mcuTarget = new McuTarget(vendorStm, "STM32F769I-DISCOVERY", stmEvalPackages, armGccPackage); mcuTargets.append(mcuTarget); // NXP - mcuTarget = new McuTarget(vendorNxp, "MIMXRT1050-EVK", nxpEvalPackages); - mcuTarget->setToolChainFile(armGccToochainFile); + mcuTarget = new McuTarget(vendorNxp, "MIMXRT1050-EVK", nxpEvalPackages, armGccPackage); mcuTargets.append(mcuTarget); // Desktop (Qt) - mcuTarget = new McuTarget(vendorQt, "Qt", desktopPackages); + mcuTarget = new McuTarget(vendorQt, "Qt", desktopPackages, nullptr); mcuTarget->setColorDepth(32); mcuTargets.append(mcuTarget); @@ -431,32 +511,6 @@ McuSupportOptions::~McuSupportOptions() mcuTargets.clear(); } -static ProjectExplorer::ToolChain* armGccToolchain(const Utils::FilePath &path, Core::Id language) -{ - using namespace ProjectExplorer; - - ToolChain *toolChain = ToolChainManager::toolChain([&path, language](const ToolChain *t){ - return t->compilerCommand() == path && t->language() == language; - }); - if (!toolChain) { - ToolChainFactory *gccFactory = - Utils::findOrDefault(ToolChainFactory::allToolChainFactories(), [](ToolChainFactory *f){ - return f->supportedToolChainType() == ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID; - }); - if (gccFactory) { - const QList<ToolChain*> detected = gccFactory->detectForImport({path, language}); - if (!detected.isEmpty()) { - toolChain = detected.first(); - toolChain->setDetection(ToolChain::ManualDetection); - toolChain->setDisplayName("Arm GCC"); - ToolChainManager::registerToolChain(toolChain); - } - } - } - - return toolChain; -} - static bool mcuTargetIsDesktop(const McuTarget* mcuTarget) { return mcuTarget->qulPlatform() == "Qt"; @@ -492,48 +546,22 @@ static void setKitProperties(const QString &kitName, ProjectExplorer::Kit *k, } } -static void setKitToolchains(ProjectExplorer::Kit *k, const QString &armGccPath) +static void setKitToolchains(ProjectExplorer::Kit *k, const McuToolChainPackage *tcPackage) { - using namespace ProjectExplorer; - - const QString compileNameScheme = Utils::HostOsInfo::withExecutableSuffix( - armGccPath + "/bin/arm-none-eabi-%1"); - ToolChain *cTc = armGccToolchain( - Utils::FilePath::fromUserInput(compileNameScheme.arg("gcc")), - ProjectExplorer::Constants::C_LANGUAGE_ID); - ToolChain *cxxTc = armGccToolchain( - Utils::FilePath::fromUserInput(compileNameScheme.arg("g++")), - ProjectExplorer::Constants::CXX_LANGUAGE_ID); - ToolChainKitAspect::setToolChain(k, cTc); - ToolChainKitAspect::setToolChain(k, cxxTc); + ProjectExplorer::ToolChainKitAspect::setToolChain(k, tcPackage->toolChain( + ProjectExplorer::Constants::C_LANGUAGE_ID)); + ProjectExplorer::ToolChainKitAspect::setToolChain(k, tcPackage->toolChain( + ProjectExplorer::Constants::CXX_LANGUAGE_ID)); } -static void setKitDebugger(ProjectExplorer::Kit *k, const QString &armGccPath) +static void setKitDebugger(ProjectExplorer::Kit *k, const McuToolChainPackage *tcPackage) { - using namespace Debugger; - - const Utils::FilePath command = Utils::FilePath::fromUserInput( - Utils::HostOsInfo::withExecutableSuffix(armGccPath + "/bin/arm-none-eabi-gdb-py")); - const DebuggerItem *debugger = DebuggerItemManager::findByCommand(command); - QVariant debuggerId; - if (!debugger) { - DebuggerItem newDebugger; - newDebugger.setCommand(command); - newDebugger.setUnexpandedDisplayName( - McuPackage::tr("Arm GDB at %1").arg(command.toUserOutput())); - debuggerId = DebuggerItemManager::registerDebugger(newDebugger); - } else { - debuggerId = debugger->id(); - } - - DebuggerKitAspect::setDebugger(k, debuggerId); + Debugger::DebuggerKitAspect::setDebugger(k, tcPackage->debuggerId()); } static void setKitDevice(ProjectExplorer::Kit *k) { - using namespace ProjectExplorer; - - DeviceTypeKitAspect::setDeviceTypeId(k, Constants::DEVICE_TYPE); + ProjectExplorer::DeviceTypeKitAspect::setDeviceTypeId(k, Constants::DEVICE_TYPE); } static void setKitEnvironment(ProjectExplorer::Kit *k, const McuTarget* mcuTarget) @@ -564,11 +592,13 @@ static void setKitCMakeOptions(ProjectExplorer::Kit *k, const McuTarget* mcuTarg CMakeConfig config = CMakeConfigurationKitAspect::configuration(k); config.append(CMakeConfigItem("CMAKE_CXX_COMPILER", "%{Compiler:Executable:Cxx}")); config.append(CMakeConfigItem("CMAKE_C_COMPILER", "%{Compiler:Executable:C}")); - if (!mcuTarget->toolChainFile().isEmpty()) - config.append(CMakeConfigItem("CMAKE_TOOLCHAIN_FILE", - (qulDir + "/" + mcuTarget->toolChainFile()).toUtf8())); + if (mcuTarget->toolChainPackage()) + config.append(CMakeConfigItem( + "CMAKE_TOOLCHAIN_FILE", + (qulDir + "/lib/cmake/Qul/toolchain/" + + mcuTarget->toolChainPackage()->cmakeToolChainFileName()).toUtf8())); config.append(CMakeConfigItem("QUL_GENERATORS", - (qulDir + "/CMake/QulGenerators.cmake").toUtf8())); + (qulDir + "/lib/cmake/Qul/QulGenerators.cmake").toUtf8())); config.append(CMakeConfigItem("QUL_PLATFORM", mcuTarget->qulPlatform().toUtf8())); if (mcuTargetIsDesktop(mcuTarget)) @@ -607,15 +637,13 @@ ProjectExplorer::Kit *McuSupportOptions::newKit(const McuTarget *mcuTarget) { using namespace ProjectExplorer; - const QString armGccPath = armGccPackage->path(); - const QString qulDir = qtForMCUsSdkPackage->path(); const auto init = [this, mcuTarget](Kit *k) { KitGuard kitGuard(k); setKitProperties(kitName(mcuTarget), k, mcuTarget); if (!mcuTargetIsDesktop(mcuTarget)) { - setKitToolchains(k, armGccPackage->path()); - setKitDebugger(k, armGccPackage->path()); + setKitToolchains(k, mcuTarget->toolChainPackage()); + setKitDebugger(k, mcuTarget->toolChainPackage()); setKitDevice(k); } setKitEnvironment(k, mcuTarget); diff --git a/src/plugins/mcusupport/mcusupportoptions.h b/src/plugins/mcusupport/mcusupportoptions.h index 55e75d2bfb0..deb7010f9da 100644 --- a/src/plugins/mcusupport/mcusupportoptions.h +++ b/src/plugins/mcusupport/mcusupportoptions.h @@ -30,6 +30,10 @@ QT_FORWARD_DECLARE_CLASS(QWidget) +namespace Core { +class Id; +} + namespace Utils { class PathChooser; class InfoLabel; @@ -37,6 +41,7 @@ class InfoLabel; namespace ProjectExplorer { class Kit; +class ToolChain; } namespace McuSupport { @@ -55,6 +60,7 @@ public: McuPackage(const QString &label, const QString &defaultPath, const QString &detectionPath, const QString &settingsKey); + virtual ~McuPackage() = default; QString path() const; QString label() const; @@ -95,17 +101,38 @@ private: Status m_status = InvalidPath; }; +class McuToolChainPackage : public McuPackage +{ +public: + enum Type { + TypeArmGcc, + TypeIAR, + TypeKEIL + }; + + McuToolChainPackage(const QString &label, const QString &defaultPath, + const QString &detectionPath, const QString &settingsKey, Type type); + + Type type() const; + ProjectExplorer::ToolChain *toolChain(Core::Id language) const; + QString cmakeToolChainFileName() const; + QVariant debuggerId() const; + +private: + const Type m_type; +}; + class McuTarget : public QObject { Q_OBJECT public: - McuTarget(const QString &vendor, const QString &platform, const QVector<McuPackage *> &packages); + McuTarget(const QString &vendor, const QString &platform, const QVector<McuPackage *> &packages, + McuToolChainPackage *toolChainPackage); QString vendor() const; QVector<McuPackage *> packages() const; - void setToolChainFile(const QString &toolChainFile); - QString toolChainFile() const; + McuToolChainPackage *toolChainPackage() const; QString qulPlatform() const; void setColorDepth(int colorDepth); int colorDepth() const; @@ -115,7 +142,7 @@ private: const QString m_vendor; const QString m_qulPlatform; const QVector<McuPackage*> m_packages; - QString m_toolChainFile; + McuToolChainPackage *m_toolChainPackage; int m_colorDepth = -1; }; @@ -129,7 +156,6 @@ public: QVector<McuPackage*> packages; QVector<McuTarget*> mcuTargets; - McuPackage *armGccPackage = nullptr; McuPackage *qtForMCUsSdkPackage = nullptr; QString kitName(const McuTarget* mcuTarget) const; diff --git a/src/plugins/mcusupport/mcusupportoptionspage.cpp b/src/plugins/mcusupport/mcusupportoptionspage.cpp index b63db28c656..5d72fd819df 100644 --- a/src/plugins/mcusupport/mcusupportoptionspage.cpp +++ b/src/plugins/mcusupport/mcusupportoptionspage.cpp @@ -183,7 +183,6 @@ void McuSupportOptionsWidget::apply() for (auto package : m_options.packages) package->writeToSettings(); - QTC_ASSERT(m_options.armGccPackage, return); QTC_ASSERT(m_options.qtForMCUsSdkPackage, return); if (!isVisible() || !cMakeAvailable()) diff --git a/src/plugins/mcusupport/wizards/application/project.qmlproject.tpl b/src/plugins/mcusupport/wizards/application/project.qmlproject.tpl new file mode 100644 index 00000000000..0b5d6d58631 --- /dev/null +++ b/src/plugins/mcusupport/wizards/application/project.qmlproject.tpl @@ -0,0 +1,19 @@ +/* File generated by Qt Creator */ + +import QmlProject 1.1 + +Project { + mainFile: "%{MainQmlFile}" + qtForMCUs: true + + /* Include .qml, .js, and image files from current directory and subdirectories */ + QmlFiles { + directory: "." + } + JavaScriptFiles { + directory: "." + } + ImageFiles { + directory: "." + } +} diff --git a/src/plugins/mcusupport/wizards/application/wizard.json b/src/plugins/mcusupport/wizards/application/wizard.json index 4e16d17e937..1c598507e13 100644 --- a/src/plugins/mcusupport/wizards/application/wizard.json +++ b/src/plugins/mcusupport/wizards/application/wizard.json @@ -48,6 +48,11 @@ "openAsProject": true }, { + "source": "project.qmlproject.tpl", + "target": "%{ProjectDirectory}/%{ProjectName}.qmlproject", + "openInEditor": false + }, + { "source": "main.qml.tpl", "target": "%{ProjectDirectory}/%{MainQmlFile}", "openInEditor": true diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt index 9f033bee0da..24b7dbd6553 100644 --- a/src/plugins/projectexplorer/CMakeLists.txt +++ b/src/plugins/projectexplorer/CMakeLists.txt @@ -162,6 +162,7 @@ add_qtc_plugin(ProjectExplorer sessionview.cpp sessionview.h showineditortaskhandler.cpp showineditortaskhandler.h showoutputtaskhandler.cpp showoutputtaskhandler.h + simpleprojectwizard.cpp simpleprojectwizard.h target.cpp target.h targetsettingspanel.cpp targetsettingspanel.h targetsetuppage.cpp targetsetuppage.h diff --git a/src/plugins/projectexplorer/abi.cpp b/src/plugins/projectexplorer/abi.cpp index afaeb126e19..0cb6ca7fb80 100644 --- a/src/plugins/projectexplorer/abi.cpp +++ b/src/plugins/projectexplorer/abi.cpp @@ -666,6 +666,12 @@ bool Abi::isCompatibleWith(const Abi &other) const return isCompat; } +bool Abi::isFullyCompatibleWith(const Abi &other) const +{ + return *this == other || (wordWidth() == other.wordWidth() + && compatibleMSVCFlavors(osFlavor(), other.osFlavor())); +} + bool Abi::isValid() const { return m_architecture != UnknownArchitecture diff --git a/src/plugins/projectexplorer/abi.h b/src/plugins/projectexplorer/abi.h index 517046ec3bc..3da9334e2e2 100644 --- a/src/plugins/projectexplorer/abi.h +++ b/src/plugins/projectexplorer/abi.h @@ -134,6 +134,7 @@ public: bool operator != (const Abi &other) const; bool operator == (const Abi &other) const; bool isCompatibleWith(const Abi &other) const; + bool isFullyCompatibleWith(const Abi &other) const; bool isValid() const; bool isNull() const; diff --git a/src/plugins/projectexplorer/buildmanager.cpp b/src/plugins/projectexplorer/buildmanager.cpp index 27c46a54a61..41bcc17ccc8 100644 --- a/src/plugins/projectexplorer/buildmanager.cpp +++ b/src/plugins/projectexplorer/buildmanager.cpp @@ -47,6 +47,7 @@ #include <coreplugin/progressmanager/progressmanager.h> #include <extensionsystem/pluginmanager.h> #include <utils/runextensions.h> +#include <utils/stringutils.h> #include <QApplication> #include <QElapsedTimer> @@ -458,11 +459,8 @@ void BuildManager::updateTaskCount() void BuildManager::finish() { - const QTime format = QTime(0, 0, 0, 0).addMSecs(d->m_elapsed.elapsed() + 500); - QString time = format.toString("h:mm:ss"); - if (time.startsWith("0:")) - time.remove(0, 2); // Don't display zero hours - m_instance->addToOutputWindow(tr("Elapsed time: %1.") .arg(time), BuildStep::OutputFormat::NormalMessage); + const QString elapsedTime = Utils::formatElapsedTime(d->m_elapsed.elapsed()); + m_instance->addToOutputWindow(elapsedTime, BuildStep::OutputFormat::NormalMessage); QApplication::alert(ICore::mainWindow(), 3000); } diff --git a/src/plugins/projectexplorer/buildsettingspropertiespage.cpp b/src/plugins/projectexplorer/buildsettingspropertiespage.cpp index 924adfa6784..b0f4ce758a8 100644 --- a/src/plugins/projectexplorer/buildsettingspropertiespage.cpp +++ b/src/plugins/projectexplorer/buildsettingspropertiespage.cpp @@ -244,7 +244,7 @@ QString BuildSettingsWidget::uniqueName(const QString & name) QString result = name.trimmed(); if (!result.isEmpty()) { QStringList bcNames; - foreach (BuildConfiguration *bc, m_target->buildConfigurations()) { + for (BuildConfiguration *bc : m_target->buildConfigurations()) { if (bc == m_buildConfiguration) continue; bcNames.append(bc->displayName()); diff --git a/src/plugins/qmakeprojectmanager/images/qmakeprojectmanager.png b/src/plugins/projectexplorer/images/importasproject.png Binary files differindex b75e0422f7f..b75e0422f7f 100644 --- a/src/plugins/qmakeprojectmanager/images/qmakeprojectmanager.png +++ b/src/plugins/projectexplorer/images/importasproject.png diff --git a/src/plugins/qmakeprojectmanager/images/qmakeprojectmanager@2x.png b/src/plugins/projectexplorer/images/importasproject@2x.png Binary files differindex 8c708b52e3b..8c708b52e3b 100644 --- a/src/plugins/qmakeprojectmanager/images/qmakeprojectmanager@2x.png +++ b/src/plugins/projectexplorer/images/importasproject@2x.png diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardgeneratorfactory.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardgeneratorfactory.cpp index 4f4f8882f74..5d9a7e19ef4 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardgeneratorfactory.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardgeneratorfactory.cpp @@ -36,10 +36,10 @@ #include <coreplugin/dialogs/promptoverwritedialog.h> #include <texteditor/icodestylepreferences.h> #include <texteditor/icodestylepreferencesfactory.h> -#include <texteditor/normalindenter.h> #include <texteditor/storagesettings.h> #include <texteditor/tabsettings.h> #include <texteditor/texteditorsettings.h> +#include <texteditor/textindenter.h> #include <utils/algorithm.h> #include <utils/mimetypes/mimedatabase.h> @@ -101,7 +101,7 @@ bool JsonWizardGenerator::formatFile(const JsonWizard *wizard, GeneratedFile *fi indenter->setFileName(Utils::FilePath::fromString(file->path())); } if (!indenter) - indenter = new NormalIndenter(&doc); + indenter = new TextIndenter(&doc); ICodeStylePreferences *codeStylePrefs = codeStylePreferences(baseProject, languageId); indenter->setCodeStylePreferences(codeStylePrefs); diff --git a/src/plugins/projectexplorer/miniprojecttargetselector.cpp b/src/plugins/projectexplorer/miniprojecttargetselector.cpp index 85b75860e88..0057366a175 100644 --- a/src/plugins/projectexplorer/miniprojecttargetselector.cpp +++ b/src/plugins/projectexplorer/miniprojecttargetselector.cpp @@ -1259,17 +1259,17 @@ void MiniProjectTargetSelector::activeTargetChanged(Target *target) if (m_target) { QList<QObject *> bl; - foreach (BuildConfiguration *bc, target->buildConfigurations()) + for (BuildConfiguration *bc : target->buildConfigurations()) bl.append(bc); m_listWidgets[BUILD]->setProjectConfigurations(bl, target->activeBuildConfiguration()); QList<QObject *> dl; - foreach (DeployConfiguration *dc, target->deployConfigurations()) + for (DeployConfiguration *dc : target->deployConfigurations()) dl.append(dc); m_listWidgets[DEPLOY]->setProjectConfigurations(dl, target->activeDeployConfiguration()); QList<QObject *> rl; - foreach (RunConfiguration *rc, target->runConfigurations()) + for (RunConfiguration *rc : target->runConfigurations()) rl.append(rc); m_listWidgets[RUN]->setProjectConfigurations(rl, target->activeRunConfiguration()); diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index af07fa7e5d6..f338b3bfafc 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -340,6 +340,7 @@ void Project::setActiveTarget(Target *target) (target && Utils::contains(d->m_targets, target))) { d->m_activeTarget = target; emit activeTargetChanged(d->m_activeTarget); + ProjectExplorerPlugin::updateActions(); } } @@ -353,16 +354,16 @@ void Project::setNeedsInitialExpansion(bool needsExpansion) d->m_needsInitialExpansion = needsExpansion; } -void Project::setExtraProjectFiles(const QVector<Utils::FilePath> &projectDocumentPaths) +void Project::setExtraProjectFiles(const QSet<Utils::FilePath> &projectDocumentPaths) { - QSet<Utils::FilePath> uniqueNewFiles = Utils::toSet(projectDocumentPaths); + QSet<Utils::FilePath> uniqueNewFiles = projectDocumentPaths; uniqueNewFiles.remove(projectFilePath()); // Make sure to never add the main project file! QSet<Utils::FilePath> existingWatches = Utils::transform<QSet>(d->m_extraProjectDocuments, &Core::IDocument::filePath); - QSet<Utils::FilePath> toAdd = uniqueNewFiles.subtract(existingWatches); - QSet<Utils::FilePath> toRemove = existingWatches.subtract(uniqueNewFiles); + const QSet<Utils::FilePath> toAdd = uniqueNewFiles - existingWatches; + const QSet<Utils::FilePath> toRemove = existingWatches - uniqueNewFiles; Utils::erase(d->m_extraProjectDocuments, [&toRemove](const std::unique_ptr<Core::IDocument> &d) { return toRemove.contains(d->filePath()); @@ -400,7 +401,7 @@ bool Project::copySteps(Target *sourceTarget, Target *newTarget) QStringList runconfigurationError; const Project * const project = newTarget->project(); - foreach (BuildConfiguration *sourceBc, sourceTarget->buildConfigurations()) { + for (BuildConfiguration *sourceBc : sourceTarget->buildConfigurations()) { ProjectMacroExpander expander(project->projectFilePath(), project->displayName(), newTarget->kit(), sourceBc->displayName(), sourceBc->buildType()); @@ -422,7 +423,7 @@ bool Project::copySteps(Target *sourceTarget, Target *newTarget) SessionManager::setActiveBuildConfiguration(newTarget, bcs.first(), SetActive::NoCascade); } - foreach (DeployConfiguration *sourceDc, sourceTarget->deployConfigurations()) { + for (DeployConfiguration *sourceDc : sourceTarget->deployConfigurations()) { DeployConfiguration *newDc = DeployConfigurationFactory::clone(newTarget, sourceDc); if (!newDc) { deployconfigurationError << sourceDc->displayName(); @@ -439,7 +440,7 @@ bool Project::copySteps(Target *sourceTarget, Target *newTarget) SessionManager::setActiveDeployConfiguration(newTarget, dcs.first(), SetActive::NoCascade); } - foreach (RunConfiguration *sourceRc, sourceTarget->runConfigurations()) { + for (RunConfiguration *sourceRc : sourceTarget->runConfigurations()) { RunConfiguration *newRc = RunConfigurationFactory::clone(newTarget, sourceRc); if (!newRc) { runconfigurationError << sourceRc->displayName(); diff --git a/src/plugins/projectexplorer/project.h b/src/plugins/projectexplorer/project.h index 2b0c95a1341..53e4b272c7c 100644 --- a/src/plugins/projectexplorer/project.h +++ b/src/plugins/projectexplorer/project.h @@ -162,7 +162,7 @@ public: // Set project files that will be watched and trigger the same callback // as the main project file. - void setExtraProjectFiles(const QVector<Utils::FilePath> &projectDocumentPaths); + void setExtraProjectFiles(const QSet<Utils::FilePath> &projectDocumentPaths); void setDisplayName(const QString &name); void setProjectLanguage(Core::Id id, bool enabled); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index af5973fb4b3..816b2441966 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -98,6 +98,7 @@ #include "targetsettingspanel.h" #include "projectpanelfactory.h" #include "projectexplorericons.h" +#include "simpleprojectwizard.h" #include "windebuginterface.h" #include "msvctoolchain.h" @@ -448,10 +449,6 @@ public: void projectAdded(ProjectExplorer::Project *pro); void projectRemoved(ProjectExplorer::Project *pro); void projectDisplayNameChanged(ProjectExplorer::Project *pro); - void startupProjectChanged(); // Calls updateRunAction - void activeTargetChanged(); - void activeRunConfigurationChanged(); - void activeBuildConfigurationChanged(); void doUpdateRunActions(); @@ -713,6 +710,7 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er QList<IWizardFactory *> result; result << CustomWizard::createWizards(); result << JsonWizardFactory::createWizardFactories(); + result << new SimpleProjectWizard; return result; }); @@ -730,8 +728,6 @@ bool ProjectExplorerPlugin::initialize(const QStringList &arguments, QString *er dd, &ProjectExplorerPluginPrivate::projectAdded); connect(sessionManager, &SessionManager::projectRemoved, dd, &ProjectExplorerPluginPrivate::projectRemoved); - connect(sessionManager, &SessionManager::startupProjectChanged, - dd, &ProjectExplorerPluginPrivate::startupProjectChanged); connect(sessionManager, &SessionManager::projectDisplayNameChanged, dd, &ProjectExplorerPluginPrivate::projectDisplayNameChanged); connect(sessionManager, &SessionManager::dependencyChanged, @@ -2938,85 +2934,6 @@ void ProjectExplorerPluginPrivate::projectDisplayNameChanged(Project *pro) updateActions(); } -void ProjectExplorerPluginPrivate::startupProjectChanged() -{ - static QPointer<Project> previousStartupProject = nullptr; - Project *project = SessionManager::startupProject(); - if (project == previousStartupProject) - return; - - if (previousStartupProject) { - disconnect(previousStartupProject.data(), &Project::activeTargetChanged, - this, &ProjectExplorerPluginPrivate::activeTargetChanged); - } - - previousStartupProject = project; - - if (project) { - connect(project, &Project::activeTargetChanged, - this, &ProjectExplorerPluginPrivate::activeTargetChanged); - } - - activeTargetChanged(); - updateActions(); -} - -void ProjectExplorerPluginPrivate::activeTargetChanged() -{ - static QPointer<Target> previousTarget = nullptr; - Target *target = nullptr; - Project *startupProject = SessionManager::startupProject(); - if (startupProject) - target = startupProject->activeTarget(); - if (target == previousTarget) - return; - - if (previousTarget) { - disconnect(previousTarget.data(), &Target::activeRunConfigurationChanged, - this, &ProjectExplorerPluginPrivate::activeRunConfigurationChanged); - disconnect(previousTarget.data(), &Target::activeBuildConfigurationChanged, - this, &ProjectExplorerPluginPrivate::activeBuildConfigurationChanged); - } - previousTarget = target; - if (target) { - connect(target, &Target::activeRunConfigurationChanged, - this, &ProjectExplorerPluginPrivate::activeRunConfigurationChanged); - connect(previousTarget.data(), &Target::activeBuildConfigurationChanged, - this, &ProjectExplorerPluginPrivate::activeBuildConfigurationChanged); - } - - activeBuildConfigurationChanged(); - activeRunConfigurationChanged(); - updateDeployActions(); -} - -void ProjectExplorerPluginPrivate::activeRunConfigurationChanged() -{ - static QPointer<RunConfiguration> previousRunConfiguration = nullptr; - RunConfiguration *rc = nullptr; - Project *startupProject = SessionManager::startupProject(); - if (startupProject && startupProject->activeTarget()) - rc = startupProject->activeTarget()->activeRunConfiguration(); - if (rc == previousRunConfiguration) - return; - updateActions(); - doUpdateRunActions(); -} - -void ProjectExplorerPluginPrivate::activeBuildConfigurationChanged() -{ - static QPointer<BuildConfiguration> previousBuildConfiguration = nullptr; - - BuildConfiguration *bc = nullptr; - if (Target *target = SessionManager::startupTarget()) - bc = target->activeBuildConfiguration(); - if (bc == previousBuildConfiguration) - return; - - updateActions(); - doUpdateRunActions(); -} - void ProjectExplorerPluginPrivate::updateDeployActions() { Project *project = SessionManager::startupProject(); diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro index 341247b735a..4f9b5dd4f7a 100644 --- a/src/plugins/projectexplorer/projectexplorer.pro +++ b/src/plugins/projectexplorer/projectexplorer.pro @@ -165,7 +165,8 @@ HEADERS += projectexplorer.h \ parseissuesdialog.h \ projectconfigurationaspects.h \ treescanner.h \ - rawprojectpart.h + rawprojectpart.h \ + simpleprojectwizard.h SOURCES += projectexplorer.cpp \ abi.cpp \ @@ -311,7 +312,8 @@ SOURCES += projectexplorer.cpp \ parseissuesdialog.cpp \ projectconfigurationaspects.cpp \ treescanner.cpp \ - rawprojectpart.cpp + rawprojectpart.cpp \ + simpleprojectwizard.cpp FORMS += \ editorsettingspropertiespage.ui \ diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index 8fe4fe522d8..6398533ca43 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -142,6 +142,7 @@ Project { "sessiondialog.cpp", "sessiondialog.h", "sessiondialog.ui", "showineditortaskhandler.cpp", "showineditortaskhandler.h", "showoutputtaskhandler.cpp", "showoutputtaskhandler.h", + "simpleprojectwizard.cpp", "simpleprojectwizard.h", "target.cpp", "target.h", "targetsettingspanel.cpp", "targetsettingspanel.h", "targetsetuppage.cpp", "targetsetuppage.h", diff --git a/src/plugins/projectexplorer/projectexplorer.qrc b/src/plugins/projectexplorer/projectexplorer.qrc index 36b149e2538..0f5e0dc3069 100644 --- a/src/plugins/projectexplorer/projectexplorer.qrc +++ b/src/plugins/projectexplorer/projectexplorer.qrc @@ -86,5 +86,7 @@ <file>images/settingscategory_kits@2x.png</file> <file>images/settingscategory_cpp.png</file> <file>images/settingscategory_cpp@2x.png</file> + <file>images/importasproject.png</file> + <file>images/importasproject@2x.png</file> </qresource> </RCC> diff --git a/src/plugins/projectexplorer/projectfilewizardextension.cpp b/src/plugins/projectexplorer/projectfilewizardextension.cpp index 33be4cdcfe8..ff58e14308b 100644 --- a/src/plugins/projectexplorer/projectfilewizardextension.cpp +++ b/src/plugins/projectexplorer/projectfilewizardextension.cpp @@ -35,15 +35,15 @@ #include <utils/stringutils.h> #include <coreplugin/icore.h> -#include <texteditor/texteditorsettings.h> +#include <projectexplorer/editorconfiguration.h> +#include <projectexplorer/project.h> +#include <projectexplorer/projecttree.h> #include <texteditor/icodestylepreferences.h> #include <texteditor/icodestylepreferencesfactory.h> -#include <texteditor/normalindenter.h> -#include <texteditor/tabsettings.h> #include <texteditor/storagesettings.h> -#include <projectexplorer/project.h> -#include <projectexplorer/projecttree.h> -#include <projectexplorer/editorconfiguration.h> +#include <texteditor/tabsettings.h> +#include <texteditor/texteditorsettings.h> +#include <texteditor/textindenter.h> #include <utils/mimetypes/mimedatabase.h> # #include <QPointer> @@ -259,7 +259,7 @@ void ProjectFileWizardExtension::applyCodeStyle(GeneratedFile *file) const indenter->setFileName(Utils::FilePath::fromString(file->path())); } if (!indenter) - indenter = new NormalIndenter(&doc); + indenter = new TextIndenter(&doc); ICodeStylePreferences *codeStylePrefs = codeStylePreferences(baseProject, languageId); indenter->setCodeStylePreferences(codeStylePrefs); diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp index bb3bc8b8dca..f76d15531e8 100644 --- a/src/plugins/projectexplorer/session.cpp +++ b/src/plugins/projectexplorer/session.cpp @@ -323,7 +323,7 @@ void SessionManager::setActiveBuildConfiguration(Target *target, BuildConfigurat if (!otherTarget || otherTarget->kit()->id() != kitId) continue; - foreach (BuildConfiguration *otherBc, otherTarget->buildConfigurations()) { + for (BuildConfiguration *otherBc : otherTarget->buildConfigurations()) { if (otherBc->displayName() == name) { otherTarget->setActiveBuildConfiguration(otherBc); break; @@ -351,7 +351,7 @@ void SessionManager::setActiveDeployConfiguration(Target *target, DeployConfigur if (!otherTarget || otherTarget->kit()->id() != kitId) continue; - foreach (DeployConfiguration *otherDc, otherTarget->deployConfigurations()) { + for (DeployConfiguration *otherDc : otherTarget->deployConfigurations()) { if (otherDc->displayName() == name) { otherTarget->setActiveDeployConfiguration(otherDc); break; diff --git a/src/plugins/qmakeprojectmanager/wizards/simpleprojectwizard.cpp b/src/plugins/projectexplorer/simpleprojectwizard.cpp index f601b4c5a12..d9d88aa3158 100644 --- a/src/plugins/qmakeprojectmanager/wizards/simpleprojectwizard.cpp +++ b/src/plugins/projectexplorer/simpleprojectwizard.cpp @@ -25,16 +25,18 @@ #include "simpleprojectwizard.h" -#include <qmakeprojectmanager/qmakeprojectmanagerconstants.h> +#include "projectexplorerconstants.h" #include <app/app_version.h> #include <coreplugin/basefilewizard.h> #include <coreplugin/icore.h> +#include <cmakeprojectmanager/cmakeprojectconstants.h> #include <projectexplorer/projectexplorerconstants.h> #include <projectexplorer/customwizard/customwizard.h> #include <projectexplorer/selectablefilesmodel.h> +#include <qmakeprojectmanager/qmakeprojectmanagerconstants.h> #include <utils/algorithm.h> #include <utils/fileutils.h> @@ -43,9 +45,11 @@ #include <utils/wizard.h> #include <QApplication> +#include <QComboBox> #include <QDebug> #include <QDir> #include <QFileInfo> +#include <QLineEdit> #include <QPainter> #include <QPixmap> #include <QStyle> @@ -53,10 +57,9 @@ #include <QWizardPage> using namespace Core; -using namespace ProjectExplorer; using namespace Utils; -namespace QmakeProjectManager { +namespace ProjectExplorer { namespace Internal { class SimpleProjectWizardDialog; @@ -72,10 +75,14 @@ public: void cleanupPage() override { m_filesWidget->cancelParsing(); } FilePaths selectedFiles() const { return m_filesWidget->selectedFiles(); } FilePaths selectedPaths() const { return m_filesWidget->selectedPaths(); } + QString qtModules() const { return m_qtModules; } + QString buildSystem() const { return m_buildSystem; } private: SimpleProjectWizardDialog *m_simpleProjectWizardDialog; SelectableFilesWidget *m_filesWidget; + QString m_qtModules; + QString m_buildSystem; }; FilesSelectionWizardPage::FilesSelectionWizardPage(SimpleProjectWizardDialog *simpleProjectWizard) @@ -83,6 +90,31 @@ FilesSelectionWizardPage::FilesSelectionWizardPage(SimpleProjectWizardDialog *si m_filesWidget(new SelectableFilesWidget(this)) { auto layout = new QVBoxLayout(this); + { + auto hlayout = new QHBoxLayout; + hlayout->addWidget(new QLabel("Qt modules", this)); + auto lineEdit = new QLineEdit("core gui widgets", this); + connect(lineEdit, &QLineEdit::editingFinished, this, [this, lineEdit]{ + m_qtModules = lineEdit->text(); + }); + m_qtModules = lineEdit->text(); + hlayout->addWidget(lineEdit); + layout->addLayout(hlayout); + } + + { + auto hlayout = new QHBoxLayout; + hlayout->addWidget(new QLabel("Build system", this)); + auto comboBox = new QComboBox(this); + connect(comboBox, &QComboBox::currentTextChanged, this, [this](const QString &bs){ + m_buildSystem = bs; + }); + comboBox->addItems(QStringList() << "qmake" << "cmake"); + comboBox->setEditable(false); + comboBox->setCurrentText("qmake"); + hlayout->addWidget(comboBox); + layout->addLayout(hlayout); + } layout->addWidget(m_filesWidget); m_filesWidget->setBaseDirEditable(false); @@ -119,6 +151,8 @@ public: void setPath(const QString &path) { m_firstPage->setPath(path); } FilePaths selectedFiles() const { return m_secondPage->selectedFiles(); } FilePaths selectedPaths() const { return m_secondPage->selectedPaths(); } + QString qtModules() const { return m_secondPage->qtModules(); } + QString buildSystem() const { return m_secondPage->buildSystem(); } QString projectName() const { return m_firstPage->fileName(); } FileWizardPage *m_firstPage; @@ -133,14 +167,15 @@ void FilesSelectionWizardPage::initializePage() SimpleProjectWizard::SimpleProjectWizard() { - setSupportedProjectTypes({Constants::QMAKEPROJECT_ID}); - setIcon(QIcon(QLatin1String(":/qmakeprojectmanager/images/qmakeprojectmanager.png"))); - setDisplayName(tr("Import as qmake Project (Limited Functionality)")); + setSupportedProjectTypes({QmakeProjectManager::Constants::QMAKEPROJECT_ID, + CMakeProjectManager::Constants::CMAKEPROJECT_ID}); + setIcon(QIcon(QLatin1String(":/projectexplorer/images/importasproject.png"))); + setDisplayName(tr("Import as qmake or cmake Project (Limited Functionality)")); setId("Z.DummyProFile"); setDescription(tr("Imports existing projects that do not use qmake, CMake or Autotools.<p>" - "This creates a qmake .pro file that allows you to use %1 as a code editor " + "This creates a project file that allows you to use %1 as a code editor " "and as a launcher for debugging and analyzing tools. " - "If you want to build the project, you might need to edit the generated .pro file.") + "If you want to build the project, you might need to edit the generated project file.") .arg(Core::Constants::IDE_DISPLAY_NAME)); setCategory(ProjectExplorer::Constants::IMPORT_WIZARD_CATEGORY); setDisplayCategory(ProjectExplorer::Constants::IMPORT_WIZARD_CATEGORY_DISPLAY); @@ -159,12 +194,10 @@ BaseFileWizard *SimpleProjectWizard::create(QWidget *parent, return wizard; } -GeneratedFiles SimpleProjectWizard::generateFiles(const QWizard *w, - QString *errorMessage) const +GeneratedFiles generateQmakeFiles(const SimpleProjectWizardDialog *wizard, + QString *errorMessage) { Q_UNUSED(errorMessage) - - auto wizard = qobject_cast<const SimpleProjectWizardDialog *>(w); const QString projectPath = wizard->path(); const QDir dir(projectPath); const QString projectName = wizard->projectName(); @@ -209,15 +242,112 @@ GeneratedFiles SimpleProjectWizard::generateFiles(const QWizard *w, + " This file was created for editing the project sources only.\n" "# You may attempt to use it for building too, by modifying this file here.\n\n" "#TARGET = " + projectName + "\n\n" + "QT = " + wizard->qtModules() + "\n\n" + proHeaders + "\n\n" + proSources + "\n\n" + proIncludes + "\n\n" "#DEFINES = \n\n" - ); + ); + + return GeneratedFiles{generatedProFile}; +} + +GeneratedFiles generateCmakeFiles(const SimpleProjectWizardDialog *wizard, + QString *errorMessage) +{ + Q_UNUSED(errorMessage) + const QString projectPath = wizard->path(); + const QDir dir(projectPath); + const QString projectName = wizard->projectName(); + const QString projectFileName = QFileInfo(dir, "CMakeLists.txt").absoluteFilePath(); + const QStringList paths = Utils::transform(wizard->selectedPaths(), &FilePath::toString); + + MimeType headerType = Utils::mimeTypeForName("text/x-chdr"); + + QStringList nameFilters = headerType.globPatterns(); + + QString includes = "include_directories(\n"; + bool haveIncludes = false; + for (const QString &path : paths) { + QFileInfo fileInfo(path); + QDir thisDir(fileInfo.absoluteFilePath()); + if (!thisDir.entryList(nameFilters, QDir::Files).isEmpty()) { + QString relative = dir.relativeFilePath(path); + if (!relative.isEmpty()) { + includes.append(" " + relative + "\n"); + haveIncludes = true; + } + } + } + if (haveIncludes) + includes += ")"; + else + includes.clear(); + + QString srcs = "set (SRCS\n"; + for (const FilePath &fileName : wizard->selectedFiles()) + srcs += " " + dir.relativeFilePath(fileName.toString()) + "\n"; + srcs += ")\n"; + + QString components = "find_package(Qt5 COMPONENTS"; + QString libs = "target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE"; + bool haveQtModules = false; + for (QString c : wizard->qtModules().split(' ')) { + if (c.isEmpty()) + continue; + c[0] = c[0].toUpper(); + libs += " Qt5::" + c; + components += " " + c; + haveQtModules = true; + } + if (haveQtModules) { + libs += ")\n"; + components += " REQUIRED)"; + } else { + libs.clear(); + components.clear(); + } + + GeneratedFile generatedProFile(projectFileName); + generatedProFile.setAttributes(Core::GeneratedFile::OpenProjectAttribute); + generatedProFile.setContents( + "# Created by and for " + QLatin1String(Core::Constants::IDE_DISPLAY_NAME) + + " This file was created for editing the project sources only.\n" + "# You may attempt to use it for building too, by modifying this file here.\n\n" + "cmake_minimum_required(VERSION 3.5)\n" + "project("+ projectName +")\n\n" + "set(CMAKE_INCLUDE_CURRENT_DIR ON)\n" + "set(CMAKE_AUTOUIC ON)\n" + "set(CMAKE_AUTOMOC ON)\n" + "set(CMAKE_AUTORCC ON)\n" + "set(CMAKE_CXX_STANDARD 11)\n" + "set(CMAKE_CXX_STANDARD_REQUIRED ON)\n" + + components + "\n\n" + + includes + "\n\n" + + srcs + "\n\n" + "add_executable(${CMAKE_PROJECT_NAME} ${SRCS})\n\n" + + libs + ); return GeneratedFiles{generatedProFile}; } +GeneratedFiles SimpleProjectWizard::generateFiles(const QWizard *w, + QString *errorMessage) const +{ + Q_UNUSED(errorMessage) + + auto wizard = qobject_cast<const SimpleProjectWizardDialog *>(w); + if (wizard->buildSystem() == "qmake") + return generateQmakeFiles(wizard, errorMessage); + else if (wizard->buildSystem() == "cmake") + return generateCmakeFiles(wizard, errorMessage); + + if (errorMessage) + *errorMessage = tr("Unknown build system \"%1\"").arg(wizard->buildSystem()); + return {}; +} + bool SimpleProjectWizard::postGenerateFiles(const QWizard *w, const GeneratedFiles &l, QString *errorMessage) const { @@ -226,6 +356,6 @@ bool SimpleProjectWizard::postGenerateFiles(const QWizard *w, const GeneratedFil } } // namespace Internal -} // namespace QmakeProjectManager +} // namespace GenericProjectManager #include "simpleprojectwizard.moc" diff --git a/src/plugins/qmakeprojectmanager/wizards/simpleprojectwizard.h b/src/plugins/projectexplorer/simpleprojectwizard.h index ee1f794c3e0..d4bcce5616f 100644 --- a/src/plugins/qmakeprojectmanager/wizards/simpleprojectwizard.h +++ b/src/plugins/projectexplorer/simpleprojectwizard.h @@ -27,7 +27,7 @@ #include <coreplugin/basefilewizardfactory.h> -namespace QmakeProjectManager { +namespace ProjectExplorer { namespace Internal { class SimpleProjectWizard : public Core::BaseFileWizardFactory @@ -45,4 +45,4 @@ private: }; } // namespace Internal -} // namespace QmakeProjectManager +} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/target.cpp b/src/plugins/projectexplorer/target.cpp index 177e4011f55..96bff5606b4 100644 --- a/src/plugins/projectexplorer/target.cpp +++ b/src/plugins/projectexplorer/target.cpp @@ -329,6 +329,7 @@ void Target::setActiveBuildConfiguration(BuildConfiguration *bc) bc != d->m_activeBuildConfiguration)) { d->m_activeBuildConfiguration = bc; emit activeBuildConfigurationChanged(d->m_activeBuildConfiguration); + ProjectExplorerPlugin::updateActions(); } } @@ -465,6 +466,7 @@ void Target::setActiveRunConfiguration(RunConfiguration *rc) rc != d->m_activeRunConfiguration)) { d->m_activeRunConfiguration = rc; emit activeRunConfigurationChanged(d->m_activeRunConfiguration); + ProjectExplorerPlugin::updateActions(); } updateDeviceState(); } diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index 0bd173a742f..eb841cbc672 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -168,6 +168,12 @@ static bool supportsNodeAction(ProjectAction action, const Node *node) return false; } +static QString buildKeyValue(const QJsonObject &product) +{ + return product.value("name").toString() + '.' + + product.value("multiplex-configuration-id").toString(); +} + QbsBuildSystem::QbsBuildSystem(QbsBuildConfiguration *bc) : BuildSystem(bc->target()), m_session(new QbsSession(this)), @@ -692,13 +698,13 @@ void QbsBuildSystem::updateDocuments() OpTimer opTimer("updateDocuments"); const FilePath buildDir = FilePath::fromString( m_projectData.value("build-directory").toString()); - const auto filePaths = transform<QVector<FilePath>>( + const auto filePaths = transform<QSet<FilePath>>( m_projectData.value("build-system-files").toArray(), [](const QJsonValue &v) { return FilePath::fromString(v.toString()); }); // A changed qbs file (project, module etc) should trigger a re-parse, but not if // the file was generated by qbs itself, in which case that might cause an infinite loop. - const QVector<FilePath> nonBuildDirFilePaths = filtered(filePaths, + const QSet<FilePath> nonBuildDirFilePaths = filtered(filePaths, [buildDir](const FilePath &p) { return !p.isChildOf(buildDir); }); @@ -905,7 +911,7 @@ static RawProjectParts generateProjectParts( rpp.setProjectFileLocation(location.value("file-path").toString(), location.value("line").toInt(), location.value("column").toInt()); - rpp.setBuildSystemTarget(productName); + rpp.setBuildSystemTarget(buildKeyValue(prd)); rpp.setBuildTargetType(prd.value("is-runnable").toBool() ? BuildTargetType::Executable : BuildTargetType::Library); @@ -1067,8 +1073,7 @@ void QbsBuildSystem::updateApplicationTargets() } } BuildTargetInfo bti; - bti.buildKey = productData.value("name").toString() + '.' - + productData.value("multiplex-configuration-id").toString(); + bti.buildKey = buildKeyValue(productData); bti.targetFilePath = FilePath::fromString(targetFile); bti.projectFilePath = FilePath::fromString(projectFile); bti.isQtcRunnable = isQtcRunnable; // Fixed up below. diff --git a/src/plugins/qmakeprojectmanager/CMakeLists.txt b/src/plugins/qmakeprojectmanager/CMakeLists.txt index b87a17a66a6..f61d50d0c3d 100644 --- a/src/plugins/qmakeprojectmanager/CMakeLists.txt +++ b/src/plugins/qmakeprojectmanager/CMakeLists.txt @@ -40,7 +40,6 @@ add_qtc_plugin(QmakeProjectManager qmakestep.cpp qmakestep.h wizards/qtprojectparameters.cpp wizards/qtprojectparameters.h wizards/qtwizard.cpp wizards/qtwizard.h - wizards/simpleprojectwizard.cpp wizards/simpleprojectwizard.h wizards/subdirsprojectwizard.cpp wizards/subdirsprojectwizard.h wizards/subdirsprojectwizarddialog.cpp wizards/subdirsprojectwizarddialog.h wizards/wizards.qrc diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index a807adf1d69..93a95192688 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -262,9 +262,9 @@ void QmakeBuildSystem::updateCodeModels() void QmakeBuildSystem::updateDocuments() { - QVector<FilePath> projectDocuments; + QSet<FilePath> projectDocuments; project()->rootProjectNode()->forEachProjectNode([&projectDocuments](const ProjectNode *n) { - projectDocuments << n->filePath(); + projectDocuments.insert(n->filePath()); }); project()->setExtraProjectFiles(projectDocuments); } diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.pro b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.pro index cc4f27ae78a..90a6a78a8fe 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.pro +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.pro @@ -21,7 +21,6 @@ HEADERS += \ wizards/qtwizard.h \ wizards/subdirsprojectwizard.h \ wizards/subdirsprojectwizarddialog.h \ - wizards/simpleprojectwizard.h \ qmakeprojectmanagerconstants.h \ qmakestep.h \ externaleditors.h \ @@ -50,7 +49,6 @@ SOURCES += \ wizards/qtwizard.cpp \ wizards/subdirsprojectwizard.cpp \ wizards/subdirsprojectwizarddialog.cpp \ - wizards/simpleprojectwizard.cpp \ qmakestep.cpp \ externaleditors.cpp \ qmakebuildconfiguration.cpp \ diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.qbs b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.qbs index 4955ca43a17..e46f7c90b45 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.qbs +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.qbs @@ -77,7 +77,6 @@ Project { "qtwizard.cpp", "qtwizard.h", "subdirsprojectwizard.cpp", "subdirsprojectwizard.h", "subdirsprojectwizarddialog.cpp", "subdirsprojectwizarddialog.h", - "simpleprojectwizard.cpp", "simpleprojectwizard.h", "wizards.qrc" ] } diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.qrc b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.qrc index 87248770da4..8e13ebeeb5d 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanager.qrc +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanager.qrc @@ -3,7 +3,5 @@ <file>images/dark_headers.png</file> <file>images/dark_sources.png</file> <file>images/dark_unknown.png</file> - <file>images/qmakeprojectmanager.png</file> - <file>images/qmakeprojectmanager@2x.png</file> </qresource> </RCC> diff --git a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp index 054871bf37c..e1899418dd9 100644 --- a/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeprojectmanagerplugin.cpp @@ -32,7 +32,6 @@ #include "qmakestep.h" #include "qmakemakestep.h" #include "qmakebuildconfiguration.h" -#include "wizards/simpleprojectwizard.h" #include "wizards/subdirsprojectwizard.h" #include "customwidgetwizard/customwidgetwizard.h" #include "qmakeprojectmanagerconstants.h" @@ -168,8 +167,7 @@ bool QmakeProjectManagerPlugin::initialize(const QStringList &arguments, QString IWizardFactory::registerFactoryCreator([] { return QList<IWizardFactory *> { new SubdirsProjectWizard, - new CustomWidgetWizard, - new SimpleProjectWizard + new CustomWidgetWizard }; }); diff --git a/src/plugins/qmldesigner/components/componentcore/findimplementation.cpp b/src/plugins/qmldesigner/components/componentcore/findimplementation.cpp index 7cc1d9d7124..a1d7b5fad43 100644 --- a/src/plugins/qmldesigner/components/componentcore/findimplementation.cpp +++ b/src/plugins/qmldesigner/components/componentcore/findimplementation.cpp @@ -35,6 +35,8 @@ #include <qmljs/qmljsscopebuilder.h> #include <qmljs/qmljsmodelmanagerinterface.h> +#include <QDebug> + namespace { using namespace QmlJS; @@ -42,7 +44,7 @@ using namespace QmlJS; class FindImplementationVisitor: protected AST::Visitor { public: - using Results = QList<AST::SourceLocation>; + using Results = QList<SourceLocation>; FindImplementationVisitor(const Document::Ptr &doc, const ContextPtr &context) : m_document(doc) @@ -66,13 +68,13 @@ public: } protected: - QString textAt(const AST::SourceLocation &location) + QString textAt(const SourceLocation &location) { return m_document->source().mid(location.offset, location.length); } - QString textAt(const AST::SourceLocation &from, - const AST::SourceLocation &to) + QString textAt(const SourceLocation &from, + const SourceLocation &to) { return m_document->source().mid(from.offset, to.end() - from.begin()); } @@ -206,7 +208,10 @@ protected: return false; } - + void throwRecursionDepthError() override + { + qWarning("Warning: Hit maximum recursion depth while visiting AST in FindImplementationVisitor"); + } private: bool checkTypeName(AST::UiQualifiedId *id) { @@ -223,7 +228,7 @@ private: } Results m_implemenations; - AST::SourceLocation m_formLocation; + SourceLocation m_formLocation; Document::Ptr m_document; ContextPtr m_context; @@ -281,7 +286,7 @@ QList<QmlJSEditor::FindReferences::Usage> FindImplementation::run(const QString FindImplementationVisitor visitor(document, context); FindImplementationVisitor::Results results = visitor(typeName, itemName, targetValue); - foreach (const AST::SourceLocation &location, results) { + foreach (const SourceLocation &location, results) { usages.append(QmlJSEditor::FindReferences::Usage(fileName, matchingLine(location.offset, document->source()), location.startLine, location.startColumn - 1, location.length)); diff --git a/src/plugins/qmldesigner/components/edit3d/edit3d.qrc b/src/plugins/qmldesigner/components/edit3d/edit3d.qrc index 1719b8ed63a..c0456890cd5 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3d.qrc +++ b/src/plugins/qmldesigner/components/edit3d/edit3d.qrc @@ -1,34 +1,34 @@ <RCC> <qresource prefix="/edit3d"> - <file>images/edit_light_off.png</file> - <file>images/edit_light_off@2x.png</file> - <file>images/edit_light_on.png</file> - <file>images/edit_light_on@2x.png</file> - <file>images/fit_active.png</file> - <file>images/fit_active@2x.png</file> <file>images/global.png</file> <file>images/global@2x.png</file> - <file>images/group_selection_selected.png</file> - <file>images/group_selection_selected@2x.png</file> - <file>images/item_selection_selected.png</file> - <file>images/item_selection_selected@2x.png</file> <file>images/local.png</file> <file>images/local@2x.png</file> - <file>images/move_active.png</file> - <file>images/move_active@2x.png</file> - <file>images/move_selected.png</file> - <file>images/move_selected@2x.png</file> - <file>images/ortho.png</file> - <file>images/ortho@2x.png</file> - <file>images/persp.png</file> - <file>images/persp@2x.png</file> - <file>images/rotate_active.png</file> - <file>images/rotate_active@2x.png</file> - <file>images/rotate_selected.png</file> - <file>images/rotate_selected@2x.png</file> - <file>images/scale_active.png</file> - <file>images/scale_active@2x.png</file> - <file>images/scale_selected.png</file> - <file>images/scale_selected@2x.png</file> + <file>images/edit_light_off.png</file> + <file>images/edit_light_off@2x.png</file> + <file>images/edit_light_on.png</file> + <file>images/edit_light_on@2x.png</file> + <file>images/fit_selected.png</file> + <file>images/fit_selected@2x.png</file> + <file>images/move_off.png</file> + <file>images/move_off@2x.png</file> + <file>images/move_on.png</file> + <file>images/move_on@2x.png</file> + <file>images/perspective_camera.png</file> + <file>images/perspective_camera@2x.png</file> + <file>images/rotate_off.png</file> + <file>images/rotate_off@2x.png</file> + <file>images/rotate_on.png</file> + <file>images/rotate_on@2x.png</file> + <file>images/scale_off.png</file> + <file>images/scale_off@2x.png</file> + <file>images/scale_on.png</file> + <file>images/scale_on@2x.png</file> + <file>images/select_group.png</file> + <file>images/select_group@2x.png</file> + <file>images/select_item.png</file> + <file>images/select_item@2x.png</file> + <file>images/orthographic_camera.png</file> + <file>images/orthographic_camera@2x.png</file> </qresource> </RCC> diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp index 8a1c049907b..37c80246a51 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp @@ -117,9 +117,7 @@ void Edit3DCanvas::dropEvent(QDropEvent *e) { Q_UNUSED(e) - QmlVisualNode::createQmlVisualNode(m_parent->view(), m_itemLibraryEntry, m_activeScene, {}); + QmlVisualNode::createQml3DNode(m_parent->view(), m_itemLibraryEntry, m_activeScene); } } - - diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.h b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.h index 48b05789476..2243a466dd4 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.h @@ -59,7 +59,7 @@ protected: private: QPointer<Edit3DWidget> m_parent; QImage m_image; - qint32 m_activeScene; + qint32 m_activeScene = -1; ItemLibraryEntry m_itemLibraryEntry; }; diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.h b/src/plugins/qmldesigner/components/edit3d/edit3dview.h index 64ffedb1540..bf6519dd7cf 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.h @@ -73,15 +73,15 @@ private: QPointer<Edit3DWidget> m_edit3DWidget; QVector<Edit3DAction *> m_leftActions; QVector<Edit3DAction *> m_rightActions; - Edit3DAction *m_selectionModeAction; - Edit3DAction *m_moveToolAction; - Edit3DAction *m_rotateToolAction; - Edit3DAction *m_scaleToolAction; - Edit3DAction *m_fitAction; - Edit3DAction *m_cameraModeAction; - Edit3DAction *m_orientationModeAction; - Edit3DAction *m_editLightAction; - Edit3DAction *m_resetAction; + Edit3DAction *m_selectionModeAction = nullptr; + Edit3DAction *m_moveToolAction = nullptr; + Edit3DAction *m_rotateToolAction = nullptr; + Edit3DAction *m_scaleToolAction = nullptr; + Edit3DAction *m_fitAction = nullptr; + Edit3DAction *m_cameraModeAction = nullptr; + Edit3DAction *m_orientationModeAction = nullptr; + Edit3DAction *m_editLightAction = nullptr; + Edit3DAction *m_resetAction = nullptr; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/images/edit_light_off.png b/src/plugins/qmldesigner/components/edit3d/images/edit_light_off.png Binary files differindex 73e6e92374b..81ff3ba1e61 100644 --- a/src/plugins/qmldesigner/components/edit3d/images/edit_light_off.png +++ b/src/plugins/qmldesigner/components/edit3d/images/edit_light_off.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/edit_light_off@2x.png b/src/plugins/qmldesigner/components/edit3d/images/edit_light_off@2x.png Binary files differindex 5166264e16d..e25d6699b58 100644 --- a/src/plugins/qmldesigner/components/edit3d/images/edit_light_off@2x.png +++ b/src/plugins/qmldesigner/components/edit3d/images/edit_light_off@2x.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/edit_light_on.png b/src/plugins/qmldesigner/components/edit3d/images/edit_light_on.png Binary files differindex 7660c285460..e0bde1c5f74 100644 --- a/src/plugins/qmldesigner/components/edit3d/images/edit_light_on.png +++ b/src/plugins/qmldesigner/components/edit3d/images/edit_light_on.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/edit_light_on@2x.png b/src/plugins/qmldesigner/components/edit3d/images/edit_light_on@2x.png Binary files differindex 836bd2a0d59..37e5047cd77 100644 --- a/src/plugins/qmldesigner/components/edit3d/images/edit_light_on@2x.png +++ b/src/plugins/qmldesigner/components/edit3d/images/edit_light_on@2x.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/fit_active.png b/src/plugins/qmldesigner/components/edit3d/images/fit_active.png Binary files differdeleted file mode 100644 index 056e9ec3c8b..00000000000 --- a/src/plugins/qmldesigner/components/edit3d/images/fit_active.png +++ /dev/null diff --git a/src/plugins/qmldesigner/components/edit3d/images/fit_active@2x.png b/src/plugins/qmldesigner/components/edit3d/images/fit_active@2x.png Binary files differdeleted file mode 100644 index 4b05f83d460..00000000000 --- a/src/plugins/qmldesigner/components/edit3d/images/fit_active@2x.png +++ /dev/null diff --git a/src/plugins/qmldesigner/components/edit3d/images/fit_selected.png b/src/plugins/qmldesigner/components/edit3d/images/fit_selected.png Binary files differnew file mode 100644 index 00000000000..b8c7297f4e8 --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/images/fit_selected.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/fit_selected@2x.png b/src/plugins/qmldesigner/components/edit3d/images/fit_selected@2x.png Binary files differnew file mode 100644 index 00000000000..278e832f1ef --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/images/fit_selected@2x.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/global.png b/src/plugins/qmldesigner/components/edit3d/images/global.png Binary files differindex 1bd09c680ac..abba1f5d277 100644 --- a/src/plugins/qmldesigner/components/edit3d/images/global.png +++ b/src/plugins/qmldesigner/components/edit3d/images/global.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/global@2x.png b/src/plugins/qmldesigner/components/edit3d/images/global@2x.png Binary files differindex a2a857fb10c..1a2fc06ee33 100644 --- a/src/plugins/qmldesigner/components/edit3d/images/global@2x.png +++ b/src/plugins/qmldesigner/components/edit3d/images/global@2x.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/group_selection_selected.png b/src/plugins/qmldesigner/components/edit3d/images/group_selection_selected.png Binary files differdeleted file mode 100644 index bfb848aa384..00000000000 --- a/src/plugins/qmldesigner/components/edit3d/images/group_selection_selected.png +++ /dev/null diff --git a/src/plugins/qmldesigner/components/edit3d/images/group_selection_selected@2x.png b/src/plugins/qmldesigner/components/edit3d/images/group_selection_selected@2x.png Binary files differdeleted file mode 100644 index f18895dc440..00000000000 --- a/src/plugins/qmldesigner/components/edit3d/images/group_selection_selected@2x.png +++ /dev/null diff --git a/src/plugins/qmldesigner/components/edit3d/images/item_selection_selected.png b/src/plugins/qmldesigner/components/edit3d/images/item_selection_selected.png Binary files differdeleted file mode 100644 index 2b685d3d00a..00000000000 --- a/src/plugins/qmldesigner/components/edit3d/images/item_selection_selected.png +++ /dev/null diff --git a/src/plugins/qmldesigner/components/edit3d/images/item_selection_selected@2x.png b/src/plugins/qmldesigner/components/edit3d/images/item_selection_selected@2x.png Binary files differdeleted file mode 100644 index eb0051a606e..00000000000 --- a/src/plugins/qmldesigner/components/edit3d/images/item_selection_selected@2x.png +++ /dev/null diff --git a/src/plugins/qmldesigner/components/edit3d/images/local.png b/src/plugins/qmldesigner/components/edit3d/images/local.png Binary files differindex 0a608f6816e..94b2f97c4ce 100644 --- a/src/plugins/qmldesigner/components/edit3d/images/local.png +++ b/src/plugins/qmldesigner/components/edit3d/images/local.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/local@2x.png b/src/plugins/qmldesigner/components/edit3d/images/local@2x.png Binary files differindex a5c931e750f..f4f95e4e3a7 100644 --- a/src/plugins/qmldesigner/components/edit3d/images/local@2x.png +++ b/src/plugins/qmldesigner/components/edit3d/images/local@2x.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/move_active.png b/src/plugins/qmldesigner/components/edit3d/images/move_active.png Binary files differdeleted file mode 100644 index d21d290349c..00000000000 --- a/src/plugins/qmldesigner/components/edit3d/images/move_active.png +++ /dev/null diff --git a/src/plugins/qmldesigner/components/edit3d/images/move_active@2x.png b/src/plugins/qmldesigner/components/edit3d/images/move_active@2x.png Binary files differdeleted file mode 100644 index bd0827f918c..00000000000 --- a/src/plugins/qmldesigner/components/edit3d/images/move_active@2x.png +++ /dev/null diff --git a/src/plugins/qmldesigner/components/edit3d/images/move_off.png b/src/plugins/qmldesigner/components/edit3d/images/move_off.png Binary files differnew file mode 100644 index 00000000000..1c07c7cf6d8 --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/images/move_off.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/move_off@2x.png b/src/plugins/qmldesigner/components/edit3d/images/move_off@2x.png Binary files differnew file mode 100644 index 00000000000..ac943afe1a7 --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/images/move_off@2x.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/move_on.png b/src/plugins/qmldesigner/components/edit3d/images/move_on.png Binary files differnew file mode 100644 index 00000000000..c23b711b3ff --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/images/move_on.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/move_on@2x.png b/src/plugins/qmldesigner/components/edit3d/images/move_on@2x.png Binary files differnew file mode 100644 index 00000000000..e0065301727 --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/images/move_on@2x.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/move_selected.png b/src/plugins/qmldesigner/components/edit3d/images/move_selected.png Binary files differdeleted file mode 100644 index 5c8ce42a758..00000000000 --- a/src/plugins/qmldesigner/components/edit3d/images/move_selected.png +++ /dev/null diff --git a/src/plugins/qmldesigner/components/edit3d/images/move_selected@2x.png b/src/plugins/qmldesigner/components/edit3d/images/move_selected@2x.png Binary files differdeleted file mode 100644 index fad362a3e6a..00000000000 --- a/src/plugins/qmldesigner/components/edit3d/images/move_selected@2x.png +++ /dev/null diff --git a/src/plugins/qmldesigner/components/edit3d/images/ortho.png b/src/plugins/qmldesigner/components/edit3d/images/ortho.png Binary files differdeleted file mode 100644 index 35b36203fa2..00000000000 --- a/src/plugins/qmldesigner/components/edit3d/images/ortho.png +++ /dev/null diff --git a/src/plugins/qmldesigner/components/edit3d/images/ortho@2x.png b/src/plugins/qmldesigner/components/edit3d/images/ortho@2x.png Binary files differdeleted file mode 100644 index 443c73e444b..00000000000 --- a/src/plugins/qmldesigner/components/edit3d/images/ortho@2x.png +++ /dev/null diff --git a/src/plugins/qmldesigner/components/edit3d/images/orthographic_camera.png b/src/plugins/qmldesigner/components/edit3d/images/orthographic_camera.png Binary files differnew file mode 100644 index 00000000000..844bf8edf77 --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/images/orthographic_camera.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/orthographic_camera@2x.png b/src/plugins/qmldesigner/components/edit3d/images/orthographic_camera@2x.png Binary files differnew file mode 100644 index 00000000000..69a18a2a82f --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/images/orthographic_camera@2x.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/persp.png b/src/plugins/qmldesigner/components/edit3d/images/persp.png Binary files differdeleted file mode 100644 index 9a48e763996..00000000000 --- a/src/plugins/qmldesigner/components/edit3d/images/persp.png +++ /dev/null diff --git a/src/plugins/qmldesigner/components/edit3d/images/persp@2x.png b/src/plugins/qmldesigner/components/edit3d/images/persp@2x.png Binary files differdeleted file mode 100644 index 88a4eab9c6a..00000000000 --- a/src/plugins/qmldesigner/components/edit3d/images/persp@2x.png +++ /dev/null diff --git a/src/plugins/qmldesigner/components/edit3d/images/perspective_camera.png b/src/plugins/qmldesigner/components/edit3d/images/perspective_camera.png Binary files differnew file mode 100644 index 00000000000..2461d8be5e7 --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/images/perspective_camera.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/perspective_camera@2x.png b/src/plugins/qmldesigner/components/edit3d/images/perspective_camera@2x.png Binary files differnew file mode 100644 index 00000000000..321dcfb5ea8 --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/images/perspective_camera@2x.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/rotate_active.png b/src/plugins/qmldesigner/components/edit3d/images/rotate_active.png Binary files differdeleted file mode 100644 index bdabaf30285..00000000000 --- a/src/plugins/qmldesigner/components/edit3d/images/rotate_active.png +++ /dev/null diff --git a/src/plugins/qmldesigner/components/edit3d/images/rotate_active@2x.png b/src/plugins/qmldesigner/components/edit3d/images/rotate_active@2x.png Binary files differdeleted file mode 100644 index 8c81f409d32..00000000000 --- a/src/plugins/qmldesigner/components/edit3d/images/rotate_active@2x.png +++ /dev/null diff --git a/src/plugins/qmldesigner/components/edit3d/images/rotate_off.png b/src/plugins/qmldesigner/components/edit3d/images/rotate_off.png Binary files differnew file mode 100644 index 00000000000..6cd93d946d0 --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/images/rotate_off.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/rotate_off@2x.png b/src/plugins/qmldesigner/components/edit3d/images/rotate_off@2x.png Binary files differnew file mode 100644 index 00000000000..105a9132143 --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/images/rotate_off@2x.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/rotate_on.png b/src/plugins/qmldesigner/components/edit3d/images/rotate_on.png Binary files differnew file mode 100644 index 00000000000..7e680b5a85e --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/images/rotate_on.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/rotate_on@2x.png b/src/plugins/qmldesigner/components/edit3d/images/rotate_on@2x.png Binary files differnew file mode 100644 index 00000000000..ee93a691381 --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/images/rotate_on@2x.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/rotate_selected.png b/src/plugins/qmldesigner/components/edit3d/images/rotate_selected.png Binary files differdeleted file mode 100644 index 42dc2763ce4..00000000000 --- a/src/plugins/qmldesigner/components/edit3d/images/rotate_selected.png +++ /dev/null diff --git a/src/plugins/qmldesigner/components/edit3d/images/rotate_selected@2x.png b/src/plugins/qmldesigner/components/edit3d/images/rotate_selected@2x.png Binary files differdeleted file mode 100644 index b6cc48c0533..00000000000 --- a/src/plugins/qmldesigner/components/edit3d/images/rotate_selected@2x.png +++ /dev/null diff --git a/src/plugins/qmldesigner/components/edit3d/images/scale_active.png b/src/plugins/qmldesigner/components/edit3d/images/scale_active.png Binary files differdeleted file mode 100644 index cd63c1d03bc..00000000000 --- a/src/plugins/qmldesigner/components/edit3d/images/scale_active.png +++ /dev/null diff --git a/src/plugins/qmldesigner/components/edit3d/images/scale_active@2x.png b/src/plugins/qmldesigner/components/edit3d/images/scale_active@2x.png Binary files differdeleted file mode 100644 index 0d95e8e8913..00000000000 --- a/src/plugins/qmldesigner/components/edit3d/images/scale_active@2x.png +++ /dev/null diff --git a/src/plugins/qmldesigner/components/edit3d/images/scale_off.png b/src/plugins/qmldesigner/components/edit3d/images/scale_off.png Binary files differnew file mode 100644 index 00000000000..664cb20434b --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/images/scale_off.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/scale_off@2x.png b/src/plugins/qmldesigner/components/edit3d/images/scale_off@2x.png Binary files differnew file mode 100644 index 00000000000..52777e16724 --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/images/scale_off@2x.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/scale_on.png b/src/plugins/qmldesigner/components/edit3d/images/scale_on.png Binary files differnew file mode 100644 index 00000000000..6219923f9ce --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/images/scale_on.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/scale_on@2x.png b/src/plugins/qmldesigner/components/edit3d/images/scale_on@2x.png Binary files differnew file mode 100644 index 00000000000..6dac35fb32e --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/images/scale_on@2x.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/scale_selected.png b/src/plugins/qmldesigner/components/edit3d/images/scale_selected.png Binary files differdeleted file mode 100644 index 4cca7726170..00000000000 --- a/src/plugins/qmldesigner/components/edit3d/images/scale_selected.png +++ /dev/null diff --git a/src/plugins/qmldesigner/components/edit3d/images/scale_selected@2x.png b/src/plugins/qmldesigner/components/edit3d/images/scale_selected@2x.png Binary files differdeleted file mode 100644 index 690cf5f924f..00000000000 --- a/src/plugins/qmldesigner/components/edit3d/images/scale_selected@2x.png +++ /dev/null diff --git a/src/plugins/qmldesigner/components/edit3d/images/select_group.png b/src/plugins/qmldesigner/components/edit3d/images/select_group.png Binary files differnew file mode 100644 index 00000000000..228d8d4d9ac --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/images/select_group.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/select_group@2x.png b/src/plugins/qmldesigner/components/edit3d/images/select_group@2x.png Binary files differnew file mode 100644 index 00000000000..477853d7d5c --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/images/select_group@2x.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/select_item.png b/src/plugins/qmldesigner/components/edit3d/images/select_item.png Binary files differnew file mode 100644 index 00000000000..922a4d4f251 --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/images/select_item.png diff --git a/src/plugins/qmldesigner/components/edit3d/images/select_item@2x.png b/src/plugins/qmldesigner/components/edit3d/images/select_item@2x.png Binary files differnew file mode 100644 index 00000000000..571cc35ee2d --- /dev/null +++ b/src/plugins/qmldesigner/components/edit3d/images/select_item@2x.png diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp index 37c0efc9d7f..a9da5b22f49 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp @@ -125,6 +125,13 @@ void FormEditorView::setupFormEditorItemTree(const QmlItemNode &qmlItemNode) } } else if (qmlItemNode.isFlowView() && qmlItemNode.isRootNode()) { m_scene->addFormEditorItem(qmlItemNode, FormEditorScene::Flow); + + ModelNode node = qmlItemNode.modelNode(); + if (!node.hasAuxiliaryData("width") && !node.hasAuxiliaryData("height")) { + node.setAuxiliaryData("width", 10000); + node.setAuxiliaryData("height", 10000); + } + for (const QmlObjectNode &nextNode : qmlItemNode.allDirectSubNodes()) { if (QmlItemNode::isValidQmlItemNode(nextNode) && nextNode.toQmlItemNode().isFlowItem()) { setupFormEditorItemTree(nextNode.toQmlItemNode()); @@ -384,7 +391,9 @@ void FormEditorView::bindingPropertiesChanged(const QList<BindingProperty> &prop if (target.modelNode().isValid() && target.isFlowTransition()) { FormEditorItem *item = m_scene->itemForQmlItemNode(target.toQmlItemNode()); if (item) { - m_scene->reparentItem(node.toQmlItemNode(), node.toQmlItemNode().modelParentItem()); + const QmlItemNode itemNode = node.toQmlItemNode(); + if (itemNode.hasNodeParent()) + m_scene->reparentItem(itemNode, itemNode.modelParentItem()); m_scene->synchronizeTransformation(item); item->update(); } diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp index ec7e1d782d8..24177ccc6c9 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp @@ -43,6 +43,8 @@ #include <zoomaction.h> #include <toolbox.h> +#include <coreplugin/actionmanager/actionmanager.h> +#include <coreplugin/actionmanager/command.h> #include <coreplugin/icore.h> #include <utils/fileutils.h> @@ -59,6 +61,11 @@ namespace QmlDesigner { FormEditorWidget::FormEditorWidget(FormEditorView *view) : m_formEditorView(view) { + Core::Context context(Constants::C_QMLFORMEDITOR); + m_context = new Core::IContext(this); + m_context->setContext(context); + m_context->setWidget(this); + auto fillLayout = new QVBoxLayout(this); fillLayout->setContentsMargins(0, 0, 0, 0); fillLayout->setSpacing(0); @@ -77,21 +84,19 @@ FormEditorWidget::FormEditorWidget(FormEditorView *view) : m_noSnappingAction->setCheckable(true); m_noSnappingAction->setChecked(true); m_noSnappingAction->setIcon(Icons::NO_SNAPPING.icon()); + registerActionAsCommand(m_noSnappingAction, Constants::FORMEDITOR_NO_SNAPPING, QKeySequence(Qt::Key_T)); - m_snappingAndAnchoringAction = layoutActionGroup->addAction(tr("Snap to parent or sibling items and generate anchors (W).")); - m_snappingAndAnchoringAction->setShortcut(Qt::Key_W); - m_snappingAndAnchoringAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); + m_snappingAndAnchoringAction = layoutActionGroup->addAction(tr("Snap to parent or sibling items and generate anchors")); m_snappingAndAnchoringAction->setCheckable(true); m_snappingAndAnchoringAction->setChecked(true); m_snappingAndAnchoringAction->setIcon(Icons::NO_SNAPPING_AND_ANCHORING.icon()); + registerActionAsCommand(m_snappingAndAnchoringAction, Constants::FORMEDITOR_NO_SNAPPING_AND_ANCHORING, QKeySequence(Qt::Key_W)); - m_snappingAction = layoutActionGroup->addAction(tr("Snap to parent or sibling items but do not generate anchors (E).")); - m_snappingAction->setShortcut(Qt::Key_E); - m_snappingAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); + m_snappingAction = layoutActionGroup->addAction(tr("Snap to parent or sibling items but do not generate anchors")); m_snappingAction->setCheckable(true); m_snappingAction->setChecked(true); m_snappingAction->setIcon(Icons::SNAPPING.icon()); - + registerActionAsCommand(m_snappingAction, Constants::FORMEDITOR_SNAPPING, QKeySequence(Qt::Key_E)); addActions(layoutActionGroup->actions()); upperActions.append(layoutActionGroup->actions()); @@ -101,12 +106,12 @@ FormEditorWidget::FormEditorWidget(FormEditorView *view) : addAction(separatorAction); upperActions.append(separatorAction); - m_showBoundingRectAction = new QAction(tr("Show bounding rectangles and stripes for empty items (A)."), this); - m_showBoundingRectAction->setShortcut(Qt::Key_A); - m_showBoundingRectAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); + m_showBoundingRectAction = new QAction(Utils::Icons::BOUNDING_RECT.icon(), + tr("Show bounding rectangles and stripes for empty items"), + this); m_showBoundingRectAction->setCheckable(true); m_showBoundingRectAction->setChecked(false); - m_showBoundingRectAction->setIcon(Utils::Icons::BOUNDING_RECT.icon()); + registerActionAsCommand(m_showBoundingRectAction, Constants::FORMEDITOR_NO_SHOW_BOUNDING_RECTANGLE, QKeySequence(Qt::Key_A)); addAction(m_showBoundingRectAction.data()); upperActions.append(m_showBoundingRectAction.data()); @@ -155,10 +160,8 @@ FormEditorWidget::FormEditorWidget(FormEditorView *view) : upperActions.append(m_zoomAction.data()); m_toolBox->addRightSideAction(m_zoomAction.data()); - m_resetAction = new QAction(tr("Reset view (R)."), this); - m_resetAction->setShortcut(Qt::Key_R); - m_resetAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); - m_resetAction->setIcon(Utils::Icons::RESET_TOOLBAR.icon()); + m_resetAction = new QAction(Utils::Icons::RESET_TOOLBAR.icon(), tr("Reset view"), this); + registerActionAsCommand(m_resetAction, Constants::FORMEDITOR_REFRESH, QKeySequence(Qt::Key_R)); addAction(m_resetAction.data()); upperActions.append(m_resetAction.data()); @@ -207,6 +210,15 @@ void FormEditorWidget::changeBackgound(const QColor &color) m_graphicsView->activateColoredBackground(color); } +void FormEditorWidget::registerActionAsCommand(QAction *action, Core::Id id, const QKeySequence &keysequence) +{ + Core::Context context(Constants::C_QMLFORMEDITOR); + + Core::Command *command = Core::ActionManager::registerAction(action, id, context); + command->setDefaultKeySequence(keysequence); + command->augmentActionWithShortcutToolTip(action); +} + void FormEditorWidget::wheelEvent(QWheelEvent *event) { if (event->modifiers().testFlag(Qt::ControlModifier)) { diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.h b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.h index f7efbf60c05..f8cd0cd1a8d 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.h +++ b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.h @@ -98,6 +98,7 @@ private: void changeRootItemWidth(const QString &widthText); void changeRootItemHeight(const QString &heightText); void changeBackgound(const QColor &color); + void registerActionAsCommand(QAction *action, Core::Id id, const QKeySequence &keysequence); QPointer<FormEditorView> m_formEditorView; QPointer<FormEditorGraphicsView> m_graphicsView; @@ -115,6 +116,7 @@ private: QPointer<Option3DAction> m_option3DAction; QPointer<QAction> m_resetAction; QPointer<DocumentWarningWidget> m_documentErrorWidget; + Core::IContext *m_context = nullptr; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/importmanager/importswidget.cpp b/src/plugins/qmldesigner/components/importmanager/importswidget.cpp index 07ada7c8588..5f10c36bc96 100644 --- a/src/plugins/qmldesigner/components/importmanager/importswidget.cpp +++ b/src/plugins/qmldesigner/components/importmanager/importswidget.cpp @@ -27,6 +27,9 @@ #include "importlabel.h" #include "importmanagercombobox.h" +#include <designdocument.h> +#include <qmldesignerplugin.h> + #include <utils/algorithm.h> #include <QVBoxLayout> @@ -90,7 +93,22 @@ void ImportsWidget::setPossibleImports(QList<Import> possibleImports) { Utils::sort(possibleImports, importLess); m_addImportComboBox->clear(); - foreach (const Import &possibleImport, possibleImports) { + + const DesignDocument *designDocument = QmlDesignerPlugin::instance()->currentDesignDocument(); + const bool isQtForMCUs = designDocument && designDocument->isQtForMCUsProject(); + + QList<Import> filteredImports; + + const QStringList mcuWhiteList = {"QtQuick", "QtQuick.Controls"}; + + if (isQtForMCUs) + filteredImports = Utils::filtered(possibleImports, [mcuWhiteList](const Import &import) { + return mcuWhiteList.contains(import.url()) || !import.url().startsWith("Qt"); + }); + else + filteredImports = possibleImports; + + for (const Import &possibleImport : filteredImports) { if (!isImportAlreadyUsed(possibleImport, m_importLabels)) m_addImportComboBox->addItem(possibleImport.toString(true), QVariant::fromValue(possibleImport)); } diff --git a/src/plugins/qmldesigner/components/integration/designdocument.cpp b/src/plugins/qmldesigner/components/integration/designdocument.cpp index 9d3809727ed..75b45fedb86 100644 --- a/src/plugins/qmldesigner/components/integration/designdocument.cpp +++ b/src/plugins/qmldesigner/components/integration/designdocument.cpp @@ -269,6 +269,14 @@ void DesignDocument::changeToDocumentModel() viewManager().attachViewsExceptRewriterAndComponetView(); } +bool DesignDocument::isQtForMCUsProject() const +{ + if (m_currentTarget) + return m_currentTarget->additionalData("CustomQtForMCUs").toBool(); + + return true; +} + void DesignDocument::changeToInFileComponentModel(ComponentTextModifier *textModifer) { m_inFileComponentTextModifier.reset(textModifer); diff --git a/src/plugins/qmldesigner/components/integration/designdocument.h b/src/plugins/qmldesigner/components/integration/designdocument.h index 7e8509eb4d4..60a0f3f11a1 100644 --- a/src/plugins/qmldesigner/components/integration/designdocument.h +++ b/src/plugins/qmldesigner/components/integration/designdocument.h @@ -97,6 +97,8 @@ public: void changeToDocumentModel(); + bool isQtForMCUsProject() const; + signals: void displayNameChanged(const QString &newFileName); void dirtyStateChanged(bool newState); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp index b1efd1af0e2..3ec61f9cabb 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp @@ -25,17 +25,19 @@ #include "propertyeditorvalue.h" -#include <bindingproperty.h> - -#include <QRegExp> -#include <QUrl> #include <abstractview.h> +#include <bindingproperty.h> +#include <designdocument.h> #include <nodeproperty.h> #include <nodemetainfo.h> +#include <qmldesignerplugin.h> #include <qmlobjectnode.h> -#include <bindingproperty.h> + #include <utils/qtcassert.h> +#include <QRegExp> +#include <QUrl> + //using namespace QmlDesigner; PropertyEditorValue::PropertyEditorValue(QObject *parent) @@ -261,6 +263,22 @@ bool PropertyEditorValue::isTranslated() const return false; } +bool PropertyEditorValue::isAvailable() const +{ + const QList<QByteArray> mcuProperties = {"layer", "opacity", "rotation", "scale", "transformOrigin", "smooth", "antialiasing", "border"}; + const QList<QByteArray> list = name().split('.'); + const QByteArray pureName = list.first(); + + QmlDesigner::DesignDocument *designDocument = + QmlDesigner::QmlDesignerPlugin::instance()->documentManager().currentDesignDocument(); + + + if (designDocument && designDocument->isQtForMCUsProject()) + return !mcuProperties.contains(pureName); + + return true; +} + QmlDesigner::ModelNode PropertyEditorValue::modelNode() const { return m_modelNode; diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h index a69bca8a739..52de9cbb707 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h @@ -89,6 +89,8 @@ class PropertyEditorValue : public QObject Q_PROPERTY(QString name READ nameAsQString FINAL) Q_PROPERTY(PropertyEditorNodeWrapper* complexNode READ complexNode NOTIFY complexNodeChanged FINAL) + Q_PROPERTY(bool isAvailable READ isAvailable NOTIFY isBoundChanged) + public: PropertyEditorValue(QObject *parent=nullptr); @@ -115,6 +117,8 @@ public: bool isTranslated() const; + bool isAvailable() const; + QmlDesigner::PropertyName name() const; QString nameAsQString() const; void setName(const QmlDesigner::PropertyName &name); diff --git a/src/plugins/qmldesigner/components/propertyeditor/qmlanchorbindingproxy.cpp b/src/plugins/qmldesigner/components/propertyeditor/qmlanchorbindingproxy.cpp index 7a38f74f34e..b4ec89d3687 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/qmlanchorbindingproxy.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/qmlanchorbindingproxy.cpp @@ -894,6 +894,7 @@ QmlItemNode QmlAnchorBindingProxy::targetIdToNode(const QString &id) const QString QmlAnchorBindingProxy::idForNode(const QmlItemNode &qmlItemNode) const { + QTC_ASSERT(qmlItemNode.isValid(), return {}); if (m_qmlItemNode.instanceParent().modelNode() == qmlItemNode) return QStringLiteral("parent"); diff --git a/src/plugins/qmldesigner/designercore/filemanager/addpropertyvisitor.cpp b/src/plugins/qmldesigner/designercore/filemanager/addpropertyvisitor.cpp index 7c0688ba9aa..3c04d341bbd 100644 --- a/src/plugins/qmldesigner/designercore/filemanager/addpropertyvisitor.cpp +++ b/src/plugins/qmldesigner/designercore/filemanager/addpropertyvisitor.cpp @@ -79,8 +79,8 @@ bool AddPropertyVisitor::visit(QmlJS::AST::UiObjectBinding *ast) void AddPropertyVisitor::addInMembers(QmlJS::AST::UiObjectInitializer *initializer) { QmlJS::AST::UiObjectMemberList *insertAfter = searchMemberToInsertAfter(initializer->members, m_name, m_propertyOrder); - QmlJS::AST::SourceLocation endOfPreviousMember; - QmlJS::AST::SourceLocation startOfNextMember; + QmlJS::SourceLocation endOfPreviousMember; + QmlJS::SourceLocation startOfNextMember; bool previousMemberSemicolon = false; unsigned depth; diff --git a/src/plugins/qmldesigner/designercore/filemanager/astobjecttextextractor.cpp b/src/plugins/qmldesigner/designercore/filemanager/astobjecttextextractor.cpp index d29ac90cde6..8633e270e41 100644 --- a/src/plugins/qmldesigner/designercore/filemanager/astobjecttextextractor.cpp +++ b/src/plugins/qmldesigner/designercore/filemanager/astobjecttextextractor.cpp @@ -27,6 +27,8 @@ #include <qmljs/parser/qmljsast_p.h> +#include <QDebug> + using namespace QmlDesigner; ASTObjectTextExtractor::ASTObjectTextExtractor(const QString &text): @@ -69,3 +71,8 @@ bool ASTObjectTextExtractor::visit(QmlJS::AST::UiObjectDefinition *ast) return m_text.isEmpty(); } + +void ASTObjectTextExtractor::throwRecursionDepthError() +{ + qWarning("Warning: Hit maximum recursion depth while visiting the AST in ASTObjectTextExtractor"); +} diff --git a/src/plugins/qmldesigner/designercore/filemanager/astobjecttextextractor.h b/src/plugins/qmldesigner/designercore/filemanager/astobjecttextextractor.h index 385d8c1c970..ecc00bde18b 100644 --- a/src/plugins/qmldesigner/designercore/filemanager/astobjecttextextractor.h +++ b/src/plugins/qmldesigner/designercore/filemanager/astobjecttextextractor.h @@ -43,6 +43,8 @@ protected: bool visit(QmlJS::AST::UiObjectBinding *ast) override; bool visit(QmlJS::AST::UiObjectDefinition *ast) override; + void throwRecursionDepthError() override; + private: QmlJS::Document::MutablePtr m_document; quint32 m_location = 0; diff --git a/src/plugins/qmldesigner/designercore/filemanager/firstdefinitionfinder.cpp b/src/plugins/qmldesigner/designercore/filemanager/firstdefinitionfinder.cpp index 76ecb59f303..7fe59053da6 100644 --- a/src/plugins/qmldesigner/designercore/filemanager/firstdefinitionfinder.cpp +++ b/src/plugins/qmldesigner/designercore/filemanager/firstdefinitionfinder.cpp @@ -98,3 +98,8 @@ bool FirstDefinitionFinder::visit(QmlJS::AST::UiObjectDefinition *ast) } return true; } + +void FirstDefinitionFinder::throwRecursionDepthError() +{ + qWarning("Warning: Hit maximum recursion depth while visiting the AST in FirstDefinitionFinder"); +} diff --git a/src/plugins/qmldesigner/designercore/filemanager/firstdefinitionfinder.h b/src/plugins/qmldesigner/designercore/filemanager/firstdefinitionfinder.h index b4e9826f521..2a963ae2fbf 100644 --- a/src/plugins/qmldesigner/designercore/filemanager/firstdefinitionfinder.h +++ b/src/plugins/qmldesigner/designercore/filemanager/firstdefinitionfinder.h @@ -43,6 +43,8 @@ protected: bool visit(QmlJS::AST::UiObjectBinding *ast) override; bool visit(QmlJS::AST::UiObjectDefinition *ast) override; + void throwRecursionDepthError() override; + void extractFirstObjectDefinition(QmlJS::AST::UiObjectInitializer* ast); private: diff --git a/src/plugins/qmldesigner/designercore/filemanager/moveobjectbeforeobjectvisitor.cpp b/src/plugins/qmldesigner/designercore/filemanager/moveobjectbeforeobjectvisitor.cpp index 3be5de5bc91..a4931be5386 100644 --- a/src/plugins/qmldesigner/designercore/filemanager/moveobjectbeforeobjectvisitor.cpp +++ b/src/plugins/qmldesigner/designercore/filemanager/moveobjectbeforeobjectvisitor.cpp @@ -147,7 +147,7 @@ void MoveObjectBeforeObjectVisitor::doMove() moveInfo.prefixToInsert = QString(moveInfo.leadingCharsToRemove, QLatin1Char(' ')); moveInfo.suffixToInsert = separator + QStringLiteral("\n\n"); } else { - const QmlJS::AST::SourceLocation insertionPoint = lastParentLocation(); + const QmlJS::SourceLocation insertionPoint = lastParentLocation(); Q_ASSERT(insertionPoint.isValid()); moveInfo.destination = insertionPoint.offset; int dummy = -1; @@ -169,7 +169,7 @@ QmlJS::AST::Node *MoveObjectBeforeObjectVisitor::movingObjectParent() const return nullptr; } -QmlJS::AST::SourceLocation MoveObjectBeforeObjectVisitor::lastParentLocation() const +QmlJS::SourceLocation MoveObjectBeforeObjectVisitor::lastParentLocation() const { dump(movingObjectParents); @@ -179,5 +179,5 @@ QmlJS::AST::SourceLocation MoveObjectBeforeObjectVisitor::lastParentLocation() c else if (auto initializer = QmlJS::AST::cast<QmlJS::AST::UiArrayBinding*>(parent)) return initializer->rbracketToken; else - return QmlJS::AST::SourceLocation(); + return QmlJS::SourceLocation(); } diff --git a/src/plugins/qmldesigner/designercore/filemanager/moveobjectbeforeobjectvisitor.h b/src/plugins/qmldesigner/designercore/filemanager/moveobjectbeforeobjectvisitor.h index 922d9fe40a7..c47caf56e21 100644 --- a/src/plugins/qmldesigner/designercore/filemanager/moveobjectbeforeobjectvisitor.h +++ b/src/plugins/qmldesigner/designercore/filemanager/moveobjectbeforeobjectvisitor.h @@ -58,7 +58,7 @@ private: void doMove(); QmlJS::AST::Node *movingObjectParent() const; - QmlJS::AST::SourceLocation lastParentLocation() const; + QmlJS::SourceLocation lastParentLocation() const; private: QStack<QmlJS::AST::Node *> parents; diff --git a/src/plugins/qmldesigner/designercore/filemanager/objectlengthcalculator.cpp b/src/plugins/qmldesigner/designercore/filemanager/objectlengthcalculator.cpp index e0908f2f27b..f54167c2d86 100644 --- a/src/plugins/qmldesigner/designercore/filemanager/objectlengthcalculator.cpp +++ b/src/plugins/qmldesigner/designercore/filemanager/objectlengthcalculator.cpp @@ -88,3 +88,8 @@ bool ObjectLengthCalculator::visit(QmlJS::AST::UiObjectDefinition *ast) return m_offset < end; } + +void ObjectLengthCalculator::throwRecursionDepthError() +{ + qWarning("Warning: Hit maximum recursion depth while visiting the AST in ObjectLengthCalculator"); +} diff --git a/src/plugins/qmldesigner/designercore/filemanager/objectlengthcalculator.h b/src/plugins/qmldesigner/designercore/filemanager/objectlengthcalculator.h index af745d2acdf..f9bce822e30 100644 --- a/src/plugins/qmldesigner/designercore/filemanager/objectlengthcalculator.h +++ b/src/plugins/qmldesigner/designercore/filemanager/objectlengthcalculator.h @@ -43,6 +43,8 @@ protected: bool visit(QmlJS::AST::UiObjectBinding *ast) override; bool visit(QmlJS::AST::UiObjectDefinition *ast) override; + void throwRecursionDepthError() override; + private: QmlJS::Document::MutablePtr m_doc; quint32 m_offset = 0; diff --git a/src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.cpp b/src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.cpp index 94b89efcd94..25a72134b2a 100644 --- a/src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.cpp +++ b/src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.cpp @@ -68,12 +68,12 @@ QString QMLRewriter::textBetween(int startPosition, int endPosition) const return m_textModifier->text().mid(startPosition, endPosition - startPosition); } -QString QMLRewriter::textAt(const QmlJS::AST::SourceLocation &location) const +QString QMLRewriter::textAt(const QmlJS::SourceLocation &location) const { return m_textModifier->text().mid(location.offset, location.length); } -unsigned QMLRewriter::calculateIndentDepth(const QmlJS::AST::SourceLocation &position) const +unsigned QMLRewriter::calculateIndentDepth(const QmlJS::SourceLocation &position) const { QTextDocument *doc = m_textModifier->textDocument(); QTextCursor tc(doc); @@ -151,20 +151,20 @@ QString QMLRewriter::removeIndentation(const QString &text, unsigned depth) return result; } -QmlJS::AST::SourceLocation QMLRewriter::calculateLocation(QmlJS::AST::UiQualifiedId *id) +QmlJS::SourceLocation QMLRewriter::calculateLocation(QmlJS::AST::UiQualifiedId *id) { Q_ASSERT(id != nullptr); - const QmlJS::AST::SourceLocation startLocation = id->identifierToken; + const QmlJS::SourceLocation startLocation = id->identifierToken; QmlJS::AST::UiQualifiedId *nextId = id; while (nextId->next) { nextId = nextId->next; } - const QmlJS::AST::SourceLocation endLocation = nextId->identifierToken; + const QmlJS::SourceLocation endLocation = nextId->identifierToken; - return QmlJS::AST::SourceLocation(startLocation.offset, endLocation.end() - startLocation.offset); + return QmlJS::SourceLocation(startLocation.offset, endLocation.end() - startLocation.offset); } bool QMLRewriter::isMissingSemicolon(QmlJS::AST::UiObjectMember *member) @@ -340,3 +340,8 @@ void QMLRewriter::dump(const ASTPath &path) qCDebug(qmlRewriter).noquote() << QString(i + 1, QLatin1Char('-')) << typeid(*node).name(); } } + +void QMLRewriter::throwRecursionDepthError() +{ + qCWarning(qmlRewriter) << "Warning: Hit maximum recursion level while visiting AST in QMLRewriter"; +} diff --git a/src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.h b/src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.h index 062710ef4c7..c773de35bec 100644 --- a/src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.h +++ b/src/plugins/qmldesigner/designercore/filemanager/qmlrewriter.h @@ -51,20 +51,22 @@ public: protected: using QmlJS::AST::Visitor::visit; + void throwRecursionDepthError() override; + virtual void replace(int offset, int length, const QString &text); virtual void move(const QmlDesigner::TextModifier::MoveInfo &moveInfo); QString textBetween(int startPosition, int endPosition) const; - QString textAt(const QmlJS::AST::SourceLocation &location) const; + QString textAt(const QmlJS::SourceLocation &location) const; int indentDepth() const { return textModifier()->indentDepth(); } - unsigned calculateIndentDepth(const QmlJS::AST::SourceLocation &position) const; + unsigned calculateIndentDepth(const QmlJS::SourceLocation &position) const; static QString addIndentation(const QString &text, unsigned depth); static QString removeIndentation(const QString &text, unsigned depth); static QString removeIndentationFromLine(const QString &text, int depth); - static QmlJS::AST::SourceLocation calculateLocation(QmlJS::AST::UiQualifiedId *id); + static QmlJS::SourceLocation calculateLocation(QmlJS::AST::UiQualifiedId *id); static bool isMissingSemicolon(QmlJS::AST::UiObjectMember *member); static bool isMissingSemicolon(QmlJS::AST::Statement *stmt); diff --git a/src/plugins/qmldesigner/designercore/include/qmlvisualnode.h b/src/plugins/qmldesigner/designercore/include/qmlvisualnode.h index e573ec1bc99..d2169b52ff7 100644 --- a/src/plugins/qmldesigner/designercore/include/qmlvisualnode.h +++ b/src/plugins/qmldesigner/designercore/include/qmlvisualnode.h @@ -102,9 +102,9 @@ public: const Position &position, NodeAbstractProperty parentproperty); - static QmlVisualNode createQmlVisualNode(AbstractView *view, + static QmlVisualNode createQml3DNode(AbstractView *view, const ItemLibraryEntry &itemLibraryEntry, - qint32 sceneRootId, const QVector3D &position); + qint32 sceneRootId = -1, const QVector3D &position = {}); static NodeListProperty findSceneNodeProperty(AbstractView *view, qint32 sceneRootId); diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index e361b742058..66572534261 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -1452,7 +1452,7 @@ void NodeInstanceView::library3DItemDropped(const Drop3DLibraryItemCommand &comm QDataStream stream(command.itemData()); ItemLibraryEntry itemLibraryEntry; stream >> itemLibraryEntry; - QmlVisualNode::createQmlVisualNode(this, itemLibraryEntry, command.sceneRootId(), {}); + QmlVisualNode::createQml3DNode(this, itemLibraryEntry, command.sceneRootId(), {}); } void NodeInstanceView::handlePuppetToCreatorCommand(const PuppetToCreatorCommand &command) diff --git a/src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp b/src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp index a5fddccba9a..c1298aa92ed 100644 --- a/src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp +++ b/src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp @@ -93,7 +93,7 @@ bool BaseTextEditModifier::renameId(const QString &oldId, const QString &newId) if (auto bte = qobject_cast<TextEditor::TextEditorWidget*>(plainTextEdit())) { if (auto document = qobject_cast<QmlJSEditor::QmlJSEditorDocument *>(bte->textDocument())) { Utils::ChangeSet changeSet; - foreach (const QmlJS::AST::SourceLocation &loc, + foreach (const QmlJS::SourceLocation &loc, document->semanticInfo().idLocations.value(oldId)) { changeSet.replace(loc.begin(), loc.end(), newId); } diff --git a/src/plugins/qmldesigner/designercore/model/documentmessage.cpp b/src/plugins/qmldesigner/designercore/model/documentmessage.cpp index cbf5843dac6..1d0c124b52f 100644 --- a/src/plugins/qmldesigner/designercore/model/documentmessage.cpp +++ b/src/plugins/qmldesigner/designercore/model/documentmessage.cpp @@ -26,6 +26,7 @@ #include <documentmessage.h> #include <qmljs/parser/qmljsengine_p.h> +#include <qmljs/parser/qmljsdiagnosticmessage_p.h> namespace QmlDesigner { diff --git a/src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp index ada504908f9..16caa385e67 100644 --- a/src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp @@ -294,15 +294,16 @@ QmlObjectNode QmlVisualNode::createQmlObjectNode(AbstractView *view, return newQmlObjectNode; } -QmlVisualNode QmlVisualNode::createQmlVisualNode(AbstractView *view, - const ItemLibraryEntry &itemLibraryEntry, - qint32 sceneRootId, const QVector3D &position) +QmlVisualNode QmlVisualNode::createQml3DNode(AbstractView *view, + const ItemLibraryEntry &itemLibraryEntry, + qint32 sceneRootId, const QVector3D &position) { - NodeAbstractProperty sceneNodeProperty = findSceneNodeProperty(view, sceneRootId); + NodeAbstractProperty sceneNodeProperty = sceneRootId != -1 ? findSceneNodeProperty(view, sceneRootId) + : view->rootModelNode().defaultNodeAbstractProperty(); + QTC_ASSERT(sceneNodeProperty.isValid(), return {}); - ModelNode node = createQmlObjectNode(view, itemLibraryEntry, position, sceneNodeProperty).modelNode(); - return node; + return createQmlObjectNode(view, itemLibraryEntry, position, sceneNodeProperty).modelNode(); } NodeListProperty QmlVisualNode::findSceneNodeProperty(AbstractView *view, qint32 sceneRootId) @@ -318,8 +319,7 @@ NodeListProperty QmlVisualNode::findSceneNodeProperty(AbstractView *view, qint32 bool QmlVisualNode::isFlowTransition(const ModelNode &node) { - return node.metaInfo().isValid() - && node.metaInfo().isSubclassOf("FlowView.FlowTransition"); + return node.metaInfo().isValid() && node.metaInfo().isSubclassOf("FlowView.FlowTransition"); } bool QmlVisualNode::isFlowTransition() const diff --git a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp index 8dad77ad44c..541ed1ceaf3 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp +++ b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp @@ -483,6 +483,42 @@ static QString replaceIllegalPropertyNameChars(const QString &str) return ret; } +static bool idIsQmlKeyWord(const QString& id) +{ + static const QSet<QString> keywords = { + "as", + "break", + "case", + "catch", + "continue", + "debugger", + "default", + "delete", + "do", + "else", + "finally", + "for", + "function", + "if", + "import", + "in", + "instanceof", + "new", + "return", + "switch", + "this", + "throw", + "try", + "typeof", + "var", + "void", + "while", + "with" + }; + + return keywords.contains(id); +} + QString RewriterView::auxiliaryDataAsQML() const { bool hasAuxData = false; @@ -523,6 +559,9 @@ QString RewriterView::auxiliaryDataAsQML() const if (key.endsWith("@Internal")) continue; + if (idIsQmlKeyWord(key)) + continue; + const QVariant value = data.value(key.toUtf8()); QString strValue = value.toString(); diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp index de07ef230fe..a82792b1e8b 100644 --- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp @@ -772,8 +772,8 @@ void TextToModelMerger::setupImports(const Document::Ptr &doc, continue; QString version; - if (import->versionToken.isValid()) - version = textAt(doc, import->versionToken); + if (import->version != nullptr) + version = QLatin1String("%1.%2").arg(import->version->majorVersion).arg(import->version->minorVersion); const QString &as = import->importId.toString(); if (!import->fileName.isEmpty()) { @@ -2036,7 +2036,7 @@ void TextToModelMerger::collectLinkErrors(QList<DocumentMessage> *errors, const void TextToModelMerger::collectImportErrors(QList<DocumentMessage> *errors) { if (m_rewriterView->model()->imports().isEmpty()) { - const QmlJS::DiagnosticMessage diagnosticMessage(QmlJS::Severity::Error, AST::SourceLocation(0, 0, 0, 0), QCoreApplication::translate("QmlDesigner::TextToModelMerger", "No import statements found")); + const QmlJS::DiagnosticMessage diagnosticMessage(QmlJS::Severity::Error, SourceLocation(0, 0, 0, 0), QCoreApplication::translate("QmlDesigner::TextToModelMerger", "No import statements found")); errors->append(DocumentMessage(diagnosticMessage, QUrl::fromLocalFile(m_document->fileName()))); } @@ -2047,7 +2047,7 @@ void TextToModelMerger::collectImportErrors(QList<DocumentMessage> *errors) if (supportedQtQuickVersion(import.version())) { hasQtQuick = true; } else { - const QmlJS::DiagnosticMessage diagnosticMessage(QmlJS::Severity::Error, AST::SourceLocation(0, 0, 0, 0), + const QmlJS::DiagnosticMessage diagnosticMessage(QmlJS::Severity::Error, SourceLocation(0, 0, 0, 0), QCoreApplication::translate("QmlDesigner::TextToModelMerger", "Unsupported QtQuick version")); errors->append(DocumentMessage(diagnosticMessage, QUrl::fromLocalFile(m_document->fileName()))); } @@ -2172,14 +2172,14 @@ QSet<QPair<QString, QString> > TextToModelMerger::qrcMapping() const } QString TextToModelMerger::textAt(const Document::Ptr &doc, - const AST::SourceLocation &location) + const SourceLocation &location) { return doc->source().mid(location.offset, location.length); } QString TextToModelMerger::textAt(const Document::Ptr &doc, - const AST::SourceLocation &from, - const AST::SourceLocation &to) + const SourceLocation &from, + const SourceLocation &to) { return doc->source().mid(from.offset, to.end() - from.begin()); } diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h index 82def3927f2..2884453f8c5 100644 --- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h +++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h @@ -144,10 +144,10 @@ private: void addIsoIconQrcMapping(const QUrl &fileUrl); static QString textAt(const QmlJS::Document::Ptr &doc, - const QmlJS::AST::SourceLocation &location); + const QmlJS::SourceLocation &location); static QString textAt(const QmlJS::Document::Ptr &doc, - const QmlJS::AST::SourceLocation &from, - const QmlJS::AST::SourceLocation &to); + const QmlJS::SourceLocation &from, + const QmlJS::SourceLocation &to); private: RewriterView *m_rewriterView; diff --git a/src/plugins/qmldesigner/designmodewidget.cpp b/src/plugins/qmldesigner/designmodewidget.cpp index 091f1d5e459..db8e819869f 100644 --- a/src/plugins/qmldesigner/designmodewidget.cpp +++ b/src/plugins/qmldesigner/designmodewidget.cpp @@ -182,21 +182,11 @@ QWidget *DesignModeWidget::createProjectExplorerWidget(QWidget *parent) void DesignModeWidget::readSettings() // readPerspectives { return; - - QSettings *settings = Core::ICore::settings(); - - settings->beginGroup("Bauhaus"); - settings->endGroup(); } void DesignModeWidget::saveSettings() // savePerspectives { return; - - QSettings *settings = Core::ICore::settings(); - - settings->beginGroup("Bauhaus"); - settings->endGroup(); } void DesignModeWidget::enableWidgets() diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h index 5dcb014e58f..89c5b643967 100644 --- a/src/plugins/qmldesigner/qmldesignerconstants.h +++ b/src/plugins/qmldesigner/qmldesignerconstants.h @@ -48,6 +48,11 @@ const char TOGGLE_RIGHT_SIDEBAR[] = "QmlDesigner.ToggleRightSideBar"; const char TOGGLE_STATES_EDITOR[] = "QmlDesigner.ToggleStatesEditor"; const char GO_INTO_COMPONENT[] = "QmlDesigner.GoIntoComponent"; const char EXPORT_AS_IMAGE[] = "QmlDesigner.ExportAsImage"; +const char FORMEDITOR_REFRESH[] = "QmlDesigner.FormEditor.Refresh"; +const char FORMEDITOR_SNAPPING[] = "QmlDesigner.FormEditor.Snapping"; +const char FORMEDITOR_NO_SNAPPING[] = "QmlDesigner.FormEditor.NoSnapping"; +const char FORMEDITOR_NO_SNAPPING_AND_ANCHORING[] = "QmlDesigner.FormEditor.NoSnappingAndAnchoring"; +const char FORMEDITOR_NO_SHOW_BOUNDING_RECTANGLE[] = "QmlDesigner.FormEditor.ShowBoundingRectangle"; const char QML_DESIGNER_SUBFOLDER[] = "/designer/"; const char QUICK_3D_ASSETS_FOLDER[] = "/Quick3DAssets"; diff --git a/src/plugins/qmldesigner/qmldesignericons.h b/src/plugins/qmldesigner/qmldesignericons.h index 840f1ea97c7..146565133d7 100644 --- a/src/plugins/qmldesigner/qmldesignericons.h +++ b/src/plugins/qmldesigner/qmldesignericons.h @@ -52,27 +52,27 @@ const Utils::Icon EDIT3D_LIGHT_ON({ const Utils::Icon EDIT3D_LIGHT_OFF({ {QLatin1String(":/edit3d/images/edit_light_off.png"), Utils::Theme::IconsBaseColor}}); const Utils::Icon EDIT3D_SELECTION_MODE_ON({ - {QLatin1String(":/edit3d/images/group_selection_selected.png"), Utils::Theme::IconsBaseColor}}); + {QLatin1String(":/edit3d/images/select_group.png"), Utils::Theme::IconsBaseColor}}); const Utils::Icon EDIT3D_SELECTION_MODE_OFF({ - {QLatin1String(":/edit3d/images/item_selection_selected.png"), Utils::Theme::IconsBaseColor}}); + {QLatin1String(":/edit3d/images/select_item.png"), Utils::Theme::IconsBaseColor}}); const Utils::Icon EDIT3D_MOVE_TOOL_ON({ - {QLatin1String(":/edit3d/images/move_selected.png"), Utils::Theme::IconsBaseColor}}); + {QLatin1String(":/edit3d/images/move_on.png"), Utils::Theme::IconsBaseColor}}); const Utils::Icon EDIT3D_MOVE_TOOL_OFF({ - {QLatin1String(":/edit3d/images/move_active.png"), Utils::Theme::IconsBaseColor}}); + {QLatin1String(":/edit3d/images/move_off.png"), Utils::Theme::IconsBaseColor}}); const Utils::Icon EDIT3D_ROTATE_TOOL_ON({ - {QLatin1String(":/edit3d/images/rotate_selected.png"), Utils::Theme::IconsBaseColor}}); + {QLatin1String(":/edit3d/images/rotate_on.png"), Utils::Theme::IconsBaseColor}}); const Utils::Icon EDIT3D_ROTATE_TOOL_OFF({ - {QLatin1String(":/edit3d/images/rotate_active.png"), Utils::Theme::IconsBaseColor}}); + {QLatin1String(":/edit3d/images/rotate_off.png"), Utils::Theme::IconsBaseColor}}); const Utils::Icon EDIT3D_SCALE_TOOL_ON({ - {QLatin1String(":/edit3d/images/scale_selected.png"), Utils::Theme::IconsBaseColor}}); + {QLatin1String(":/edit3d/images/scale_on.png"), Utils::Theme::IconsBaseColor}}); const Utils::Icon EDIT3D_SCALE_TOOL_OFF({ - {QLatin1String(":/edit3d/images/scale_active.png"), Utils::Theme::IconsBaseColor}}); + {QLatin1String(":/edit3d/images/scale_off.png"), Utils::Theme::IconsBaseColor}}); const Utils::Icon EDIT3D_FIT_SELECTED_OFF({ - {QLatin1String(":/edit3d/images/fit_active.png"), Utils::Theme::IconsBaseColor}}); + {QLatin1String(":/edit3d/images/fit_selected.png"), Utils::Theme::IconsBaseColor}}); const Utils::Icon EDIT3D_EDIT_CAMERA_ON({ - {QLatin1String(":/edit3d/images/persp.png"), Utils::Theme::IconsBaseColor}}); + {QLatin1String(":/edit3d/images/perspective_camera.png"), Utils::Theme::IconsBaseColor}}); const Utils::Icon EDIT3D_EDIT_CAMERA_OFF({ - {QLatin1String(":/edit3d/images/ortho.png"), Utils::Theme::IconsBaseColor}}); + {QLatin1String(":/edit3d/images/orthographic_camera.png"), Utils::Theme::IconsBaseColor}}); const Utils::Icon EDIT3D_ORIENTATION_ON({ {QLatin1String(":/edit3d/images/global.png"), Utils::Theme::IconsBaseColor}}); const Utils::Icon EDIT3D_ORIENTATION_OFF({ diff --git a/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp b/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp index 3afca0b0360..9ed886246ba 100644 --- a/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp +++ b/src/plugins/qmljseditor/qmljscomponentfromobjectdef.cpp @@ -51,6 +51,7 @@ #include <QMessageBox> using namespace QmlJS::AST; +using QmlJS::SourceLocation; using namespace QmlJSTools; namespace QmlJSEditor { diff --git a/src/plugins/qmljseditor/qmljseditor.cpp b/src/plugins/qmljseditor/qmljseditor.cpp index 13eab82ce4b..c260c2f7085 100644 --- a/src/plugins/qmljseditor/qmljseditor.cpp +++ b/src/plugins/qmljseditor/qmljseditor.cpp @@ -86,6 +86,7 @@ #include <QTextCodec> #include <QTimer> #include <QTreeView> +#include <QDebug> enum { UPDATE_USES_DEFAULT_INTERVAL = 150, @@ -230,7 +231,7 @@ bool QmlJSEditorWidget::isOutlineCursorChangesBlocked() void QmlJSEditorWidget::jumpToOutlineElement(int /*index*/) { QModelIndex index = m_outlineCombo->view()->currentIndex(); - AST::SourceLocation location = m_qmlJsEditorDocument->outlineModel()->sourceLocation(index); + SourceLocation location = m_qmlJsEditorDocument->outlineModel()->sourceLocation(index); if (!location.isValid()) return; @@ -332,7 +333,7 @@ void QmlJSEditorWidget::updateUses() return; QList<QTextEdit::ExtraSelection> selections; - foreach (const AST::SourceLocation &loc, + foreach (const SourceLocation &loc, m_qmlJsEditorDocument->semanticInfo().idLocations.value(wordUnderCursor())) { if (! loc.isValid()) continue; @@ -432,6 +433,11 @@ protected: } } } + + void throwRecursionDepthError() override + { + qWarning("Warning: Hit maximum recursion depth visiting AST in SelectedElement"); + } }; void QmlJSEditorWidget::setSelectedElements() @@ -941,7 +947,7 @@ QModelIndex QmlJSEditorWidget::indexForPosition(unsigned cursorPosition, const Q const int rowCount = model->rowCount(rootIndex); for (int i = 0; i < rowCount; ++i) { QModelIndex childIndex = model->index(i, 0, rootIndex); - AST::SourceLocation location = model->sourceLocation(childIndex); + SourceLocation location = model->sourceLocation(childIndex); if ((cursorPosition >= location.offset) && (cursorPosition <= location.offset + location.length)) { diff --git a/src/plugins/qmljseditor/qmljseditordocument.cpp b/src/plugins/qmljseditor/qmljseditordocument.cpp index bb487202c05..b600af61c07 100644 --- a/src/plugins/qmljseditor/qmljseditordocument.cpp +++ b/src/plugins/qmljseditor/qmljseditordocument.cpp @@ -43,6 +43,8 @@ #include <qmljstools/qmljsmodelmanager.h> #include <qmljstools/qmljsqtstylecodeformatter.h> +#include <QDebug> + const char QML_UI_FILE_WARNING[] = "QmlJSEditor.QmlUiFileWarning"; using namespace QmlJSEditor; @@ -69,7 +71,7 @@ struct Declaration class FindIdDeclarations: protected Visitor { public: - using Result = QHash<QString, QList<AST::SourceLocation> >; + using Result = QHash<QString, QList<SourceLocation> >; Result operator()(Document::Ptr doc) { @@ -110,7 +112,7 @@ protected: if (auto idExpr = AST::cast<const AST::IdentifierExpression *>(stmt->expression)) { if (!idExpr->name.isEmpty()) { const QString &id = idExpr->name.toString(); - QList<AST::SourceLocation> *locs = &_ids[id]; + QList<SourceLocation> *locs = &_ids[id]; locs->append(idExpr->firstSourceLocation()); locs->append(_maybeIds.value(id)); _maybeIds.remove(id); @@ -138,6 +140,11 @@ protected: return false; } + void throwRecursionDepthError() override + { + qWarning("Warning: Hit maximum recursion depth while visiting AST in FindIdDeclarations"); + } + private: Result _ids; Result _maybeIds; @@ -414,6 +421,11 @@ protected: return true; } + void throwRecursionDepthError() override + { + qWarning("Warning: Hit maximum recursion depth while visiting AST in CreateRanges"); + } + Range createRange(AST::UiObjectMember *member, AST::UiObjectInitializer *ast) { return createRange(member, member->firstSourceLocation(), ast->rbraceToken); @@ -429,7 +441,7 @@ protected: return createRange(ast, block->lbraceToken, block->rbraceToken); } - Range createRange(AST::Node *ast, AST::SourceLocation start, AST::SourceLocation end) + Range createRange(AST::Node *ast, SourceLocation start, SourceLocation end) { Range range; diff --git a/src/plugins/qmljseditor/qmljsfindreferences.cpp b/src/plugins/qmljseditor/qmljsfindreferences.cpp index 670fc692824..d6f85ef26c7 100644 --- a/src/plugins/qmljseditor/qmljsfindreferences.cpp +++ b/src/plugins/qmljseditor/qmljsfindreferences.cpp @@ -51,6 +51,7 @@ #include <QTimer> #include <QtConcurrentRun> #include <QtConcurrentMap> +#include <QDebug> #include <QDir> #include <QApplication> #include <QLabel> @@ -70,7 +71,7 @@ namespace { class FindUsages: protected Visitor { public: - using Result = QList<AST::SourceLocation>; + using Result = QList<SourceLocation>; FindUsages(Document::Ptr doc, const ContextPtr &context) : _doc(doc) @@ -236,6 +237,11 @@ protected: return true; } + void throwRecursionDepthError() override + { + qWarning("Warning: Hit maximum recursion depth while visitin AST in FindUsages"); + } + private: bool contains(const QmlComponentChain *chain) { @@ -294,7 +300,7 @@ private: class FindTypeUsages: protected Visitor { public: - using Result = QList<AST::SourceLocation>; + using Result = QList<SourceLocation>; FindTypeUsages(Document::Ptr doc, const ContextPtr &context) : _doc(doc) @@ -427,6 +433,10 @@ protected: return false; } + void throwRecursionDepthError() override + { + qWarning("Warning: Hit maximum recursion depth while visitin AST in FindTypeUsages"); + } private: bool checkTypeName(UiQualifiedId *id) @@ -624,6 +634,11 @@ protected: return true; } + void throwRecursionDepthError() override + { + qWarning("Warning: Hit maximum recursion depth visiting AST in FindUsages"); + } + private: bool containsOffset(SourceLocation start, SourceLocation end) { @@ -720,7 +735,7 @@ public: // find all idenfifier expressions, try to resolve them and check if the result is in scope FindUsages findUsages(doc, context); FindUsages::Result results = findUsages(name, scope); - foreach (const AST::SourceLocation &loc, results) + foreach (const SourceLocation &loc, results) usages.append(Usage(fileName, matchingLine(loc.offset, doc->source()), loc.startLine, loc.startColumn - 1, loc.length)); if (future->isPaused()) future->waitForResume(); @@ -762,7 +777,7 @@ public: // find all idenfifier expressions, try to resolve them and check if the result is in scope FindTypeUsages findUsages(doc, context); FindTypeUsages::Result results = findUsages(name, scope); - foreach (const AST::SourceLocation &loc, results) + foreach (const SourceLocation &loc, results) usages.append(Usage(fileName, matchingLine(loc.offset, doc->source()), loc.startLine, loc.startColumn - 1, loc.length)); if (future->isPaused()) future->waitForResume(); @@ -944,7 +959,7 @@ QList<FindReferences::Usage> FindReferences::findUsageOfType(const QString &file foreach (const QmlJS::Document::Ptr &doc, snapshot) { FindTypeUsages findUsages(doc, context); FindTypeUsages::Result results = findUsages(typeName, targetValue); - foreach (const AST::SourceLocation &loc, results) { + foreach (const SourceLocation &loc, results) { usages.append(Usage(doc->fileName(), matchingLine(loc.offset, doc->source()), loc.startLine, loc.startColumn - 1, loc.length)); } } diff --git a/src/plugins/qmljseditor/qmljshoverhandler.cpp b/src/plugins/qmljseditor/qmljshoverhandler.cpp index cf73d63d7c6..1009a7f5433 100644 --- a/src/plugins/qmljseditor/qmljshoverhandler.cpp +++ b/src/plugins/qmljseditor/qmljshoverhandler.cpp @@ -63,8 +63,8 @@ namespace QmlJSEditor { namespace { QString textAt(const Document::Ptr doc, - const AST::SourceLocation &from, - const AST::SourceLocation &to) + const SourceLocation &from, + const SourceLocation &to) { return doc->source().mid(from.offset, to.end() - from.begin()); } diff --git a/src/plugins/qmljseditor/qmljsoutline.cpp b/src/plugins/qmljseditor/qmljsoutline.cpp index abd333f4685..0fcac6e60a4 100644 --- a/src/plugins/qmljseditor/qmljsoutline.cpp +++ b/src/plugins/qmljseditor/qmljsoutline.cpp @@ -206,7 +206,7 @@ void QmlJSOutlineWidget::updateTextCursor(const QModelIndex &index) if (!m_editor->isOutlineCursorChangesBlocked()) { QModelIndex sourceIndex = m_filterModel->mapToSource(index); - AST::SourceLocation location + SourceLocation location = m_editor->qmlJsEditorDocument()->outlineModel()->sourceLocation(sourceIndex); if (!location.isValid()) diff --git a/src/plugins/qmljseditor/qmljssemantichighlighter.cpp b/src/plugins/qmljseditor/qmljssemantichighlighter.cpp index e3b169f46dd..65e9b0ca2e5 100644 --- a/src/plugins/qmljseditor/qmljssemantichighlighter.cpp +++ b/src/plugins/qmljseditor/qmljssemantichighlighter.cpp @@ -46,6 +46,7 @@ #include <utils/qtcassert.h> #include <utils/runextensions.h> +#include <QDebug> #include <QTextDocument> #include <QThreadPool> @@ -163,6 +164,11 @@ protected: return false; } + + void throwRecursionDepthError() override + { + qWarning("Warning: Hit maximum recursion depth while visitin AST in CollectStateNames"); + } }; class CollectionTask : protected Visitor @@ -453,6 +459,11 @@ protected: } } + void throwRecursionDepthError() override + { + qWarning("Warning: Hit Maximum recursion depth when visiting AST in CollectionTask"); + } + private: void addUse(const SourceLocation &location, SemanticHighlighter::UseType type) { diff --git a/src/plugins/qmljseditor/qmljssemantichighlighter.h b/src/plugins/qmljseditor/qmljssemantichighlighter.h index 7fa25b588fd..77ea2a7c122 100644 --- a/src/plugins/qmljseditor/qmljssemantichighlighter.h +++ b/src/plugins/qmljseditor/qmljssemantichighlighter.h @@ -32,7 +32,7 @@ #include <QVector> namespace QmlJS { -namespace AST { class SourceLocation; } +class SourceLocation; } namespace TextEditor { class FontSettings; } diff --git a/src/plugins/qmljseditor/qmljswrapinloader.cpp b/src/plugins/qmljseditor/qmljswrapinloader.cpp index d83d34e23eb..5f0ef4bb05a 100644 --- a/src/plugins/qmljseditor/qmljswrapinloader.cpp +++ b/src/plugins/qmljseditor/qmljswrapinloader.cpp @@ -35,6 +35,7 @@ #include <qmljs/qmljsbind.h> #include <qmljstools/qmljsrefactoringchanges.h> +#include <QDebug> #include <QDir> #include <QFileInfo> #include <QCoreApplication> @@ -71,6 +72,11 @@ protected: return true; } + void throwRecursionDepthError() override + { + qWarning("Warning: Hit maximum recursion depth while visitin AST in FindIds"); + } + Result result; }; diff --git a/src/plugins/qmljseditor/qmloutlinemodel.cpp b/src/plugins/qmljseditor/qmloutlinemodel.cpp index 50162fb1fc2..0cda207b515 100644 --- a/src/plugins/qmljseditor/qmloutlinemodel.cpp +++ b/src/plugins/qmljseditor/qmloutlinemodel.cpp @@ -64,7 +64,7 @@ QmlOutlineItem::QmlOutlineItem(QmlOutlineModel *model) : QVariant QmlOutlineItem::data(int role) const { if (role == Qt::ToolTipRole) { - AST::SourceLocation location = m_outlineModel->sourceLocation(index()); + SourceLocation location = m_outlineModel->sourceLocation(index()); AST::UiQualifiedId *uiQualifiedId = m_outlineModel->idNode(index()); if (!uiQualifiedId || !location.isValid() || !m_outlineModel->m_semanticInfo.isValid()) return QVariant(); @@ -146,6 +146,11 @@ private: parent.insert(objMember, stack.last()); } } + + void throwRecursionDepthError() override + { + qWarning("Warning: Hit maximum recursion depth while visiting AST in ObjectMemberParentVisitor"); + } }; @@ -304,6 +309,11 @@ private: } } + void throwRecursionDepthError() override + { + qWarning("Warning: Hit maximum recursion limit visiting AST in QmlOutlineModelSync"); + } + QmlOutlineModel *m_model; QHash<AST::Node*, QModelIndex> m_nodeToIndex; @@ -341,7 +351,7 @@ QMimeData *QmlOutlineModel::mimeData(const QModelIndexList &indexes) const stream << indexes.size(); for (const auto &index : indexes) { - AST::SourceLocation location = sourceLocation(index); + SourceLocation location = sourceLocation(index); data->addFile(m_editorDocument->filePath().toString(), location.startLine, location.startColumn - 1 /*editors have 0-based column*/); @@ -719,9 +729,9 @@ AST::Node *QmlOutlineModel::nodeForIndex(const QModelIndex &index) const return nullptr; } -AST::SourceLocation QmlOutlineModel::sourceLocation(const QModelIndex &index) const +SourceLocation QmlOutlineModel::sourceLocation(const QModelIndex &index) const { - AST::SourceLocation location; + SourceLocation location; QTC_ASSERT(index.isValid() && (index.model() == this), return location); AST::Node *node = nodeForIndex(index); if (node) { @@ -981,8 +991,8 @@ QString QmlOutlineModel::asString(AST::UiQualifiedId *id) return text; } -AST::SourceLocation QmlOutlineModel::getLocation(AST::UiObjectMember *objMember) { - AST::SourceLocation location; +SourceLocation QmlOutlineModel::getLocation(AST::UiObjectMember *objMember) { + SourceLocation location; location = objMember->firstSourceLocation(); location.length = objMember->lastSourceLocation().offset - objMember->firstSourceLocation().offset @@ -990,8 +1000,8 @@ AST::SourceLocation QmlOutlineModel::getLocation(AST::UiObjectMember *objMember) return location; } -AST::SourceLocation QmlOutlineModel::getLocation(AST::ExpressionNode *exprNode) { - AST::SourceLocation location; +SourceLocation QmlOutlineModel::getLocation(AST::ExpressionNode *exprNode) { + SourceLocation location; location = exprNode->firstSourceLocation(); location.length = exprNode->lastSourceLocation().offset - exprNode->firstSourceLocation().offset @@ -999,14 +1009,14 @@ AST::SourceLocation QmlOutlineModel::getLocation(AST::ExpressionNode *exprNode) return location; } -AST::SourceLocation QmlOutlineModel::getLocation(AST::PatternPropertyList *propertyNode) { +SourceLocation QmlOutlineModel::getLocation(AST::PatternPropertyList *propertyNode) { if (auto assignment = AST::cast<AST::PatternProperty *>(propertyNode->property)) return getLocation(assignment); return propertyNode->firstSourceLocation(); // should never happen } -AST::SourceLocation QmlOutlineModel::getLocation(AST::PatternProperty *propertyNode) { - AST::SourceLocation location; +SourceLocation QmlOutlineModel::getLocation(AST::PatternProperty *propertyNode) { + SourceLocation location; location = propertyNode->name->propertyNameToken; location.length = propertyNode->initializer->lastSourceLocation().end() - location.offset; diff --git a/src/plugins/qmljseditor/qmloutlinemodel.h b/src/plugins/qmljseditor/qmloutlinemodel.h index 17dd08abd80..626b5f3be4f 100644 --- a/src/plugins/qmljseditor/qmloutlinemodel.h +++ b/src/plugins/qmljseditor/qmloutlinemodel.h @@ -90,7 +90,7 @@ public: void update(const QmlJSTools::SemanticInfo &semanticInfo); QmlJS::AST::Node *nodeForIndex(const QModelIndex &index) const; - QmlJS::AST::SourceLocation sourceLocation(const QModelIndex &index) const; + QmlJS::SourceLocation sourceLocation(const QModelIndex &index) const; QmlJS::AST::UiQualifiedId *idNode(const QModelIndex &index) const; QIcon icon(const QModelIndex &index) const; @@ -138,10 +138,10 @@ private: QStandardItem *parentItem(); static QString asString(QmlJS::AST::UiQualifiedId *id); - static QmlJS::AST::SourceLocation getLocation(QmlJS::AST::UiObjectMember *objMember); - static QmlJS::AST::SourceLocation getLocation(QmlJS::AST::ExpressionNode *exprNode); - static QmlJS::AST::SourceLocation getLocation(QmlJS::AST::PatternProperty *propertyNode); - static QmlJS::AST::SourceLocation getLocation(QmlJS::AST::PatternPropertyList *propertyNode); + static QmlJS::SourceLocation getLocation(QmlJS::AST::UiObjectMember *objMember); + static QmlJS::SourceLocation getLocation(QmlJS::AST::ExpressionNode *exprNode); + static QmlJS::SourceLocation getLocation(QmlJS::AST::PatternProperty *propertyNode); + static QmlJS::SourceLocation getLocation(QmlJS::AST::PatternPropertyList *propertyNode); QIcon getIcon(QmlJS::AST::UiQualifiedId *objDef); QString getAnnotation(QmlJS::AST::UiObjectInitializer *objInitializer); diff --git a/src/plugins/qmljstools/qmljslocatordata.cpp b/src/plugins/qmljstools/qmljslocatordata.cpp index 3b68bf6521f..39ef4f4de5a 100644 --- a/src/plugins/qmljstools/qmljslocatordata.cpp +++ b/src/plugins/qmljstools/qmljslocatordata.cpp @@ -33,6 +33,7 @@ //#include <qmljs/qmljsinterpreter.h> #include <qmljs/parser/qmljsast_p.h> +#include <QDebug> #include <QMutexLocker> using namespace QmlJSTools::Internal; @@ -224,6 +225,11 @@ protected: return true; } + + void throwRecursionDepthError() override + { + qWarning("Warning: Hit maximum recursion limit visiting AST in FunctionFinder."); + } }; } // anonymous namespace diff --git a/src/plugins/qmljstools/qmljsrefactoringchanges.cpp b/src/plugins/qmljstools/qmljsrefactoringchanges.cpp index 3fda024e4ed..2cb21f4f555 100644 --- a/src/plugins/qmljstools/qmljsrefactoringchanges.cpp +++ b/src/plugins/qmljstools/qmljsrefactoringchanges.cpp @@ -149,7 +149,7 @@ Document::Ptr QmlJSRefactoringFile::qmljsDocument() const return m_qmljsDocument; } -unsigned QmlJSRefactoringFile::startOf(const AST::SourceLocation &loc) const +unsigned QmlJSRefactoringFile::startOf(const SourceLocation &loc) const { return position(loc.startLine, loc.startColumn); } @@ -176,7 +176,7 @@ bool QmlJSRefactoringFile::isCursorOn(AST::UiQualifiedId *ast) const return pos <= ast->identifierToken.end(); } -bool QmlJSRefactoringFile::isCursorOn(AST::SourceLocation loc) const +bool QmlJSRefactoringFile::isCursorOn(SourceLocation loc) const { const unsigned pos = cursor().position(); return pos >= loc.begin() && pos <= loc.end(); diff --git a/src/plugins/qmljstools/qmljsrefactoringchanges.h b/src/plugins/qmljstools/qmljsrefactoringchanges.h index 2d6f5788d40..7d4bf37546b 100644 --- a/src/plugins/qmljstools/qmljsrefactoringchanges.h +++ b/src/plugins/qmljstools/qmljsrefactoringchanges.h @@ -49,11 +49,11 @@ public: \returns the offset in the document for the start position of the given source location. */ - unsigned startOf(const QmlJS::AST::SourceLocation &loc) const; + unsigned startOf(const QmlJS::SourceLocation &loc) const; bool isCursorOn(QmlJS::AST::UiObjectMember *ast) const; bool isCursorOn(QmlJS::AST::UiQualifiedId *ast) const; - bool isCursorOn(QmlJS::AST::SourceLocation loc) const; + bool isCursorOn(QmlJS::SourceLocation loc) const; protected: QmlJSRefactoringFile(const QString &fileName, const QSharedPointer<TextEditor::RefactoringChangesData> &data); diff --git a/src/plugins/qmljstools/qmljssemanticinfo.cpp b/src/plugins/qmljstools/qmljssemanticinfo.cpp index 1e9eae248a9..ce490cd4450 100644 --- a/src/plugins/qmljstools/qmljssemanticinfo.cpp +++ b/src/plugins/qmljstools/qmljssemanticinfo.cpp @@ -30,6 +30,8 @@ #include <qmljs/qmljsscopechain.h> #include <qmljs/parser/qmljsengine_p.h> +#include <QDebug> + using namespace QmlJS; using namespace QmlJS::AST; @@ -63,13 +65,13 @@ protected: node->accept(this); } - bool containsOffset(AST::SourceLocation start, AST::SourceLocation end) + bool containsOffset(SourceLocation start, SourceLocation end) { return _offset >= start.begin() && _offset <= end.end(); } bool handle(AST::Node *ast, - AST::SourceLocation start, AST::SourceLocation end, + SourceLocation start, SourceLocation end, bool addToPath = true) { if (containsOffset(start, end)) { @@ -99,8 +101,8 @@ protected: bool visit(AST::UiQualifiedId *ast) override { - AST::SourceLocation first = ast->identifierToken; - AST::SourceLocation last; + SourceLocation first = ast->identifierToken; + SourceLocation last; for (AST::UiQualifiedId *it = ast; it; it = it->next) last = it->identifierToken; if (containsOffset(first, last)) @@ -125,6 +127,10 @@ protected: return handleLocationAst(ast); } + void throwRecursionDepthError() override + { + qWarning("Warning: Hit maximum recursion depth when visiting the AST in AstPath"); + } }; } // anonmymous diff --git a/src/plugins/qmljstools/qmljssemanticinfo.h b/src/plugins/qmljstools/qmljssemanticinfo.h index 8d7d1438dc5..50bed9a4838 100644 --- a/src/plugins/qmljstools/qmljssemanticinfo.h +++ b/src/plugins/qmljstools/qmljssemanticinfo.h @@ -85,7 +85,7 @@ public: // attributes QmlJS::Snapshot snapshot; QmlJS::ContextPtr context; QList<Range> ranges; - QHash<QString, QList<QmlJS::AST::SourceLocation> > idLocations; + QHash<QString, QList<QmlJS::SourceLocation> > idLocations; // these are in addition to the parser messages in the document QList<QmlJS::DiagnosticMessage> semanticMessages; diff --git a/src/plugins/qmlprofiler/qmlprofilerdetailsrewriter.cpp b/src/plugins/qmlprofiler/qmlprofilerdetailsrewriter.cpp index cc97f7eb6a3..3be8aff25b3 100644 --- a/src/plugins/qmlprofiler/qmlprofilerdetailsrewriter.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerdetailsrewriter.cpp @@ -38,6 +38,8 @@ #include <utils/qtcassert.h> +#include <QDebug> + namespace QmlProfiler { namespace Internal { @@ -78,12 +80,16 @@ protected: return true; } + void throwRecursionDepthError() override + { + qWarning("Warning: Hit mximum recursion depth while visiting AST in PropertyVisitor"); + } private: QmlJS::AST::Node *m_lastValidNode = nullptr; quint32 m_line = 0; quint32 m_column = 0; - bool containsLocation(QmlJS::AST::SourceLocation start, QmlJS::AST::SourceLocation end) + bool containsLocation(QmlJS::SourceLocation start, QmlJS::SourceLocation end) { return (m_line > start.startLine || (m_line == start.startLine && m_column >= start.startColumn)) diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp b/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp index 1ad4bb0590c..d70a2a7707c 100644 --- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp +++ b/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp @@ -103,7 +103,7 @@ QmlProjectItem *QmlProjectFileFormat::parseProjectFile(const Utils::FilePath &fi const QVariant qtForMCUProperty = rootNode->property("qtForMCUs"); if (qtForMCUProperty.isValid() && qtForMCUProperty.toBool()) - projectItem->setQtForMCUs(targetDirectoryPropery.toBool()); + projectItem->setQtForMCUs(qtForMCUProperty.toBool()); if (debug) qDebug() << "importPath:" << importPathsProperty << "mainFile:" << mainFileProperty; diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp index fc622179cae..fe7542e8cbe 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.cpp +++ b/src/plugins/qmlprojectmanager/qmlproject.cpp @@ -57,11 +57,16 @@ #include <QDebug> #include <QRegularExpression> #include <QTextCodec> +#include <QLoggingCategory> using namespace Core; using namespace ProjectExplorer; using namespace QmlProjectManager::Internal; +namespace { +Q_LOGGING_CATEGORY(infoLogger, "QmlProjectManager.QmlBuildSystem", QtInfoMsg) +} + namespace QmlProjectManager { QmlProject::QmlProject(const Utils::FilePath &fileName) @@ -276,6 +281,10 @@ QStringList QmlBuildSystem::makeAbsolute(const Utils::FilePath &path, const QStr void QmlBuildSystem::refreshFiles(const QSet<QString> &/*added*/, const QSet<QString> &removed) { + if (m_blockFilesUpdate) { + qCDebug(infoLogger) << "Auto files refresh blocked."; + return; + } refresh(Files); if (!removed.isEmpty()) { if (auto modelManager = QmlJS::ModelManagerInterface::instance()) diff --git a/src/plugins/qmlprojectmanager/qmlproject.h b/src/plugins/qmlprojectmanager/qmlproject.h index 0cff1528984..acd8bc1094e 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.h +++ b/src/plugins/qmlprojectmanager/qmlproject.h @@ -104,6 +104,27 @@ public: QPointer<QmlProjectItem> m_projectItem; Utils::FilePath m_canonicalProjectDir; + +private: + bool m_blockFilesUpdate = false; + friend class FilesUpdateBlocker; +}; + +class FilesUpdateBlocker { +public: + FilesUpdateBlocker(QmlBuildSystem* bs): m_bs(bs) { + if (m_bs) + m_bs->m_blockFilesUpdate = true; + } + + ~FilesUpdateBlocker() { + if (m_bs) { + m_bs->m_blockFilesUpdate = false; + m_bs->refresh(QmlBuildSystem::Everything); + } + } +private: + QPointer<QmlBuildSystem> m_bs; }; class QMLPROJECTMANAGER_EXPORT QmlProject : public ProjectExplorer::Project diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index 4643eb9aeb1..49dd128d28b 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -522,7 +522,7 @@ Tasks BaseQtVersion::validateKit(const Kit *k) qtAbiString.append(qtAbi.toString()); if (!fullMatch) - fullMatch = (targetAbi == qtAbi); + fullMatch = targetAbi.isFullyCompatibleWith(qtAbi); if (!fuzzyMatch) fuzzyMatch = targetAbi.isCompatibleWith(qtAbi); } diff --git a/src/plugins/qtsupport/qtkitinformation.cpp b/src/plugins/qtsupport/qtkitinformation.cpp index 6412bba0d24..0ff13d07ece 100644 --- a/src/plugins/qtsupport/qtkitinformation.cpp +++ b/src/plugins/qtsupport/qtkitinformation.cpp @@ -223,13 +223,25 @@ void QtKitAspect::fix(ProjectExplorer::Kit *k) return; const QString spec = version->mkspec(); - const QList<ToolChain *> possibleTcs = ToolChainManager::toolChains( + QList<ToolChain *> possibleTcs = ToolChainManager::toolChains( [version](const ToolChain *t) { return t->isValid() && t->language() == Core::Id(ProjectExplorer::Constants::CXX_LANGUAGE_ID) - && version->qtAbis().contains(t->targetAbi()); + && contains(version->qtAbis(), [t](const Abi &qtAbi) { + return qtAbi.isFullyCompatibleWith(t->targetAbi()); + }); }); if (!possibleTcs.isEmpty()) { + // Prefer exact matches. + // TODO: We should probably prefer the compiler with the highest version number instead, + // but this information is currently not exposed by the ToolChain class. + sort(possibleTcs, [version](const ToolChain *tc1, const ToolChain *tc2) { + const QVector<Abi> &qtAbis = version->qtAbis(); + const bool tc1ExactMatch = qtAbis.contains(tc1->targetAbi()); + const bool tc2ExactMatch = qtAbis.contains(tc2->targetAbi()); + return tc1ExactMatch && !tc2ExactMatch; + }); + const QList<ToolChain *> goodTcs = Utils::filtered(possibleTcs, [&spec](const ToolChain *t) { return t->suggestedMkspecList().contains(spec); diff --git a/src/plugins/texteditor/CMakeLists.txt b/src/plugins/texteditor/CMakeLists.txt index 4cc3d394752..368afb47423 100644 --- a/src/plugins/texteditor/CMakeLists.txt +++ b/src/plugins/texteditor/CMakeLists.txt @@ -64,7 +64,6 @@ add_qtc_plugin(TextEditor ioutlinewidget.h linenumberfilter.cpp linenumberfilter.h marginsettings.cpp marginsettings.h - normalindenter.cpp normalindenter.h outlinefactory.cpp outlinefactory.h plaintexteditorfactory.cpp plaintexteditorfactory.h quickfix.cpp quickfix.h diff --git a/src/plugins/texteditor/fontsettingspage.cpp b/src/plugins/texteditor/fontsettingspage.cpp index c192192bdb8..f0e1bca968f 100644 --- a/src/plugins/texteditor/fontsettingspage.cpp +++ b/src/plugins/texteditor/fontsettingspage.cpp @@ -642,9 +642,8 @@ FontSettingsPage::FontSettingsPage(FontSettings *fontSettings, const FormatDescr void FontSettingsPage::setFontZoom(int zoom) { - auto w = static_cast<FontSettingsPageWidget *>(widget()); - w->m_ui.zoomSpinBox->setValue(zoom); - w->saveSettings(); + if (m_widget) + static_cast<FontSettingsPageWidget *>(m_widget.data())->m_ui.zoomSpinBox->setValue(zoom); } } // TextEditor diff --git a/src/plugins/texteditor/normalindenter.cpp b/src/plugins/texteditor/normalindenter.cpp deleted file mode 100644 index e4a8ef4d109..00000000000 --- a/src/plugins/texteditor/normalindenter.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** 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 "normalindenter.h" -#include "tabsettings.h" - -#include <QTextDocument> - -// Indent a text block based on previous line. -// Simple text paragraph layout: -// aaaa aaaa -// -// bbb bb -// bbb bb -// -// - list -// list line2 -// -// - listn -// -// ccc -// -// @todo{Add formatting to wrap paragraphs. This requires some -// hoops as the current indentation routines are not prepared -// for additional block being inserted. It might be possible -// to do in 2 steps (indenting/wrapping)} -// - -using namespace TextEditor; - -NormalIndenter::NormalIndenter(QTextDocument *doc) - : TextIndenter(doc) -{} - -int NormalIndenter::indentFor(const QTextBlock &block, - const TabSettings &tabSettings, - int cursorPositionInEditor) -{ - Q_UNUSED(tabSettings) - Q_UNUSED(cursorPositionInEditor) - - QTextBlock previous = block.previous(); - if (!previous.isValid()) - return 0; - - const QString previousText = previous.text(); - // Empty line indicates a start of a new paragraph. Leave as is. - if (previousText.isEmpty() || previousText.trimmed().isEmpty()) - return 0; - - return tabSettings.indentationColumn(previousText); -} diff --git a/src/plugins/texteditor/plaintexteditorfactory.cpp b/src/plugins/texteditor/plaintexteditorfactory.cpp index 02e89b42278..f87165b7981 100644 --- a/src/plugins/texteditor/plaintexteditorfactory.cpp +++ b/src/plugins/texteditor/plaintexteditorfactory.cpp @@ -24,14 +24,14 @@ ****************************************************************************/ #include "plaintexteditorfactory.h" -#include "texteditor.h" +#include "basehoverhandler.h" #include "textdocument.h" -#include "normalindenter.h" +#include "texteditor.h" #include "texteditoractionhandler.h" #include "texteditorconstants.h" #include "texteditorplugin.h" #include "texteditorsettings.h" -#include "basehoverhandler.h" +#include "textindenter.h" #include <coreplugin/coreconstants.h> #include <coreplugin/infobar.h> @@ -65,7 +65,6 @@ PlainTextEditorFactory::PlainTextEditorFactory() setDocumentCreator([]() { return new TextDocument(Core::Constants::K_DEFAULT_TEXT_EDITOR_ID); }); setEditorWidgetCreator([]() { return new PlainTextEditorWidget; }); - setIndenterCreator([](QTextDocument *doc) { return new NormalIndenter(doc); }); setUseGenericHighlighter(true); setEditorActionHandlers(TextEditorActionHandler::Format | diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 8dd3ff712c8..2e65082918f 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -41,7 +41,6 @@ #include "highlighter.h" #include "highlightersettings.h" #include "icodestylepreferences.h" -#include "indenter.h" #include "refactoroverlay.h" #include "snippets/snippet.h" #include "storagesettings.h" @@ -52,6 +51,7 @@ #include "texteditorconstants.h" #include "texteditoroverlay.h" #include "texteditorsettings.h" +#include "textindenter.h" #include "typingsettings.h" #include <texteditor/codeassist/assistinterface.h> @@ -2930,7 +2930,7 @@ QByteArray TextEditorWidget::saveState() const { QByteArray state; QDataStream stream(&state, QIODevice::WriteOnly); - stream << 1; // version number + stream << 2; // version number stream << verticalScrollBar()->value(); stream << horizontalScrollBar()->value(); int line, column; @@ -2950,6 +2950,9 @@ QByteArray TextEditorWidget::saveState() const } stream << foldedBlocks; + stream << firstVisibleBlockNumber(); + stream << lastVisibleBlockNumber(); + return state; } @@ -3000,6 +3003,19 @@ bool TextEditorWidget::restoreState(const QByteArray &state) gotoLine(lineVal, columnVal - 1); verticalScrollBar()->setValue(vval); horizontalScrollBar()->setValue(hval); + + if (version >= 2) { + int firstBlock, lastBlock; + stream >> firstBlock; + stream >> lastBlock; + // If current line was visible in the old state, make sure it is visible in the new state. + // This can happen if the height of the editor changed in the meantime + if (firstBlock <= lineVal && lineVal <= lastBlock + && (lineVal < firstVisibleBlockNumber() || lastVisibleBlockNumber() <= lineVal)) { + centerCursor(); + } + } + d->saveCurrentCursorPositionForNavigation(); return true; } @@ -8523,9 +8539,10 @@ namespace Internal { class TextEditorFactoryPrivate { public: - TextEditorFactoryPrivate(TextEditorFactory *parent) : - q(parent), - m_widgetCreator([]() { return new TextEditorWidget; }) + TextEditorFactoryPrivate(TextEditorFactory *parent) + : q(parent) + , m_widgetCreator([]() { return new TextEditorWidget; }) + , m_indenterCreator([](QTextDocument *d) { return new TextIndenter(d); }) {} BaseTextEditor *duplicateTextEditor(BaseTextEditor *other) diff --git a/src/plugins/texteditor/texteditor.pro b/src/plugins/texteditor/texteditor.pro index 386640307d5..6892ddd79c1 100644 --- a/src/plugins/texteditor/texteditor.pro +++ b/src/plugins/texteditor/texteditor.pro @@ -41,7 +41,6 @@ SOURCES += texteditorplugin.cpp \ texteditoroverlay.cpp \ textdocumentlayout.cpp \ completionsettings.cpp \ - normalindenter.cpp \ textindenter.cpp \ quickfix.cpp \ syntaxhighlighter.cpp \ @@ -129,7 +128,6 @@ HEADERS += texteditorplugin.h \ texteditoroverlay.h \ textdocumentlayout.h \ completionsettings.h \ - normalindenter.h \ textindenter.h \ quickfix.h \ syntaxhighlighter.h \ diff --git a/src/plugins/texteditor/texteditor.qbs b/src/plugins/texteditor/texteditor.qbs index bc8756d2abf..6564c97b0ce 100644 --- a/src/plugins/texteditor/texteditor.qbs +++ b/src/plugins/texteditor/texteditor.qbs @@ -104,8 +104,6 @@ Project { "linenumberfilter.h", "marginsettings.cpp", "marginsettings.h", - "normalindenter.cpp", - "normalindenter.h", "outlinefactory.cpp", "outlinefactory.h", "plaintexteditorfactory.cpp", diff --git a/src/plugins/texteditor/texteditorsettings.cpp b/src/plugins/texteditor/texteditorsettings.cpp index ed822f20801..eb75f8aeb9c 100644 --- a/src/plugins/texteditor/texteditorsettings.cpp +++ b/src/plugins/texteditor/texteditorsettings.cpp @@ -514,21 +514,26 @@ Core::Id TextEditorSettings::languageId(const QString &mimeType) return d->m_mimeTypeToLanguage.value(mimeType); } +static void setFontZoom(int zoom) +{ + d->m_fontSettingsPage.setFontZoom(zoom); + d->m_fontSettings.setFontZoom(zoom); + d->m_fontSettings.toSettings(Core::ICore::settings()); + emit m_instance->fontSettingsChanged(d->m_fontSettings); +} + int TextEditorSettings::increaseFontZoom(int step) { const int previousZoom = d->m_fontSettings.fontZoom(); const int newZoom = qMax(10, previousZoom + step); - if (newZoom != previousZoom) { - d->m_fontSettings.setFontZoom(newZoom); - d->m_fontSettingsPage.setFontZoom(newZoom); - } + if (newZoom != previousZoom) + setFontZoom(newZoom); return newZoom; } void TextEditorSettings::resetFontZoom() { - d->m_fontSettings.setFontZoom(100); - d->m_fontSettingsPage.setFontZoom(100); + setFontZoom(100); } } // TextEditor diff --git a/src/plugins/texteditor/textindenter.cpp b/src/plugins/texteditor/textindenter.cpp index c2d328d3fea..fcb04d5fa68 100644 --- a/src/plugins/texteditor/textindenter.cpp +++ b/src/plugins/texteditor/textindenter.cpp @@ -36,6 +36,43 @@ TextIndenter::TextIndenter(QTextDocument *doc) TextIndenter::~TextIndenter() = default; +// Indent a text block based on previous line. +// Simple text paragraph layout: +// aaaa aaaa +// +// bbb bb +// bbb bb +// +// - list +// list line2 +// +// - listn +// +// ccc +// +// @todo{Add formatting to wrap paragraphs. This requires some +// hoops as the current indentation routines are not prepared +// for additional block being inserted. It might be possible +// to do in 2 steps (indenting/wrapping)} +int TextIndenter::indentFor(const QTextBlock &block, + const TabSettings &tabSettings, + int cursorPositionInEditor) +{ + Q_UNUSED(tabSettings) + Q_UNUSED(cursorPositionInEditor) + + QTextBlock previous = block.previous(); + if (!previous.isValid()) + return 0; + + const QString previousText = previous.text(); + // Empty line indicates a start of a new paragraph. Leave as is. + if (previousText.isEmpty() || previousText.trimmed().isEmpty()) + return 0; + + return tabSettings.indentationColumn(previousText); +} + IndentationForBlock TextIndenter::indentationForBlocks(const QVector<QTextBlock> &blocks, const TabSettings &tabSettings, int /*cursorPositionInEditor*/) diff --git a/src/plugins/texteditor/textindenter.h b/src/plugins/texteditor/textindenter.h index d361713074d..c76ad134d4b 100644 --- a/src/plugins/texteditor/textindenter.h +++ b/src/plugins/texteditor/textindenter.h @@ -44,6 +44,10 @@ public: explicit TextIndenter(QTextDocument *doc); ~TextIndenter() override; + int indentFor(const QTextBlock &block, + const TabSettings &tabSettings, + int cursorPositionInEditor = -1) override; + IndentationForBlock indentationForBlocks(const QVector<QTextBlock> &blocks, const TabSettings &tabSettings, int cursorPositionInEditor = -1) override; diff --git a/src/plugins/todo/qmljstodoitemsscanner.cpp b/src/plugins/todo/qmljstodoitemsscanner.cpp index df6ea53ea8c..c3ec33e9ccc 100644 --- a/src/plugins/todo/qmljstodoitemsscanner.cpp +++ b/src/plugins/todo/qmljstodoitemsscanner.cpp @@ -78,7 +78,7 @@ void QmlJsTodoItemsScanner::processDocument(QmlJS::Document::Ptr doc) { QList<TodoItem> itemList; - foreach (const QmlJS::AST::SourceLocation &sourceLocation, doc->engine()->comments()) { + foreach (const QmlJS::SourceLocation &sourceLocation, doc->engine()->comments()) { QString source = doc->source().mid(sourceLocation.begin(), sourceLocation.length).trimmed(); // Process every line diff --git a/src/plugins/valgrind/memchecktool.cpp b/src/plugins/valgrind/memchecktool.cpp index fd8025fc8b1..c5073bd40f1 100644 --- a/src/plugins/valgrind/memchecktool.cpp +++ b/src/plugins/valgrind/memchecktool.cpp @@ -350,7 +350,7 @@ bool MemcheckErrorFilterProxyModel::filterAcceptsRow(int sourceRow, const QModel if (file.isExecutable()) validFolders << file.remoteDirectory(); } - foreach (BuildConfiguration *config, target->buildConfigurations()) + for (BuildConfiguration *config : target->buildConfigurations()) validFolders << config->buildDirectory().toString(); } } diff --git a/src/plugins/vcsbase/submiteditorwidget.cpp b/src/plugins/vcsbase/submiteditorwidget.cpp index e87a317719c..ad15a8ca9b0 100644 --- a/src/plugins/vcsbase/submiteditorwidget.cpp +++ b/src/plugins/vcsbase/submiteditorwidget.cpp @@ -622,16 +622,6 @@ void SubmitEditorWidget::checkAllToggled() d->m_ui.checkAllCheckBox->setTristate(false); } -void SubmitEditorWidget::checkAll() -{ - fileModel()->setAllChecked(true); -} - -void SubmitEditorWidget::uncheckAll() -{ - fileModel()->setAllChecked(false); -} - void SubmitEditorWidget::fileListCustomContextMenuRequested(const QPoint & pos) { // Execute menu offering to check/uncheck all @@ -642,11 +632,11 @@ void SubmitEditorWidget::fileListCustomContextMenuRequested(const QPoint & pos) QAction *uncheckAllAction = menu.addAction(tr("Unselect All")); QAction *action = menu.exec(d->m_ui.fileView->mapToGlobal(pos)); if (action == checkAllAction) { - checkAll(); + fileModel()->setAllChecked(true);; return; } if (action == uncheckAllAction) { - uncheckAll(); + fileModel()->setAllChecked(false); return; } } diff --git a/src/plugins/vcsbase/submiteditorwidget.h b/src/plugins/vcsbase/submiteditorwidget.h index 651775fe1b4..e19ab65c4de 100644 --- a/src/plugins/vcsbase/submiteditorwidget.h +++ b/src/plugins/vcsbase/submiteditorwidget.h @@ -124,8 +124,6 @@ protected slots: private: void updateCheckAllComboBox(); void checkAllToggled(); - void checkAll(); - void uncheckAll(); void triggerDiffSelected(); void diffActivated(const QModelIndex &index); diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp index aac8696c0e0..0f334b7f137 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.cpp +++ b/src/plugins/vcsbase/vcsbaseeditor.cpp @@ -255,7 +255,7 @@ private slots: void slotCopyRevision(); private: - QAction *createDescribeAction(const QString &change) const; + void addDescribeAction(QMenu *menu, const QString &change) const; QAction *createAnnotateAction(const QString &change, bool previous) const; QAction *createCopyRevisionAction(const QString &change) const; @@ -299,7 +299,7 @@ void ChangeTextCursorHandler::fillContextMenu(QMenu *menu, EditorContentType typ menu->addSeparator(); menu->addAction(createCopyRevisionAction(m_currentChange)); if (currentValid) - menu->addAction(createDescribeAction(m_currentChange)); + addDescribeAction(menu, m_currentChange); menu->addSeparator(); if (currentValid) menu->addAction(createAnnotateAction(widget->decorateVersion(m_currentChange), false)); @@ -313,7 +313,7 @@ void ChangeTextCursorHandler::fillContextMenu(QMenu *menu, EditorContentType typ default: // Describe current / Annotate file of current menu->addSeparator(); menu->addAction(createCopyRevisionAction(m_currentChange)); - menu->addAction(createDescribeAction(m_currentChange)); + addDescribeAction(menu, m_currentChange); if (widget->isFileLogAnnotateEnabled()) menu->addAction(createAnnotateAction(m_currentChange, false)); break; @@ -336,11 +336,12 @@ void ChangeTextCursorHandler::slotCopyRevision() QApplication::clipboard()->setText(m_currentChange); } -QAction *ChangeTextCursorHandler::createDescribeAction(const QString &change) const +void ChangeTextCursorHandler::addDescribeAction(QMenu *menu, const QString &change) const { auto a = new QAction(VcsBaseEditorWidget::tr("&Describe Change %1").arg(change), nullptr); connect(a, &QAction::triggered, this, &ChangeTextCursorHandler::slotDescribe); - return a; + menu->addAction(a); + menu->setDefaultAction(a); } QAction *ChangeTextCursorHandler::createAnnotateAction(const QString &change, bool previous) const @@ -358,7 +359,7 @@ QAction *ChangeTextCursorHandler::createAnnotateAction(const QString &change, bo QAction *ChangeTextCursorHandler::createCopyRevisionAction(const QString &change) const { - auto a = new QAction(editorWidget()->copyRevisionTextFormat().arg(change), nullptr); + auto a = new QAction(VcsBaseEditorWidget::tr("Copy \"%1\"").arg(change), nullptr); a->setData(change); connect(a, &QAction::triggered, this, &ChangeTextCursorHandler::slotCopyRevision); return a; @@ -564,7 +565,6 @@ public: int m_firstLineNumber = -1; QString m_annotateRevisionTextFormat; QString m_annotatePreviousRevisionTextFormat; - QString m_copyRevisionTextFormat; VcsBaseEditorConfig *m_config = nullptr; QList<AbstractTextCursorHandler *> m_textCursorHandlers; QPointer<VcsCommand> m_command; @@ -579,8 +579,7 @@ private: VcsBaseEditorWidgetPrivate::VcsBaseEditorWidgetPrivate(VcsBaseEditorWidget *editorWidget) : q(editorWidget), - m_annotateRevisionTextFormat(VcsBaseEditorWidget::tr("Annotate \"%1\"")), - m_copyRevisionTextFormat(VcsBaseEditorWidget::tr("Copy \"%1\"")) + m_annotateRevisionTextFormat(VcsBaseEditorWidget::tr("Annotate \"%1\"")) { m_textCursorHandlers.append(new ChangeTextCursorHandler(editorWidget)); m_textCursorHandlers.append(new UrlTextCursorHandler(editorWidget)); @@ -819,16 +818,6 @@ void VcsBaseEditorWidget::setAnnotatePreviousRevisionTextFormat(const QString &f d->m_annotatePreviousRevisionTextFormat = f; } -QString VcsBaseEditorWidget::copyRevisionTextFormat() const -{ - return d->m_copyRevisionTextFormat; -} - -void VcsBaseEditorWidget::setCopyRevisionTextFormat(const QString &f) -{ - d->m_copyRevisionTextFormat = f; -} - bool VcsBaseEditorWidget::isFileLogAnnotateEnabled() const { return d->m_fileLogAnnotateEnabled; @@ -976,13 +965,17 @@ void VcsBaseEditorWidget::slotCursorPositionChanged() void VcsBaseEditorWidget::contextMenuEvent(QContextMenuEvent *e) { - QPointer<QMenu> menu = createStandardContextMenu(); + QPointer<QMenu> menu; // 'click on change-interaction' if (supportChangeLinks()) { const QTextCursor cursor = cursorForPosition(e->pos()); - if (Internal::AbstractTextCursorHandler *handler = d->findTextCursorHandler(cursor)) + if (Internal::AbstractTextCursorHandler *handler = d->findTextCursorHandler(cursor)) { + menu = new QMenu; handler->fillContextMenu(menu, d->m_parameters->type); + } } + if (!menu) + menu = createStandardContextMenu(); switch (d->m_parameters->type) { case LogOutput: // log might have diff case DiffOutput: { diff --git a/src/plugins/vcsbase/vcsbaseeditor.h b/src/plugins/vcsbase/vcsbaseeditor.h index 6e32037b680..5340a3d4b26 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.h +++ b/src/plugins/vcsbase/vcsbaseeditor.h @@ -135,7 +135,6 @@ class VCSBASE_EXPORT VcsBaseEditorWidget : public TextEditor::TextEditorWidget Q_PROPERTY(QString workingDirectory READ workingDirectory WRITE setWorkingDirectory) Q_PROPERTY(QTextCodec *codec READ codec WRITE setCodec) Q_PROPERTY(QString annotateRevisionTextFormat READ annotateRevisionTextFormat WRITE setAnnotateRevisionTextFormat) - Q_PROPERTY(QString copyRevisionTextFormat READ copyRevisionTextFormat WRITE setCopyRevisionTextFormat) Q_PROPERTY(bool isFileLogAnnotateEnabled READ isFileLogAnnotateEnabled WRITE setFileLogAnnotateEnabled) Q_OBJECT @@ -188,10 +187,6 @@ public: QString annotatePreviousRevisionTextFormat() const; void setAnnotatePreviousRevisionTextFormat(const QString &); - // Format for "Copy" revision menu entries. Should contain '%1" placeholder - QString copyRevisionTextFormat() const; - void setCopyRevisionTextFormat(const QString &); - // Enable "Annotate" context menu in file log view // (set to true if the source is a single file and the VCS implements it) bool isFileLogAnnotateEnabled() const; diff --git a/src/plugins/vcsbase/vcsoutputformatter.cpp b/src/plugins/vcsbase/vcsoutputformatter.cpp index 4b09ed06eb7..9e454da544c 100644 --- a/src/plugins/vcsbase/vcsoutputformatter.cpp +++ b/src/plugins/vcsbase/vcsoutputformatter.cpp @@ -23,7 +23,11 @@ ****************************************************************************/ #include "vcsoutputformatter.h" +#include <coreplugin/iversioncontrol.h> +#include <coreplugin/vcsmanager.h> + #include <QDesktopServices> +#include <QMenu> #include <QPlainTextEdit> #include <QTextCursor> #include <QUrl> @@ -68,4 +72,18 @@ void VcsOutputFormatter::handleLink(const QString &href) emit referenceClicked(href); } +void VcsOutputFormatter::fillLinkContextMenu( + QMenu *menu, const QString &workingDirectory, const QString &href) +{ + if (href.isEmpty() || href.startsWith("http://") || href.startsWith("https://")) { + QAction *action = menu->addAction( + tr("&Open \"%1\"").arg(href), + [href] { QDesktopServices::openUrl(QUrl(href)); }); + menu->setDefaultAction(action); + return; + } + if (Core::IVersionControl *vcs = Core::VcsManager::findVersionControlForDirectory(workingDirectory)) + vcs->fillLinkContextMenu(menu, workingDirectory, href); +} + } diff --git a/src/plugins/vcsbase/vcsoutputformatter.h b/src/plugins/vcsbase/vcsoutputformatter.h index d1d508b895f..b9fd8c6c7e4 100644 --- a/src/plugins/vcsbase/vcsoutputformatter.h +++ b/src/plugins/vcsbase/vcsoutputformatter.h @@ -27,6 +27,8 @@ #include <QRegularExpression> +QT_FORWARD_DECLARE_CLASS(QMenu) + namespace VcsBase { class VcsOutputFormatter : public Utils::OutputFormatter @@ -37,6 +39,7 @@ public: ~VcsOutputFormatter() override = default; void appendMessage(const QString &text, Utils::OutputFormat format) override; void handleLink(const QString &href) override; + void fillLinkContextMenu(QMenu *menu, const QString &workingDirectory, const QString &href); signals: void referenceClicked(const QString &reference); diff --git a/src/plugins/vcsbase/vcsoutputwindow.cpp b/src/plugins/vcsbase/vcsoutputwindow.cpp index e468adcc305..1cff2dc4b72 100644 --- a/src/plugins/vcsbase/vcsoutputwindow.cpp +++ b/src/plugins/vcsbase/vcsoutputwindow.cpp @@ -175,10 +175,17 @@ QString OutputWindowPlainTextEdit::identifierUnderCursor(const QPoint &widgetPos void OutputWindowPlainTextEdit::contextMenuEvent(QContextMenuEvent *event) { - QMenu *menu = createStandardContextMenu(); + const QString href = anchorAt(event->pos()); + QMenu *menu = href.isEmpty() ? createStandardContextMenu(event->pos()) : new QMenu; // Add 'open file' QString repository; const QString token = identifierUnderCursor(event->pos(), &repository); + if (!repository.isEmpty()) { + if (VcsOutputFormatter *f = formatter()) { + if (!href.isEmpty()) + f->fillLinkContextMenu(menu, repository, href); + } + } QAction *openAction = nullptr; if (!token.isEmpty()) { // Check for a file, expand via repository if relative @@ -192,9 +199,12 @@ void OutputWindowPlainTextEdit::contextMenuEvent(QContextMenuEvent *event) openAction->setData(fi.absoluteFilePath()); } } - // Add 'clear' - menu->addSeparator(); - QAction *clearAction = menu->addAction(VcsOutputWindow::tr("Clear")); + QAction *clearAction = nullptr; + if (href.isEmpty()) { + // Add 'clear' + menu->addSeparator(); + clearAction = menu->addAction(VcsOutputWindow::tr("Clear")); + } // Run QAction *action = menu->exec(event->globalPos()); |