diff options
author | Eike Ziller <eike.ziller@qt.io> | 2019-11-01 15:31:19 +0100 |
---|---|---|
committer | Eike Ziller <eike.ziller@qt.io> | 2019-11-01 15:31:19 +0100 |
commit | 04bd6e39c8991fcb89ab15728f622a5a3ae8f0b2 (patch) | |
tree | 0517ecde8091d1680651853a4a9d209c0636cffd /src/plugins | |
parent | c92c255d1043f11478a61c1caae4069e7ef47114 (diff) | |
parent | a1d22fd2f79afab8b2379f6d93bcb417b9c8e7d5 (diff) | |
download | qt-creator-04bd6e39c8991fcb89ab15728f622a5a3ae8f0b2.tar.gz |
Merge remote-tracking branch 'origin/4.11'
Conflicts:
share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp
Change-Id: I8ea57eba526ab830608fd928c28771c5441749f8
Diffstat (limited to 'src/plugins')
89 files changed, 1230 insertions, 261 deletions
diff --git a/src/plugins/boot2qt/device-detection/qdbmessagetracker.cpp b/src/plugins/boot2qt/device-detection/qdbmessagetracker.cpp index 3e9bc558d0..8d623b6680 100644 --- a/src/plugins/boot2qt/device-detection/qdbmessagetracker.cpp +++ b/src/plugins/boot2qt/device-detection/qdbmessagetracker.cpp @@ -80,7 +80,7 @@ void QdbMessageTracker::handleWatchMessage(const QJsonDocument &document) } m_messageCache.append(message); - showMessage(tr("Qdb message: %1").arg(message), true); + showMessage(tr("QDB message: %1").arg(message), true); } } diff --git a/src/plugins/boot2qt/device-detection/qdbwatcher.cpp b/src/plugins/boot2qt/device-detection/qdbwatcher.cpp index e5a9b5c2ef..ee2b091fd3 100644 --- a/src/plugins/boot2qt/device-detection/qdbwatcher.cpp +++ b/src/plugins/boot2qt/device-detection/qdbwatcher.cpp @@ -109,7 +109,7 @@ void QdbWatcher::handleWatchError(QLocalSocket::LocalSocketError error) if (m_retried) { stop(); - emit watcherError(tr("Could not connect to QDB host server even after trying to start it")); + emit watcherError(tr("Could not connect to QDB host server even after trying to start it.")); return; } retry(); @@ -142,7 +142,7 @@ void QdbWatcher::forkHostServer() return; } if (QProcess::startDetached(qdbFilePath.toString(), {"server"})) - showMessage(tr("QDB host server started"), false); + showMessage(tr("QDB host server started."), false); else showMessage(tr("Could not start QDB host server in %1").arg(qdbFilePath.toString()), true); } @@ -153,7 +153,7 @@ void QdbWatcher::retry() { QMutexLocker lock(&s_startMutex); if (!s_startedServer) { - showMessage(tr("Starting QDB host server"), false); + showMessage(tr("Starting QDB host server."), false); forkHostServer(); s_startedServer = true; } diff --git a/src/plugins/boot2qt/qdbdevice.cpp b/src/plugins/boot2qt/qdbdevice.cpp index c6e388878d..e8b8186b50 100644 --- a/src/plugins/boot2qt/qdbdevice.cpp +++ b/src/plugins/boot2qt/qdbdevice.cpp @@ -93,7 +93,7 @@ public: Runnable r; r.setCommandLine(command); m_appRunner.start(r, device); - showMessage(QdbDevice::tr("Starting command '%1' on device '%2'.") + showMessage(QdbDevice::tr("Starting command \"%1\" on device \"%2\".") .arg(command.toUserOutput(), m_deviceName)); } @@ -112,18 +112,18 @@ private: if (!success) { QString errorString; if (!m_error.isEmpty()) { - errorString = QdbDevice::tr("Command failed on device '%1': %2") + errorString = QdbDevice::tr("Command failed on device \"%1\": %2") .arg(m_deviceName, m_error); } else { - errorString = QdbDevice::tr("Command failed on device '%1'.").arg(m_deviceName); + errorString = QdbDevice::tr("Command failed on device \"%1\".").arg(m_deviceName); } showMessage(errorString, true); if (!m_stdout.isEmpty()) - showMessage(QdbDevice::tr("stdout was: '%1'").arg(m_stdout)); + showMessage(QdbDevice::tr("stdout was: \"%1\"").arg(m_stdout)); if (!m_stderr.isEmpty()) - showMessage(QdbDevice::tr("stderr was: '%1'").arg(m_stderr)); + showMessage(QdbDevice::tr("stderr was: \"%1\"").arg(m_stderr)); } else { - showMessage(QdbDevice::tr("Commands on device '%1' finished successfully.") + showMessage(QdbDevice::tr("Commands on device \"%1\" finished successfully.") .arg(m_deviceName)); } deleteLater(); diff --git a/src/plugins/boot2qt/qdbmakedefaultappservice.cpp b/src/plugins/boot2qt/qdbmakedefaultappservice.cpp index fc7212b910..9512ac8f7d 100644 --- a/src/plugins/boot2qt/qdbmakedefaultappservice.cpp +++ b/src/plugins/boot2qt/qdbmakedefaultappservice.cpp @@ -77,7 +77,7 @@ void QdbMakeDefaultAppService::handleProcessFinished(const QString &error) QByteArray processOutput = d->processRunner->readAllStandardOutput(); if (d->makeDefault) - emit progressMessage(tr("Application made as the default one.")); + emit progressMessage(tr("Application set as the default one.")); else emit progressMessage(tr("Reset the default application.")); diff --git a/src/plugins/clangtools/clangtool.cpp b/src/plugins/clangtools/clangtool.cpp index 6b645ad952..607b78680c 100644 --- a/src/plugins/clangtools/clangtool.cpp +++ b/src/plugins/clangtools/clangtool.cpp @@ -495,12 +495,13 @@ void ClangTool::startTool(ClangTool::FileSelection fileSelection, }); m_perspective.select(); - m_diagnosticModel->clear(); - setToolBusy(true); m_diagnosticFilterModel->setProject(project); + m_applyFixitsButton->setEnabled(false); m_running = true; + + setToolBusy(true); handleStateUpdate(); updateRunActions(); diff --git a/src/plugins/clangtools/clangtoolruncontrol.cpp b/src/plugins/clangtools/clangtoolruncontrol.cpp index 6d870d93c8..e58b77a769 100644 --- a/src/plugins/clangtools/clangtoolruncontrol.cpp +++ b/src/plugins/clangtools/clangtoolruncontrol.cpp @@ -227,6 +227,7 @@ ClangToolRunWorker::ClangToolRunWorker(RunControl *runControl, const FileInfos &fileInfos, bool preventBuild) : RunWorker(runControl) + , m_runSettings(runSettings) , m_diagnosticConfig(diagnosticConfig) , m_fileInfos(fileInfos) , m_temporaryDir("clangtools-XXXXXX") @@ -305,7 +306,7 @@ void ClangToolRunWorker::start() // Create log dir if (!m_temporaryDir.isValid()) { const QString errorMessage - = tr("%1: Failed to create temporary dir, stop.").arg(toolName); + = tr("%1: Failed to create temporary directory. Stopped.").arg(toolName); appendMessage(errorMessage, Utils::ErrorMessageFormat); TaskHub::addTask(Task::Error, errorMessage, Debugger::Constants::ANALYZERTASK_ID); TaskHub::requestPopup(); @@ -390,7 +391,7 @@ void ClangToolRunWorker::analyzeNextFile() const QString executable = runner->executable(); if (!isFileExecutable(executable)) { - const QString errorMessage = tr("%1: Invalid executable \"%2\", stop.") + const QString errorMessage = tr("%1: Invalid executable \"%2\". Stopped.") .arg(runner->name(), executable); TaskHub::addTask(Task::Error, errorMessage, Debugger::Constants::ANALYZERTASK_ID); TaskHub::requestPopup(); diff --git a/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp b/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp index 6ac802d973..6608bb3ea4 100644 --- a/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp +++ b/src/plugins/clangtools/clangtoolsdiagnosticmodel.cpp @@ -101,10 +101,10 @@ QDebug operator<<(QDebug debug, const Diagnostic &d) void ClangToolsDiagnosticModel::addDiagnostics(const Diagnostics &diagnostics) { - const auto onFixitStatusChanged = [this](FixitStatus newStatus) { + const auto onFixitStatusChanged = [this](FixitStatus oldStatus, FixitStatus newStatus) { if (newStatus == FixitStatus::Scheduled) ++m_fixItsToApplyCount; - else + else if (oldStatus == FixitStatus::Scheduled) --m_fixItsToApplyCount; emit fixItsToApplyCountChanged(m_fixItsToApplyCount); }; @@ -463,7 +463,7 @@ void DiagnosticItem::setFixItStatus(const FixitStatus &status) m_fixitStatus = status; update(); if (m_onFixitStatusChanged && status != oldStatus) - m_onFixitStatusChanged(status); + m_onFixitStatusChanged(oldStatus, status); } void DiagnosticItem::setFixitOperations(const ReplacementOperations &replacements) diff --git a/src/plugins/clangtools/clangtoolsdiagnosticmodel.h b/src/plugins/clangtools/clangtoolsdiagnosticmodel.h index 3ac1df0d0c..d9fb8b4cfb 100644 --- a/src/plugins/clangtools/clangtoolsdiagnosticmodel.h +++ b/src/plugins/clangtools/clangtoolsdiagnosticmodel.h @@ -71,8 +71,9 @@ private: class DiagnosticItem : public Utils::TreeItem { public: - using OnFixitStatusChanged = std::function<void(FixitStatus newStatus)>; - DiagnosticItem(const Diagnostic &diag, const OnFixitStatusChanged &onFixitStatusChanged, + using OnFixitStatusChanged = std::function<void(FixitStatus oldStatus, FixitStatus newStatus)>; + DiagnosticItem(const Diagnostic &diag, + const OnFixitStatusChanged &onFixitStatusChanged, ClangToolsDiagnosticModel *parent); ~DiagnosticItem() override; diff --git a/src/plugins/clangtools/clangtoolsdiagnosticview.cpp b/src/plugins/clangtools/clangtoolsdiagnosticview.cpp index 4408a597b7..769266b5e0 100644 --- a/src/plugins/clangtools/clangtoolsdiagnosticview.cpp +++ b/src/plugins/clangtools/clangtoolsdiagnosticview.cpp @@ -283,7 +283,7 @@ bool DiagnosticView::eventFilter(QObject *watched, QEvent *event) return true; } default: - return QObject::eventFilter(watched, event); + return QAbstractItemView::eventFilter(watched, event); } } diff --git a/src/plugins/clangtools/clangtoolsprojectsettings.cpp b/src/plugins/clangtools/clangtoolsprojectsettings.cpp index 005897b49c..c7d692704e 100644 --- a/src/plugins/clangtools/clangtoolsprojectsettings.cpp +++ b/src/plugins/clangtools/clangtoolsprojectsettings.cpp @@ -105,7 +105,7 @@ void ClangToolsProjectSettings::load() // Load map QVariantMap map = m_project->namedSettings(SETTINGS_KEY_MAIN).toMap(); - bool write; + bool write = false; if (map.isEmpty()) { if (!m_project->namedSettings(SETTINGS_KEY_SELECTED_DIRS).isNull()) { map = convertToMapFromVersionBefore410(m_project); diff --git a/src/plugins/classview/classviewparsertreeitem.cpp b/src/plugins/classview/classviewparsertreeitem.cpp index eb2009c5ed..e80dc3e25b 100644 --- a/src/plugins/classview/classviewparsertreeitem.cpp +++ b/src/plugins/classview/classviewparsertreeitem.cpp @@ -333,11 +333,7 @@ bool ParserTreeItem::canFetchMore(QStandardItem *item) const int storedChildren = item->rowCount(); int internalChildren = d->symbolInformations.count(); - - if (storedChildren < internalChildren) - return true; - - return false; + return storedChildren < internalChildren; } /*! diff --git a/src/plugins/cmakeprojectmanager/cmakeautocompleter.cpp b/src/plugins/cmakeprojectmanager/cmakeautocompleter.cpp index eca893b8ea..eb9ae0c76f 100644 --- a/src/plugins/cmakeprojectmanager/cmakeautocompleter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeautocompleter.cpp @@ -45,10 +45,7 @@ bool CMakeAutoCompleter::isInComment(const QTextCursor &cursor) const // NOTE: This doesn't handle '#' inside quotes, nor multi-line comments QTextCursor moved = cursor; moved.movePosition(QTextCursor::StartOfLine, QTextCursor::KeepAnchor); - if (moved.selectedText().contains(QLatin1Char('#'))) - return true; - else - return false; + return moved.selectedText().contains(QLatin1Char('#')); } bool CMakeAutoCompleter::isInString(const QTextCursor &cursor) const diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index c1d5f04142..ae1e20972f 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -151,7 +151,6 @@ void CMakeBuildSystem::handleTreeScanningFinished() qDeleteAll(m_allFiles); m_allFiles = Utils::transform(m_treeScanner.release(), [](const FileNode *fn) { return fn; }); - m_combinedScanAndParseResult = m_combinedScanAndParseResult && true; m_waitingForScan = false; combineScanAndParse(); @@ -165,7 +164,6 @@ void CMakeBuildSystem::handleParsingSuccess(CMakeBuildConfiguration *bc) QTC_ASSERT(m_waitingForParse, return ); m_waitingForParse = false; - m_combinedScanAndParseResult = m_combinedScanAndParseResult && true; combineScanAndParse(); } diff --git a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp index e5d20de5dd..8517a5ee7f 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprocess.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprocess.cpp @@ -215,12 +215,12 @@ void CMakeProcess::handleProcessFinished(int code, QProcess::ExitStatus status) QString msg; if (status != QProcess::NormalExit) { if (m_processWasCanceled) { - msg = tr("*** cmake process was canceled by the user."); + msg = tr("CMake process was canceled by the user."); } else { - msg = tr("*** cmake process crashed."); + msg = tr("CMake process crashed."); } } else if (code != 0) { - msg = tr("*** cmake process exited with exit code %1.").arg(code); + msg = tr("CMake process exited with exit code %1.").arg(code); } if (!msg.isEmpty()) { diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp index 4739d0f808..9943ca5784 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectnodes.cpp @@ -88,7 +88,7 @@ void noAutoAdditionNotify(const QStringList &filePaths, const ProjectExplorer::P "\nCopy the path to the source files to the clipboard?"), "Remember My Choice", &checkValue, QDialogButtonBox::Yes | QDialogButtonBox::No, QDialogButtonBox::Yes); - if (true == checkValue) { + if (checkValue) { if (QDialogButtonBox::Yes == reply) settings->setAfterAddFileSetting(AfterAddFileAction::COPY_FILE_PATH); else if (QDialogButtonBox::No == reply) diff --git a/src/plugins/cmakeprojectmanager/fileapiparser.cpp b/src/plugins/cmakeprojectmanager/fileapiparser.cpp index 657f798ceb..25dc5d701e 100644 --- a/src/plugins/cmakeprojectmanager/fileapiparser.cpp +++ b/src/plugins/cmakeprojectmanager/fileapiparser.cpp @@ -57,7 +57,7 @@ static void reportFileApiSetupFailure() { Core::MessageManager::write(QCoreApplication::translate( "CMakeProjectManager::Internal", - "Failed to set up cmake fileapi support. Creator can not extract project information.")); + "Failed to set up CMake file API support. Qt Creator can not extract project information.")); } static std::pair<int, int> cmakeVersion(const QJsonObject &obj) @@ -112,7 +112,7 @@ static ReplyFileContents readReplyFile(const QFileInfo &fi, QString &errorMessag { const QJsonDocument document = readJsonFile(fi.filePath()); static const QString msg = QCoreApplication::translate("CMakeProjectManager::Internal", - "Invalid reply file created by cmake."); + "Invalid reply file created by CMake."); ReplyFileContents result; if (document.isNull() || document.isEmpty() || !document.isObject()) { @@ -175,7 +175,7 @@ static CMakeConfig readCacheFile(const QString &cacheFile, QString &errorMessage if (!checkJsonObject(root, "cache", 2)) { errorMessage = QCoreApplication::translate("CMakeProjectManager::Internal", - "Invalid cache file generated by cmake."); + "Invalid cache file generated by CMake."); return {}; } @@ -221,7 +221,7 @@ std::vector<CMakeFileInfo> readCMakeFilesFile(const QString &cmakeFilesFile, QSt if (!checkJsonObject(root, "cmakeFiles", 1)) { errorMessage = QCoreApplication::translate("CMakeProjectManager::Internal", - "Invalid cmakeFiles file generated by cmake."); + "Invalid cmakeFiles file generated by CMake."); return {}; } @@ -252,7 +252,7 @@ std::vector<Directory> extractDirectories(const QJsonArray &directories, QString if (directories.isEmpty()) { errorMessage = QCoreApplication::translate( "CMakeProjectManager::Internal", - "Invalid codemodel file generated by cmake: No directories."); + "Invalid codemodel file generated by CMake: No directories."); return {}; } @@ -262,7 +262,7 @@ std::vector<Directory> extractDirectories(const QJsonArray &directories, QString if (obj.isEmpty()) { errorMessage = QCoreApplication::translate( "CMakeProjectManager::Internal", - "Invalid codemodel file generated by cmake: Empty directory object."); + "Invalid codemodel file generated by CMake: Empty directory object."); continue; } Directory dir; @@ -284,7 +284,7 @@ static std::vector<Project> extractProjects(const QJsonArray &projects, QString if (projects.isEmpty()) { errorMessage = QCoreApplication::translate( "CMakeProjectManager::Internal", - "Invalid codemodel file generated by cmake: No projects."); + "Invalid codemodel file generated by CMake: No projects."); return {}; } @@ -294,7 +294,7 @@ static std::vector<Project> extractProjects(const QJsonArray &projects, QString if (obj.isEmpty()) { errorMessage = QCoreApplication::translate( "CMakeProjectManager::Internal", - "Invalid codemodel file generated by cmake: Empty project object."); + "Invalid codemodel file generated by CMake: Empty project object."); continue; } Project project; @@ -309,7 +309,7 @@ static std::vector<Project> extractProjects(const QJsonArray &projects, QString if (project.name.isEmpty() || project.directories.empty()) { errorMessage = QCoreApplication::translate( "CMakeProjectManager::Internal", - "Invalid codemodel file generated by cmake: Broken project data."); + "Invalid codemodel file generated by CMake: Broken project data."); continue; } @@ -323,7 +323,7 @@ static std::vector<Target> extractTargets(const QJsonArray &targets, QString &er if (targets.isEmpty()) { errorMessage = QCoreApplication::translate("CMakeProjectManager::Internal", - "Invalid codemodel file generated by cmake: No targets."); + "Invalid codemodel file generated by CMake: No targets."); return {}; } @@ -333,7 +333,7 @@ static std::vector<Target> extractTargets(const QJsonArray &targets, QString &er if (obj.isEmpty()) { errorMessage = QCoreApplication::translate( "CMakeProjectManager::Internal", - "Invalid codemodel file generated by cmake: Empty target object."); + "Invalid codemodel file generated by CMake: Empty target object."); continue; } Target target; @@ -347,7 +347,7 @@ static std::vector<Target> extractTargets(const QJsonArray &targets, QString &er || target.directory == -1 || target.project == -1) { errorMessage = QCoreApplication::translate( "CMakeProjectManager::Internal", - "Invalid codemodel file generated by cmake: Broken target data."); + "Invalid codemodel file generated by CMake: Broken target data."); continue; } @@ -448,7 +448,7 @@ static std::vector<Configuration> extractConfigurations(const QJsonArray &config if (configs.isEmpty()) { errorMessage = QCoreApplication::translate( "CMakeProjectManager::Internal", - "Invalid codemodel file generated by cmake: No configurations."); + "Invalid codemodel file generated by CMake: No configurations."); return {}; } @@ -458,7 +458,7 @@ static std::vector<Configuration> extractConfigurations(const QJsonArray &config if (obj.isEmpty()) { errorMessage = QCoreApplication::translate( "CMakeProjectManager::Internal", - "Invalid codemodel file generated by cmake: Empty configuration object."); + "Invalid codemodel file generated by CMake: Empty configuration object."); continue; } Configuration config; @@ -471,8 +471,8 @@ static std::vector<Configuration> extractConfigurations(const QJsonArray &config if (!validateIndexes(config)) { errorMessage = QCoreApplication::translate("CMakeProjectManager::Internal", - "Invalid codemodel file generated by cmake: Broken " - "indexes in directories/projects/targets."); + "Invalid codemodel file generated by CMake: Broken " + "indexes in directories, projects, or targets."); return {}; } @@ -489,7 +489,7 @@ static std::vector<Configuration> readCodemodelFile(const QString &codemodelFile if (!checkJsonObject(root, "codemodel", 2)) { errorMessage = QCoreApplication::translate("CMakeProjectManager::Internal", - "Invalid codemodel file generated by cmake."); + "Invalid codemodel file generated by CMake."); return {}; } @@ -787,7 +787,7 @@ TargetDetails readTargetFile(const QString &targetFile, QString &errorMessage) if (errorMessage.isEmpty() && !validateTargetDetails(result)) { errorMessage = QCoreApplication::translate( "CMakeProjectManager::Internal", - "Invalid target file generated by cmake: Broken indexes in target details."); + "Invalid target file generated by CMake: Broken indexes in target details."); } return result; } diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp index 1affca78fa..7d045f329e 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp @@ -28,6 +28,7 @@ #include <projectexplorer/headerpath.h> #include <projectexplorer/projectmacro.h> +#include <utils/algorithm.h> #include <utils/hostosinfo.h> #include <utils/optional.h> @@ -155,14 +156,16 @@ void filteredFlags(const QString &fileName, continue; } - if ((flag.startsWith("-I") || flag.startsWith("-isystem") || flag.startsWith("/I")) - && flag != "-I" && flag != "-isystem" && flag != "/I") { - bool userInclude = flag.startsWith("-I"); - const QString pathStr = updatedPathFlag(flag.mid(userInclude ? 2 : 8), - workingDir); - headerPaths.append({pathStr, userInclude - ? HeaderPathType::User - : HeaderPathType::System}); + const QStringList userIncludeFlags{"-I", "/I"}; + const QStringList systemIncludeFlags{"-isystem", "-imsvc", "/imsvc"}; + const QStringList allIncludeFlags = QStringList(userIncludeFlags) << systemIncludeFlags; + const QString includeOpt = Utils::findOrDefault(allIncludeFlags, [flag](const QString &opt) { + return flag.startsWith(opt) && flag != opt; + }); + if (!includeOpt.isEmpty()) { + const QString pathStr = updatedPathFlag(flag.mid(includeOpt.length()), workingDir); + headerPaths.append({pathStr, userIncludeFlags.contains(includeOpt) + ? HeaderPathType::User : HeaderPathType::System}); continue; } @@ -174,8 +177,12 @@ void filteredFlags(const QString &fileName, continue; } - if (flag == "-I" || flag == "-isystem" || flag == "/I") { - includePathType = (flag != "-isystem") ? HeaderPathType::User : HeaderPathType::System; + if (userIncludeFlags.contains(flag)) { + includePathType = HeaderPathType::User; + continue; + } + if (systemIncludeFlags.contains(flag)) { + includePathType = HeaderPathType::System; continue; } diff --git a/src/plugins/coreplugin/documentmanager.cpp b/src/plugins/coreplugin/documentmanager.cpp index 43760ed547..e1308ca8fe 100644 --- a/src/plugins/coreplugin/documentmanager.cpp +++ b/src/plugins/coreplugin/documentmanager.cpp @@ -1199,7 +1199,6 @@ void DocumentManager::checkForReload() if (previousDeletedAnswer != FileDeletedCloseAll) { previousDeletedAnswer = fileDeletedPrompt(document->filePath().toString(), - trigger == IDocument::TriggerExternal, ICore::dialogParent()); } switch (previousDeletedAnswer) { diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 0be92efe8a..5ec572e5a0 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -2427,9 +2427,7 @@ IEditor *EditorManager::currentEditor() bool EditorManager::closeAllEditors(bool askAboutModifiedEditors) { DocumentModelPrivate::removeAllSuspendedEntries(); - if (closeDocuments(DocumentModel::openedDocuments(), askAboutModifiedEditors)) - return true; - return false; + return closeDocuments(DocumentModel::openedDocuments(), askAboutModifiedEditors); } void EditorManager::closeOtherDocuments(IDocument *document) diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp index 732f485824..94e5aa78fe 100644 --- a/src/plugins/coreplugin/mainwindow.cpp +++ b/src/plugins/coreplugin/mainwindow.cpp @@ -131,6 +131,7 @@ MainWindow::MainWindow() QCoreApplication::setApplicationName(QLatin1String(Constants::IDE_CASED_ID)); QCoreApplication::setApplicationVersion(QLatin1String(Constants::IDE_VERSION_LONG)); QCoreApplication::setOrganizationName(QLatin1String(Constants::IDE_SETTINGSVARIANT_STR)); + QGuiApplication::setApplicationDisplayName(QLatin1String(Constants::IDE_DISPLAY_NAME)); QString baseName = QApplication::style()->objectName(); // Sometimes we get the standard windows 95 style as a fallback if (HostOsInfo::isAnyUnixHost() && !HostOsInfo::isMacHost() diff --git a/src/plugins/coreplugin/manhattanstyle.cpp b/src/plugins/coreplugin/manhattanstyle.cpp index 544f57ad3e..f64275d332 100644 --- a/src/plugins/coreplugin/manhattanstyle.cpp +++ b/src/plugins/coreplugin/manhattanstyle.cpp @@ -273,10 +273,7 @@ void ManhattanStyle::polish(QWidget *widget) widget->setContentsMargins(0, 0, 0, 0); widget->setAttribute(Qt::WA_LayoutUsesWidgetRect, true); - if (qobject_cast<QToolButton*>(widget)) { - widget->setAttribute(Qt::WA_Hover); - widget->setMaximumHeight(StyleHelper::navigationWidgetHeight() - 2); - } else if (qobject_cast<QLineEdit*>(widget)) { + if (qobject_cast<QToolButton*>(widget) || qobject_cast<QLineEdit*>(widget)) { widget->setAttribute(Qt::WA_Hover); widget->setMaximumHeight(StyleHelper::navigationWidgetHeight() - 2); } else if (qobject_cast<QLabel*>(widget)) { @@ -303,12 +300,11 @@ void ManhattanStyle::unpolish(QWidget *widget) QProxyStyle::unpolish(widget); if (panelWidget(widget)) { widget->setAttribute(Qt::WA_LayoutUsesWidgetRect, false); - if (qobject_cast<QTabBar*>(widget)) - widget->setAttribute(Qt::WA_Hover, false); - else if (qobject_cast<QToolBar*>(widget)) - widget->setAttribute(Qt::WA_Hover, false); - else if (qobject_cast<QComboBox*>(widget)) + if (qobject_cast<QTabBar*>(widget) + || qobject_cast<QToolBar*>(widget) + || qobject_cast<QComboBox*>(widget)) { widget->setAttribute(Qt::WA_Hover, false); + } } } diff --git a/src/plugins/cppeditor/cppdocumentationcommenthelper.cpp b/src/plugins/cppeditor/cppdocumentationcommenthelper.cpp index 65c3dc9769..bb656d1900 100644 --- a/src/plugins/cppeditor/cppdocumentationcommenthelper.cpp +++ b/src/plugins/cppeditor/cppdocumentationcommenthelper.cpp @@ -88,10 +88,7 @@ bool isPreviousLineCppStyleComment(const QTextCursor &cursor) return false; const QString text = actual.text().trimmed(); - if (text.startsWith(QLatin1String("///")) || text.startsWith(QLatin1String("//!"))) - return true; - - return false; + return text.startsWith(QLatin1String("///")) || text.startsWith(QLatin1String("//!")); } /// Check if next line is a CppStyle Doxygen Comment @@ -106,10 +103,7 @@ bool isNextLineCppStyleComment(const QTextCursor &cursor) return false; const QString text = actual.text().trimmed(); - if (text.startsWith(QLatin1String("///")) || text.startsWith(QLatin1String("//!"))) - return true; - - return false; + return text.startsWith(QLatin1String("///")) || text.startsWith(QLatin1String("//!")); } bool isCppStyleContinuation(const QTextCursor& cursor) diff --git a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp index beb2e2aaf7..7368ecb416 100644 --- a/src/plugins/cppeditor/cppfunctiondecldeflink.cpp +++ b/src/plugins/cppeditor/cppfunctiondecldeflink.cpp @@ -442,9 +442,7 @@ static bool canReplaceSpecifier(TranslationUnit *translationUnit, SpecifierAST * return false; } } - if (specifier->asAttributeSpecifier()) - return false; - return true; + return !specifier->asAttributeSpecifier(); } static SpecifierAST *findFirstReplaceableSpecifier(TranslationUnit *translationUnit, SpecifierListAST *list) diff --git a/src/plugins/cppeditor/cppminimizableinfobars.cpp b/src/plugins/cppeditor/cppminimizableinfobars.cpp index f90ae64227..7e65829219 100644 --- a/src/plugins/cppeditor/cppminimizableinfobars.cpp +++ b/src/plugins/cppeditor/cppminimizableinfobars.cpp @@ -156,7 +156,7 @@ static InfoBarEntry createMinimizableInfo(const Id &id, void MinimizableInfoBars::addNoProjectConfigurationEntry(const Id &id) { const QString text = tr("<b>Warning</b>: This file is not part of any project. " - "The code model might have issues to parse this file properly."); + "The code model might have issues parsing this file properly."); m_infoBar.addInfo(createMinimizableInfo(id, text, []() { settings()->setShowNoProjectInfoBar(false); diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index 7689e960e0..d384322bdd 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -581,21 +581,11 @@ static bool checkDeclarationForSplit(SimpleDeclarationAST *declaration) for (SpecifierListAST *it = declaration->decl_specifier_list; it; it = it->next) { SpecifierAST *specifier = it->value; - - if (specifier->asEnumSpecifier() != nullptr) - return false; - - else if (specifier->asClassSpecifier() != nullptr) + if (specifier->asEnumSpecifier() || specifier->asClassSpecifier()) return false; } - if (!declaration->declarator_list) - return false; - - else if (!declaration->declarator_list->next) - return false; - - return true; + return declaration->declarator_list && declaration->declarator_list->next; } namespace { @@ -3502,9 +3492,7 @@ public: bool preVisit(AST *) override { - if (m_done) - return false; - return true; + return !m_done; } void statement(StatementAST *stmt) diff --git a/src/plugins/cpptools/compileroptionsbuilder.cpp b/src/plugins/cpptools/compileroptionsbuilder.cpp index aafcd35b37..ee534757ea 100644 --- a/src/plugins/cpptools/compileroptionsbuilder.cpp +++ b/src/plugins/cpptools/compileroptionsbuilder.cpp @@ -329,9 +329,14 @@ void CompilerOptionsBuilder::addPrecompiledHeaderOptions(UsePrecompiledHeaders u for (const QString &pchFile : m_projectPart.precompiledHeaders) { // Bail if build system precomiple header artifacts exists // Clang cannot handle foreign PCH files. - if (QFile::exists(pchFile + ".gch") || QFile::exists(pchFile + ".pch")) + if (QFile::exists(pchFile + ".gch") || QFile::exists(pchFile + ".pch")) { usePrecompiledHeaders = UsePrecompiledHeaders::No; + // In case of Clang compilers, remove the pch-inclusion arguments + remove({"-Xclang", "-include-pch", "-Xclang", pchFile + ".gch"}); + remove({"-Xclang", "-include-pch", "-Xclang", pchFile + ".pch"}); + } + if (usePrecompiledHeaders == UsePrecompiledHeaders::No) { // CMake PCH will already have force included the header file in // command line options, remove it if exists. diff --git a/src/plugins/cpptools/cppchecksymbols.cpp b/src/plugins/cpptools/cppchecksymbols.cpp index f4458bd059..b42875492a 100644 --- a/src/plugins/cpptools/cppchecksymbols.cpp +++ b/src/plugins/cpptools/cppchecksymbols.cpp @@ -461,11 +461,7 @@ Scope *CheckSymbols::enclosingScope() const bool CheckSymbols::preVisit(AST *ast) { _astStack.append(ast); - - if (isCanceled()) - return false; - - return true; + return !isCanceled(); } void CheckSymbols::postVisit(AST *) @@ -1256,13 +1252,12 @@ bool CheckSymbols::maybeAddTypeOrStatic(const QList<LookupItem> &candidates, Nam Symbol *c = r.declaration(); if (c->isUsingDeclaration()) // skip using declarations... continue; - else if (c->isUsingNamespaceDirective()) // ... and using namespace directives. + if (c->isUsingNamespaceDirective()) // ... and using namespace directives. continue; - else if (c->isTypedef() || c->isNamespace() || - c->isStatic() || //consider also static variable - c->isClass() || c->isEnum() || isTemplateClass(c) || - c->isForwardClassDeclaration() || c->isTypenameArgument() || c->enclosingEnum() != nullptr) { - + if (c->isTypedef() || c->isNamespace() || + c->isStatic() || //consider also static variable + c->isClass() || c->isEnum() || isTemplateClass(c) || + c->isForwardClassDeclaration() || c->isTypenameArgument() || c->enclosingEnum()) { int line, column; getTokenStartPosition(startToken, &line, &column); const unsigned length = tok.utf16chars(); @@ -1298,11 +1293,11 @@ bool CheckSymbols::maybeAddField(const QList<LookupItem> &candidates, NameAST *a Symbol *c = r.declaration(); if (!c) continue; - else if (!c->isDeclaration()) + if (!c->isDeclaration()) return false; - else if (!(c->enclosingScope() && c->enclosingScope()->isClass())) + if (!(c->enclosingScope() && c->enclosingScope()->isClass())) return false; // shadowed - else if (c->isTypedef() || (c->type() && c->type()->isFunctionType())) + if (c->isTypedef() || (c->type() && c->type()->isFunctionType())) return false; // shadowed int line, column; diff --git a/src/plugins/cpptools/cppcodeformatter.cpp b/src/plugins/cpptools/cppcodeformatter.cpp index fca7998ece..413a5fde7b 100644 --- a/src/plugins/cpptools/cppcodeformatter.cpp +++ b/src/plugins/cpptools/cppcodeformatter.cpp @@ -179,8 +179,8 @@ void CodeFormatter::recalculateStateAfter(const QTextBlock &block) switch (kind) { case T_LBRACE: enter(brace_list_open); break; case T_RBRACE: leave(true); continue; - case T_SEMICOLON: leave(); continue; - case T_RPAREN: leave(); continue; + case T_SEMICOLON: + case T_RPAREN: case T_COMMA: leave(); continue; default: enter(assign_open); continue; } break; @@ -205,8 +205,8 @@ void CodeFormatter::recalculateStateAfter(const QTextBlock &block) case assign_open: switch (kind) { case T_RBRACE: leave(true); continue; - case T_SEMICOLON: leave(); continue; - case T_RPAREN: leave(); continue; + case T_SEMICOLON: + case T_RPAREN: case T_COMMA: leave(); continue; default: tryExpression(); break; } break; diff --git a/src/plugins/cpptools/cppcompletionassistprovider.cpp b/src/plugins/cpptools/cppcompletionassistprovider.cpp index a06c4c7b42..08100dba44 100644 --- a/src/plugins/cpptools/cppcompletionassistprovider.cpp +++ b/src/plugins/cpptools/cppcompletionassistprovider.cpp @@ -51,9 +51,7 @@ bool CppCompletionAssistProvider::isActivationCharSequence(const QString &sequen const QChar &ch = sequence.at(2); const QChar &ch2 = sequence.at(1); const QChar &ch3 = sequence.at(0); - if (activationSequenceChar(ch, ch2, ch3, nullptr, true, false) != 0) - return true; - return false; + return activationSequenceChar(ch, ch2, ch3, nullptr, true, false); } bool CppCompletionAssistProvider::isContinuationChar(const QChar &c) const diff --git a/src/plugins/cpptools/cppfollowsymbolundercursor.cpp b/src/plugins/cpptools/cppfollowsymbolundercursor.cpp index 9a66467951..ded069a96e 100644 --- a/src/plugins/cpptools/cppfollowsymbolundercursor.cpp +++ b/src/plugins/cpptools/cppfollowsymbolundercursor.cpp @@ -374,7 +374,7 @@ Symbol *findDefinition(Symbol *symbol, const Snapshot &snapshot, SymbolFinder *s if (symbol->isFunction()) return nullptr; // symbol is a function definition. - else if (!symbol->type()->isFunctionType()) + if (!symbol->type()->isFunctionType()) return nullptr; // not a function declaration return symbolFinder->findMatchingDefinition(symbol, snapshot); diff --git a/src/plugins/cpptools/cpprefactoringchanges.cpp b/src/plugins/cpptools/cpprefactoringchanges.cpp index 4d16dd4813..c063e1efdd 100644 --- a/src/plugins/cpptools/cpprefactoringchanges.cpp +++ b/src/plugins/cpptools/cpprefactoringchanges.cpp @@ -172,10 +172,7 @@ bool CppRefactoringFile::isCursorOn(unsigned tokenIndex) const int start = startOf(tokenIndex); int end = endOf(tokenIndex); - if (cursorBegin >= start && cursorBegin <= end) - return true; - - return false; + return cursorBegin >= start && cursorBegin <= end; } bool CppRefactoringFile::isCursorOn(const AST *ast) const @@ -186,10 +183,7 @@ bool CppRefactoringFile::isCursorOn(const AST *ast) const int start = startOf(ast); int end = endOf(ast); - if (cursorBegin >= start && cursorBegin <= end) - return true; - - return false; + return cursorBegin >= start && cursorBegin <= end; } Utils::ChangeSet::Range CppRefactoringFile::range(unsigned tokenIndex) const diff --git a/src/plugins/cpptools/semantichighlighter.cpp b/src/plugins/cpptools/semantichighlighter.cpp index 5c7c8110ca..2fdce4c743 100644 --- a/src/plugins/cpptools/semantichighlighter.cpp +++ b/src/plugins/cpptools/semantichighlighter.cpp @@ -87,7 +87,7 @@ void SemanticHighlighter::onHighlighterResultAvailable(int from, int to) { if (documentRevision() != m_revision) return; // outdated - else if (!m_watcher || m_watcher->isCanceled()) + if (!m_watcher || m_watcher->isCanceled()) return; // aborted qCDebug(log) << "onHighlighterResultAvailable()" << from << to; diff --git a/src/plugins/debugger/breakhandler.cpp b/src/plugins/debugger/breakhandler.cpp index 90dd8f3c86..6015f29dec 100644 --- a/src/plugins/debugger/breakhandler.cpp +++ b/src/plugins/debugger/breakhandler.cpp @@ -1065,6 +1065,7 @@ QVariant BreakpointItem::data(int column, int role) const if (role == Qt::DisplayRole) { if (!m_parameters.functionName.isEmpty()) return simplifyType(m_parameters.functionName); + if (m_parameters.type == BreakpointAtMain || m_parameters.type == BreakpointAtThrow || m_parameters.type == BreakpointAtCatch @@ -1073,15 +1074,13 @@ QVariant BreakpointItem::data(int column, int role) const //|| m_response.type == BreakpointAtVFork || m_parameters.type == BreakpointAtSysCall) return typeToString(m_parameters.type); - if (m_parameters.type == WatchpointAtAddress) { - quint64 address = m_parameters.address ? m_parameters.address : m_parameters.address; - return BreakHandler::tr("Data at 0x%1").arg(address, 0, 16); - } - if (m_parameters.type == WatchpointAtExpression) { - QString expression = !m_parameters.expression.isEmpty() - ? m_parameters.expression : m_parameters.expression; - return BreakHandler::tr("Data at %1").arg(expression); - } + + if (m_parameters.type == WatchpointAtAddress) + return BreakHandler::tr("Data at 0x%1").arg(m_parameters.address, 0, 16); + + if (m_parameters.type == WatchpointAtExpression) + return BreakHandler::tr("Data at %1").arg(m_parameters.expression); + return empty; } break; diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 4e04a02fc4..798013ed42 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -394,14 +394,7 @@ void CdbEngine::setupEngine() if (!sourcePaths.isEmpty()) debugger.addArgs({"-srcpath", sourcePaths.join(';')}); - QStringList symbolPaths = stringListSetting(CdbSymbolPaths); - QString symbolPath = sp.inferior.environment.expandedValueForKey("_NT_ALT_SYMBOL_PATH"); - if (!symbolPath.isEmpty()) - symbolPaths += symbolPath; - symbolPath = sp.inferior.environment.expandedValueForKey("_NT_SYMBOL_PATH"); - if (!symbolPath.isEmpty()) - symbolPaths += symbolPath; - debugger.addArgs({"-y", symbolPaths.join(';')}); + debugger.addArgs({"-y", QChar('"') + stringListSetting(CdbSymbolPaths).join(';') + '"'}); switch (sp.startMode) { case StartInternal: @@ -501,6 +494,16 @@ void CdbEngine::handleInitialSessionIdle() } // Take ownership of the breakpoint. Requests insertion. TODO: Cpp only? BreakpointManager::claimBreakpointsForEngine(this); + + QStringList symbolPaths = stringListSetting(CdbSymbolPaths); + QString symbolPath = rp.inferior.environment.expandedValueForKey("_NT_ALT_SYMBOL_PATH"); + if (!symbolPath.isEmpty()) + symbolPaths += symbolPath; + symbolPath = rp.inferior.environment.expandedValueForKey("_NT_SYMBOL_PATH"); + if (!symbolPath.isEmpty()) + symbolPaths += symbolPath; + + runCommand({QString(".sympath \"") + symbolPaths.join(';') + '"'}); runCommand({".symopt+0x8000"}); // disable searching public symbol table - improving the symbol lookup speed runCommand({"sxn 0x4000001f", NoFlags}); // Do not break on WowX86 exceptions. runCommand({"sxn ibp", NoFlags}); // Do not break on initial breakpoints. diff --git a/src/plugins/debugger/debuggeritem.cpp b/src/plugins/debugger/debuggeritem.cpp index 0fcd7a165a..3287095d82 100644 --- a/src/plugins/debugger/debuggeritem.cpp +++ b/src/plugins/debugger/debuggeritem.cpp @@ -381,6 +381,11 @@ static DebuggerItem::MatchLevel matchSingle(const Abi &debuggerAbi, const Abi &t return DebuggerItem::DoesNotMatch; // We have at least 'Matches well' now. Mark the combinations we really like. + if (HostOsInfo::isWindowsHost() && engineType == CdbEngineType + && targetAbi.osFlavor() >= Abi::WindowsMsvc2005Flavor + && targetAbi.osFlavor() <= Abi::WindowsLastMsvcFlavor) { + return DebuggerItem::MatchesPerfectly; + } if (HostOsInfo::isWindowsHost() && engineType == GdbEngineType && targetAbi.osFlavor() == Abi::WindowsMSysFlavor) return DebuggerItem::MatchesPerfectly; if (HostOsInfo::isLinuxHost() && engineType == GdbEngineType && targetAbi.os() == Abi::LinuxOS) diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index ff0197c225..6cf048420e 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -806,7 +806,7 @@ void GdbEngine::runCommand(const DebuggerCommand &command) int GdbEngine::commandTimeoutTime() const { int time = action(GdbWatchdogTimeout)->value().toInt(); - return 1000 * qMax(40, time); + return 1000 * qMax(20, time); } void GdbEngine::commandTimeout() diff --git a/src/plugins/debugger/moduleshandler.cpp b/src/plugins/debugger/moduleshandler.cpp index 9cb88b077e..4fd1e40669 100644 --- a/src/plugins/debugger/moduleshandler.cpp +++ b/src/plugins/debugger/moduleshandler.cpp @@ -111,9 +111,6 @@ QVariant ModuleItem::data(int column, int role) const "information.\nStepping into the module or setting " "breakpoints by file and line will not work."); case PlainSymbols: - return tr("This module contains debug information.\nStepping " - "into the module or setting breakpoints by file and " - "line is expected to work."); case FastSymbols: return tr("This module contains debug information.\nStepping " "into the module or setting breakpoints by file and " diff --git a/src/plugins/help/localhelpmanager.cpp b/src/plugins/help/localhelpmanager.cpp index 0a29750b85..8af763f426 100644 --- a/src/plugins/help/localhelpmanager.cpp +++ b/src/plugins/help/localhelpmanager.cpp @@ -544,12 +544,9 @@ void LocalHelpManager::updateFilterModel() bool LocalHelpManager::canOpenOnlineHelp(const QUrl &url) { const QString address = url.toString(); - if (address.startsWith("qthelp://org.qt-project.") - || address.startsWith("qthelp://com.nokia.") - || address.startsWith("qthelp://com.trolltech.")) { - return true; - } - return false; + return address.startsWith("qthelp://org.qt-project.") + || address.startsWith("qthelp://com.nokia.") + || address.startsWith("qthelp://com.trolltech."); } bool LocalHelpManager::openOnlineHelp(const QUrl &url) diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 83b67eadbc..defbd0bdac 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -459,7 +459,7 @@ void LanguageClientManager::openDocumentWithClient(TextEditor::TextDocument *doc void LanguageClientManager::documentClosed(Core::IDocument *document) { if (auto textDocument = qobject_cast<TextEditor::TextDocument *>(document)) { - for (Client *client : reachableClients()) + for (Client *client : m_clients) client->closeDocument(textDocument); m_clientForDocument.remove(textDocument); } diff --git a/src/plugins/languageclient/languageclientutils.cpp b/src/plugins/languageclient/languageclientutils.cpp index c476aaabcf..22c43650ee 100644 --- a/src/plugins/languageclient/languageclientutils.cpp +++ b/src/plugins/languageclient/languageclientutils.cpp @@ -213,6 +213,7 @@ void updateEditorToolBar(Core::IEditor *editor) } else { widget->toolBar()->removeAction(action); actions.remove(widget); + delete action; } } else if (client) { const QIcon icon = Utils::Icon({{":/languageclient/images/languageclient.png", diff --git a/src/plugins/mcusupport/mcusupportoptions.cpp b/src/plugins/mcusupport/mcusupportoptions.cpp index c61a3b6f6d..9cbd8a5a83 100644 --- a/src/plugins/mcusupport/mcusupportoptions.cpp +++ b/src/plugins/mcusupport/mcusupportoptions.cpp @@ -234,11 +234,26 @@ static PackageOptions *createQulPackage() static PackageOptions *createArmGccPackage() { - const QString defaultPath = - Utils::HostOsInfo::isWindowsHost() ? - QDir::fromNativeSeparators(qEnvironmentVariable("ProgramFiles(x86)")) - + "/GNU Tools ARM Embedded/" - : QString("%{Env:ARMGCC_DIR}"); + const char envVar[] = "ARMGCC_DIR"; + + QString defaultPath; + if (qEnvironmentVariableIsSet(envVar)) + defaultPath = qEnvironmentVariable(envVar); + if (defaultPath.isEmpty() && Utils::HostOsInfo::isWindowsHost()) { + const QDir installDir( + qEnvironmentVariable("ProgramFiles(x86)") + "/GNU Tools ARM Embedded/"); + if (installDir.exists()) { + // If GNU Tools installation dir has only one sub dir, + // select the sub dir, otherwise the installation dir. + const QFileInfoList subDirs = + installDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); + if (subDirs.count() == 1) + defaultPath = subDirs.first().filePath() + '/'; + } + } + if (defaultPath.isEmpty()) + defaultPath = QDir::homePath(); + auto result = new PackageOptions( PackageOptions::tr("GNU Arm Embedded Toolchain"), defaultPath, @@ -246,7 +261,7 @@ static PackageOptions *createArmGccPackage() Constants::SETTINGS_KEY_PACKAGE_ARMGCC); result->setDownloadUrl( "https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads"); - result->setEnvironmentVariableName("ARMGCC_DIR"); + result->setEnvironmentVariableName(envVar); return result; } @@ -286,8 +301,8 @@ static PackageOptions *createStm32CubeProgrammerPackage() static PackageOptions *createEvkbImxrt1050SdkPackage() { auto result = new PackageOptions( - PackageOptions::tr("NXP EVKB-IMXRT1050 SDK"), - "%{Env:EVKB_IMXRT1050_SDK_PATH}", + PackageOptions::tr("NXP i.MXRT SDK"), + "%{Env:EVKB_IMXRT1050_SDK_PATH}", // TODO: Try to not use 1050 specifics "EVKB-IMXRT1050_manifest_v3_5.xml", "evkbImxrt1050Sdk"); result->setDownloadUrl("https://mcuxpresso.nxp.com/en/welcome"); @@ -306,6 +321,7 @@ static PackageOptions *createSeggerJLinkPackage() Utils::HostOsInfo::withExecutableSuffix("JLink"), "seggerJLink"); result->setDownloadUrl("https://www.segger.com/downloads/jlink"); + result->setEnvironmentVariableName("SEGGER_JLINK_SOFTWARE_AND_DOCUMENTATION_PATH"); return result; } @@ -454,10 +470,11 @@ static void setKitEnvironment(ProjectExplorer::Kit *k, const BoardOptions* board changes.append({package->environmentVariableName(), QDir::toNativeSeparators(package->path())}); } - if (!pathAdditions.isEmpty()) { - pathAdditions.append("${Path}"); - changes.append({"Path", pathAdditions.join(Utils::HostOsInfo::pathListSeparator())}); - } + pathAdditions.append("${Path}"); + if (Utils::HostOsInfo::isWindowsHost()) + pathAdditions.append(QDir::toNativeSeparators(Core::ICore::libexecPath())); // for jom + pathAdditions.append(QDir::toNativeSeparators(Core::ICore::libexecPath() + "/clang/bin")); + changes.append({"Path", pathAdditions.join(Utils::HostOsInfo::pathListSeparator())}); EnvironmentKitAspect::setEnvironmentChanges(k, changes); } @@ -470,6 +487,8 @@ static void setKitCMakeOptions(ProjectExplorer::Kit *k, const BoardOptions* boar ("%{CurrentBuild:Env:Qul_DIR}/" + board->toolChainFile()).toUtf8())); CMakeConfigurationKitAspect::setConfiguration(k, config); + if (Utils::HostOsInfo::isWindowsHost()) + CMakeGeneratorKitAspect::setGenerator(k, "NMake Makefiles JOM"); } ProjectExplorer::Kit *McuSupportOptions::kit(const BoardOptions* board) diff --git a/src/plugins/mcusupport/mcusupportoptionspage.cpp b/src/plugins/mcusupport/mcusupportoptionspage.cpp index 1396d4226f..9057e2a054 100644 --- a/src/plugins/mcusupport/mcusupportoptionspage.cpp +++ b/src/plugins/mcusupport/mcusupportoptionspage.cpp @@ -68,7 +68,7 @@ McuSupportOptionsWidget::McuSupportOptionsWidget(const McuSupportOptions *option auto mainLayout = new QVBoxLayout(this); auto boardChooserlayout = new QHBoxLayout; - auto boardChooserLabel = new QLabel(McuSupportOptionsPage::tr("MCU board:")); + auto boardChooserLabel = new QLabel(McuSupportOptionsPage::tr("Target:")); boardChooserlayout->addWidget(boardChooserLabel); auto boardComboBox = new QComboBox; boardChooserLabel->setBuddy(boardComboBox); diff --git a/src/plugins/mcusupport/mcusupportrunconfiguration.cpp b/src/plugins/mcusupport/mcusupportrunconfiguration.cpp index 92dcb4181f..4ec72227e1 100644 --- a/src/plugins/mcusupport/mcusupportrunconfiguration.cpp +++ b/src/plugins/mcusupport/mcusupportrunconfiguration.cpp @@ -94,6 +94,7 @@ public: r.workingDirectory = target->activeBuildConfiguration()->buildDirectory().toUserOutput(); r.setCommandLine(cmd); + r.environment = target->activeBuildConfiguration()->environment(); SimpleTargetRunner::doStart(r, {}); }); } diff --git a/src/plugins/projectexplorer/abi.cpp b/src/plugins/projectexplorer/abi.cpp index 420a10ba98..42a34bbcdc 100644 --- a/src/plugins/projectexplorer/abi.cpp +++ b/src/plugins/projectexplorer/abi.cpp @@ -209,7 +209,6 @@ static Abi macAbiForCpu(quint32 type) { case 0x01000000 + 7: // CPU_TYPE_X86_64 return Abi(Abi::X86Architecture, Abi::DarwinOS, Abi::GenericFlavor, Abi::MachOFormat, 64); case 18: // CPU_TYPE_POWERPC - return Abi(Abi::PowerPCArchitecture, Abi::DarwinOS, Abi::GenericFlavor, Abi::MachOFormat, 32); case 0x01000000 + 18: // CPU_TYPE_POWERPC64 return Abi(Abi::PowerPCArchitecture, Abi::DarwinOS, Abi::GenericFlavor, Abi::MachOFormat, 32); case 12: // CPU_TYPE_ARM @@ -515,9 +514,7 @@ Abi Abi::abiFromTargetTriplet(const QString &triple) if (flavor == UnknownFlavor) flavor = GenericFlavor; format = ElfFormat; - } else if (p == "android") { - flavor = AndroidLinuxFlavor; - } else if (p == "androideabi") { + } else if (p == "android" || p == "androideabi") { flavor = AndroidLinuxFlavor; } else if (p.startsWith("freebsd")) { os = BsdOS; diff --git a/src/plugins/projectexplorer/abi.h b/src/plugins/projectexplorer/abi.h index 21794d5be7..47605b10e6 100644 --- a/src/plugins/projectexplorer/abi.h +++ b/src/plugins/projectexplorer/abi.h @@ -97,6 +97,7 @@ public: WindowsMsvc2015Flavor, WindowsMsvc2017Flavor, WindowsMsvc2019Flavor, + WindowsLastMsvcFlavor = WindowsMsvc2019Flavor, WindowsMSysFlavor, WindowsCEFlavor, diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index e761647398..c5fb985707 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -221,8 +221,12 @@ static GccToolChain::DetectedAbisResult guessGccAbi(const FilePath &path, const QStringList arguments = extraArgs; arguments << "-dumpmachine"; QString machine = QString::fromLocal8Bit(runGcc(path, arguments, env)).trimmed(); - if (machine.isEmpty()) + if (machine.isEmpty()) { + // ICC does not implement the -dumpmachine option on macOS. + if (HostOsInfo::isMacHost() && (path.fileName() == "icc" || path.fileName() == "icpc")) + return GccToolChain::DetectedAbisResult({Abi::hostAbi()}); return GccToolChain::DetectedAbisResult(); // no need to continue if running failed once... + } return GccToolChain::DetectedAbisResult(guessGccAbi(machine, macros), machine); } @@ -660,7 +664,7 @@ ToolChain::BuiltInHeaderPathsRunner GccToolChain::createBuiltInHeaderPathsRunner extraHeaderPathsFunction, flags, sysRoot, - /*target=*/""); // Target must be empty for gcc. + /*originalTargetTriple=*/""); // Must be empty for gcc. }; } @@ -1335,9 +1339,7 @@ void GccToolChainConfigWidget::handleCompilerCommandChange() // Find a good ABI for the new compiler: Abi newAbi; - if (customAbi) - newAbi = currentAbi; - else if (abiList.contains(currentAbi)) + if (customAbi || abiList.contains(currentAbi)) newAbi = currentAbi; m_abiWidget->setAbis(abiList, newAbi); @@ -1833,7 +1835,7 @@ QList<ToolChain *> MingwToolChainFactory::detectForImport(const ToolChainDescrip LinuxIccToolChain::LinuxIccToolChain() : GccToolChain(Constants::LINUXICC_TOOLCHAIN_TYPEID) { - setTypeDisplayName(LinuxIccToolChainFactory::tr("Linux ICC")); + setTypeDisplayName(LinuxIccToolChainFactory::tr("ICC")); } /** @@ -1874,7 +1876,7 @@ QStringList LinuxIccToolChain::suggestedMkspecList() const LinuxIccToolChainFactory::LinuxIccToolChainFactory() { - setDisplayName(tr("Linux ICC")); + setDisplayName(tr("ICC")); setSupportedToolChainType(Constants::LINUXICC_TOOLCHAIN_TYPEID); setSupportedLanguages({Constants::CXX_LANGUAGE_ID, Constants::C_LANGUAGE_ID}); setToolchainConstructor([] { return new LinuxIccToolChain; }); diff --git a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp index 432a22fec1..dbae037260 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp @@ -977,9 +977,7 @@ bool ListField::validate(MacroExpander *expander, QString *message) return false; updateIndex(); - if (selectionModel()->hasSelection()) - return true; - return false; + return selectionModel()->hasSelection(); } void ListField::initializeData(MacroExpander *expander) @@ -1116,11 +1114,8 @@ void ComboBoxField::setup(JsonFieldPage *page, const QString &name) selectionModel()->blockSignals(true); w->blockSignals(false); }); - page->registerObjectAsFieldWithName<QItemSelectionModel>(name, selectionModel(), &QItemSelectionModel::selectionChanged, [this]() { - const QModelIndex i = selectionModel()->currentIndex(); - if (i.isValid()) - return i.data(ValueRole); - return QVariant(); + page->registerObjectAsFieldWithName<QComboBox>(name, w, QOverload<int>::of(&QComboBox::activated), [w]() { + return w->currentData(ValueRole); }); QObject::connect(selectionModel(), &QItemSelectionModel::selectionChanged, page, [page]() { emit page->completeChanged(); @@ -1143,6 +1138,13 @@ void ComboBoxField::initializeData(MacroExpander *expander) w->setCurrentIndex(selectionModel()->currentIndex().row()); } +QVariant ComboBoxField::toSettings() const +{ + if (auto w = qobject_cast<QComboBox*>(widget())) + return w->currentData(ValueRole); + return {}; +} + void IconListField::setup(JsonFieldPage *page, const QString &name) { auto w = qobject_cast<QListView*>(widget()); diff --git a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage_p.h b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage_p.h index 62db37aff6..6e91500b8e 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage_p.h +++ b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage_p.h @@ -236,10 +236,11 @@ private: class ComboBoxField : public ListField { -public: +private: void setup(JsonFieldPage *page, const QString &name) override; QWidget *createWidget(const QString &displayName, JsonFieldPage *page) override; void initializeData(Utils::MacroExpander *expander) override; + QVariant toSettings() const override; }; class IconListField : public ListField diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index fb3e912a65..4d7aee5fc8 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -2790,9 +2790,7 @@ bool ProjectExplorerPlugin::coreAboutToClose() if (box.clickedButton() != closeAnyway) return false; } - if (!dd->m_outputPane.aboutToClose()) - return false; - return true; + return dd->m_outputPane.aboutToClose(); } void ProjectExplorerPlugin::handleCommandLineArguments(const QStringList &arguments) diff --git a/src/plugins/projectexplorer/projecttreewidget.cpp b/src/plugins/projectexplorer/projecttreewidget.cpp index 8f4d5adef7..b3ae5756e7 100644 --- a/src/plugins/projectexplorer/projecttreewidget.cpp +++ b/src/plugins/projectexplorer/projecttreewidget.cpp @@ -382,10 +382,7 @@ Node *ProjectTreeWidget::nodeForFile(const FilePath &fileName) if (ProjectNode *projectNode = project->rootProjectNode()) { projectNode->forEachGenericNode([&](Node *node) { if (node->filePath() == fileName) { - if (!bestNode) { - bestNode = node; - bestNodeExpandCount = ProjectTreeWidget::expandedCount(node); - } else if (priority(node) < priority(bestNode)) { + if (!bestNode || priority(node) < priority(bestNode)) { bestNode = node; bestNodeExpandCount = ProjectTreeWidget::expandedCount(node); } else if (priority(node) == priority(bestNode)) { diff --git a/src/plugins/projectexplorer/projectwelcomepage.cpp b/src/plugins/projectexplorer/projectwelcomepage.cpp index 0f2bfb4dc3..8d74b3f648 100644 --- a/src/plugins/projectexplorer/projectwelcomepage.cpp +++ b/src/plugins/projectexplorer/projectwelcomepage.cpp @@ -82,7 +82,6 @@ QVariant ProjectModel::data(const QModelIndex &index, int role) const case Qt::DisplayRole: return data.second; case Qt::ToolTipRole: - return data.first; case FilePathRole: return data.first; case PrettyFilePathRole: diff --git a/src/plugins/projectexplorer/projectwindow.cpp b/src/plugins/projectexplorer/projectwindow.cpp index 96cfc251d3..dfa20793e3 100644 --- a/src/plugins/projectexplorer/projectwindow.cpp +++ b/src/plugins/projectexplorer/projectwindow.cpp @@ -213,8 +213,6 @@ public: { switch (role) { case Qt::DisplayRole: - return m_project->displayName(); - case ProjectDisplayNameRole: return m_project->displayName(); diff --git a/src/plugins/projectexplorer/targetsettingspanel.cpp b/src/plugins/projectexplorer/targetsettingspanel.cpp index e1345cb50e..79cfe02fdb 100644 --- a/src/plugins/projectexplorer/targetsettingspanel.cpp +++ b/src/plugins/projectexplorer/targetsettingspanel.cpp @@ -669,8 +669,7 @@ TargetGroupItem::TargetGroupItem(const QString &displayName, Project *project) { d->m_displayName = displayName; QObject::connect(project, &Project::addedTarget, - d.get(), &TargetGroupItemPrivate::handleTargetAdded, - Qt::QueuedConnection); + d.get(), &TargetGroupItemPrivate::handleTargetAdded); QObject::connect(project, &Project::removedTarget, d.get(), &TargetGroupItemPrivate::handleTargetRemoved); QObject::connect(project, &Project::activeTargetChanged, diff --git a/src/plugins/projectexplorer/targetsetuppage.cpp b/src/plugins/projectexplorer/targetsetuppage.cpp index d80b2689c1..a200b9233d 100644 --- a/src/plugins/projectexplorer/targetsetuppage.cpp +++ b/src/plugins/projectexplorer/targetsetuppage.cpp @@ -101,7 +101,7 @@ public: noValidKitLabel = new QLabel(setupTargetPage); noValidKitLabel->setWordWrap(true); noValidKitLabel->setText(TargetSetupPage::tr("<span style=\" font-weight:600;\">No suitable kits found.</span><br/>" - "Please add a kit in the <a href=\"buildandrun\">options</a> " + "Add a kit in the <a href=\"buildandrun\">options</a> " "or via the maintenance tool of the SDK.")); noValidKitLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); noValidKitLabel->setVisible(false); diff --git a/src/plugins/projectexplorer/targetsetupwidget.cpp b/src/plugins/projectexplorer/targetsetupwidget.cpp index cc5257fabc..ddcda6d8ff 100644 --- a/src/plugins/projectexplorer/targetsetupwidget.cpp +++ b/src/plugins/projectexplorer/targetsetupwidget.cpp @@ -122,7 +122,7 @@ bool TargetSetupWidget::isKitSelected() const void TargetSetupWidget::setKitSelected(bool b) { // Only check target if there are build configurations possible - b &= !selectedBuildInfoList().isEmpty(); + b &= hasSelectedBuildConfigurations(); m_ignoreChange = true; m_detailsWidget->setChecked(b); m_detailsWidget->widget()->setEnabled(b); @@ -187,9 +187,12 @@ void TargetSetupWidget::targetCheckBoxToggled(bool b) if (m_ignoreChange) return; m_detailsWidget->widget()->setEnabled(b); - m_detailsWidget->setState(b && Utils::contains(m_infoStore, &BuildInfoStore::hasIssues) - ? Utils::DetailsWidget::Expanded - : Utils::DetailsWidget::Collapsed); + if (b && (contains(m_infoStore, &BuildInfoStore::hasIssues) + || !contains(m_infoStore, &BuildInfoStore::isEnabled))) { + m_detailsWidget->setState(DetailsWidget::Expanded); + } else if (!b) { + m_detailsWidget->setState(Utils::DetailsWidget::Collapsed); + } emit selectedToggled(); } @@ -230,12 +233,13 @@ void TargetSetupWidget::update(const Kit::Predicate &predicate) // Kits that don't fulfill the project predicate are not selectable, because we cannot // guarantee that we can handle the project sensibly (e.g. qmake project without Qt). if (predicate && !predicate(kit())) { - setEnabled(false); + toggleEnabled(false); + m_infoStore.clear(); m_detailsWidget->setToolTip(tr("You cannot use this kit, because it does not fulfill " "the project's prerequisites.")); return; } - setEnabled(true); + toggleEnabled(true); m_detailsWidget->setIcon(kit()->isValid() ? kit()->icon() : Icons::CRITICAL.icon()); m_detailsWidget->setToolTip(m_kit->toHtml()); updateDefaultBuildDirectories(); @@ -251,6 +255,22 @@ const QList<BuildInfo> TargetSetupWidget::buildInfoList(const Kit *k, const File return {info}; } +bool TargetSetupWidget::hasSelectedBuildConfigurations() const +{ + return !selectedBuildInfoList().isEmpty(); +} + +void TargetSetupWidget::toggleEnabled(bool enabled) +{ + m_detailsWidget->widget()->setEnabled(enabled && hasSelectedBuildConfigurations()); + m_detailsWidget->setCheckable(enabled); + m_detailsWidget->setExpandable(enabled); + if (!enabled) { + m_detailsWidget->setState(DetailsWidget::Collapsed); + m_detailsWidget->setChecked(false); + } +} + const QList<BuildInfo> TargetSetupWidget::selectedBuildInfoList() const { QList<BuildInfo> result; @@ -276,6 +296,7 @@ void TargetSetupWidget::updateDefaultBuildDirectories() for (const BuildInfo &buildInfo : buildInfoList(m_kit, m_projectPath)) { if (!buildInfo.factory()) continue; + bool found = false; for (BuildInfoStore &buildInfoStore : m_infoStore) { if (buildInfoStore.buildInfo.typeName == buildInfo.typeName) { if (!buildInfoStore.customBuildDir) { @@ -283,9 +304,12 @@ void TargetSetupWidget::updateDefaultBuildDirectories() buildInfoStore.pathChooser->setFileName(buildInfo.buildDirectory); m_ignoreChange = false; } + found = true; break; } } + if (!found) // the change of the kit may have produced more build information than before + addBuildInfo(buildInfo, false); } } diff --git a/src/plugins/projectexplorer/targetsetupwidget.h b/src/plugins/projectexplorer/targetsetupwidget.h index 80f64ad918..6534baf700 100644 --- a/src/plugins/projectexplorer/targetsetupwidget.h +++ b/src/plugins/projectexplorer/targetsetupwidget.h @@ -78,6 +78,9 @@ signals: private: static const QList<BuildInfo> buildInfoList(const Kit *k, const Utils::FilePath &projectPath); + bool hasSelectedBuildConfigurations() const; + + void toggleEnabled(bool enabled); void checkBoxToggled(bool b); void pathChanged(); void targetCheckBoxToggled(bool b); diff --git a/src/plugins/projectexplorer/userfileaccessor.cpp b/src/plugins/projectexplorer/userfileaccessor.cpp index 676bcf7990..5f3c3692b7 100644 --- a/src/plugins/projectexplorer/userfileaccessor.cpp +++ b/src/plugins/projectexplorer/userfileaccessor.cpp @@ -799,7 +799,7 @@ QVariant UserFileVersion19Upgrader::process(const QVariant &entry, const QString "ProjectExplorer.CustomExecutableRunConfiguration.WorkingDirectory", "Qbs.RunConfiguration.WorkingDirectory", "Qt4ProjectManager.Qt4RunConfiguration.UserWorkingDirectory", - "RemoteLinux.CustomRunConfig.WorkingDirectory" + "RemoteLinux.CustomRunConfig.WorkingDirectory", "RemoteLinux.RunConfig.WorkingDirectory", "WorkingDir"}; static const QStringList termKeys = {"CMakeProjectManager.CMakeRunConfiguration.UseTerminal", diff --git a/src/plugins/python/pythonrunconfiguration.cpp b/src/plugins/python/pythonrunconfiguration.cpp index 4477f11cb1..41386ef611 100644 --- a/src/plugins/python/pythonrunconfiguration.cpp +++ b/src/plugins/python/pythonrunconfiguration.cpp @@ -257,8 +257,10 @@ PythonRunConfiguration::PythonRunConfiguration(Target *target, Core::Id id) connect(PythonSettings::instance(), &PythonSettings::interpretersChanged, interpreterAspect, &InterpreterAspect::updateInterpreters); - interpreterAspect->updateInterpreters(PythonSettings::interpreters()); - interpreterAspect->setDefaultInterpreter(PythonSettings::defaultInterpreter()); + QList<Interpreter> interpreters = PythonSettings::detectPythonVenvs(project()->projectDirectory()); + aspect<InterpreterAspect>()->updateInterpreters(PythonSettings::interpreters()); + aspect<InterpreterAspect>()->setDefaultInterpreter( + interpreters.isEmpty() ? PythonSettings::defaultInterpreter() : interpreters.first()); auto scriptAspect = addAspect<MainScriptAspect>(); scriptAspect->setSettingsKey("PythonEditor.RunConfiguation.Script"); diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index d9ab47093c..acb7a50ddd 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -211,6 +211,7 @@ public: InterpreterOptionsPage(); void setInterpreter(const QList<Interpreter> &interpreters) { m_interpreters = interpreters; } + void addInterpreter(const Interpreter &interpreter) { m_interpreters << interpreter; } QList<Interpreter> interpreters() const { return m_interpreters; } void setDefaultInterpreter(const QString &defaultId) { m_defaultInterpreterId = defaultId; } @@ -278,6 +279,7 @@ Interpreter::Interpreter(const FilePath &python, const QString &defaultName, boo { SynchronousProcess pythonProcess; pythonProcess.setProcessChannelMode(QProcess::MergedChannels); + pythonProcess.setTimeoutS(1); SynchronousProcessResponse response = pythonProcess.runBlocking( CommandLine(python, {"--version"})); if (response.result == SynchronousProcessResponse::Finished) @@ -465,11 +467,21 @@ void PythonSettings::init() void PythonSettings::setInterpreter(const QList<Interpreter> &interpreters, const QString &defaultId) { + if (defaultId == interpreterOptionsPage().defaultInterpreter().id + && interpreters == interpreterOptionsPage().interpreters()) { + return; + } interpreterOptionsPage().setInterpreter(interpreters); interpreterOptionsPage().setDefaultInterpreter(defaultId); - toSettings(Core::ICore::settings(), {interpreters, defaultId}); - if (QTC_GUARD(settingsInstance)) - emit settingsInstance->interpretersChanged(interpreters, defaultId); + saveSettings(); +} + +void PythonSettings::addInterpreter(const Interpreter &interpreter, bool isDefault) +{ + interpreterOptionsPage().addInterpreter(interpreter); + if (isDefault) + interpreterOptionsPage().setDefaultInterpreter(interpreter.id); + saveSettings(); } PythonSettings *PythonSettings::instance() @@ -478,6 +490,52 @@ PythonSettings *PythonSettings::instance() return settingsInstance; } +QList<Interpreter> PythonSettings::detectPythonVenvs(const FilePath &path) +{ + QList<Interpreter> result; + QDir dir = path.toFileInfo().isDir() ? QDir(path.toString()) : path.toFileInfo().dir(); + if (dir.exists()) { + const QString venvPython = HostOsInfo::withExecutableSuffix("python"); + const QString activatePath = HostOsInfo::isWindowsHost() ? QString{"Scripts"} + : QString{"bin"}; + do { + for (const QString &directory : dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { + if (dir.cd(directory)) { + if (dir.cd(activatePath)) { + if (dir.exists("activate") && dir.exists(venvPython)) { + FilePath python = FilePath::fromString(dir.absoluteFilePath(venvPython)); + dir.cdUp(); + const QString defaultName = QString("Python (%1 Virtual Environment)") + .arg(dir.dirName()); + Interpreter interpreter + = Utils::findOrDefault(PythonSettings::interpreters(), + Utils::equal(&Interpreter::command, python)); + if (interpreter.command.isEmpty()) { + interpreter = Interpreter(python, defaultName); + PythonSettings::addInterpreter(interpreter); + } + result << interpreter; + } else { + dir.cdUp(); + } + } + dir.cdUp(); + } + } + } while (dir.cdUp()); + } + return result; +} + +void PythonSettings::saveSettings() +{ + const QList<Interpreter> &interpreters = interpreterOptionsPage().interpreters(); + const QString &defaultId = interpreterOptionsPage().defaultInterpreter().id; + toSettings(Core::ICore::settings(), {interpreters, defaultId}); + if (QTC_GUARD(settingsInstance)) + emit settingsInstance->interpretersChanged(interpreters, defaultId); +} + QList<Interpreter> PythonSettings::interpreters() { return interpreterOptionsPage().interpreters(); diff --git a/src/plugins/python/pythonsettings.h b/src/plugins/python/pythonsettings.h index 7ca5218ae3..0ef6c62a0f 100644 --- a/src/plugins/python/pythonsettings.h +++ b/src/plugins/python/pythonsettings.h @@ -26,6 +26,7 @@ #pragma once #include <utils/fileutils.h> +#include <utils/optional.h> #include <QUuid> @@ -43,6 +44,11 @@ public: const QString &name, const Utils::FilePath &command); + inline bool operator==(const Interpreter &other) const + { + return id == other.id && name == other.name && command == other.command; + } + QString id = QUuid::createUuid().toString(); QString name; Utils::FilePath command; @@ -57,13 +63,18 @@ public: static QList<Interpreter> interpreters(); static Interpreter defaultInterpreter(); static void setInterpreter(const QList<Interpreter> &interpreters, const QString &defaultId); + static void addInterpreter(const Interpreter &interpreter, bool isDefault = false); static PythonSettings *instance(); + static QList<Interpreter> detectPythonVenvs(const Utils::FilePath &path); + signals: void interpretersChanged(const QList<Interpreter> &interpreters, const QString &defaultId); private: PythonSettings(); + + static void saveSettings(); }; } // namespace Internal diff --git a/src/plugins/python/pythonutils.cpp b/src/plugins/python/pythonutils.cpp index 03096ee96e..aa7051b396 100644 --- a/src/plugins/python/pythonutils.cpp +++ b/src/plugins/python/pythonutils.cpp @@ -175,6 +175,11 @@ static FilePath detectPython(const FilePath &documentPath) } } + // check whether this file is inside a python virtual environment + QList<Interpreter> venvInterpreters = PythonSettings::detectPythonVenvs(documentPath); + if (!python.exists()) + python = venvInterpreters.value(0).command; + if (!python.exists()) python = PythonSettings::defaultInterpreter().command; @@ -248,9 +253,15 @@ public: ? QString{"python-language-server[pyflakes]"} : QString{"python-language-server[all]"}; - m_process.start(m_python.toString(), {"-m", "pip", "install", "--user", pylsVersion}); + QStringList arguments = {"-m", "pip", "install", pylsVersion}; + + // add --user to global pythons, but skip it for venv pythons + if (!QDir(m_python.parentDir().toString()).exists("activate")) + arguments << "--user"; + + m_process.start(m_python.toString(), arguments); - Core::MessageManager::write(tr("Running '%1 %2' to install python language server") + Core::MessageManager::write(tr("Running \"%1 %2\" to install Python language server") .arg(m_process.program(), m_process.arguments().join(' '))); m_killTimer.setSingleShot(true); @@ -261,7 +272,7 @@ private: void cancel() { SynchronousProcess::stopProcess(m_process); - Core::MessageManager::write(tr("The Python language server installation canceled by %1.") + Core::MessageManager::write(tr("The Python language server installation was canceled by %1.") .arg(m_killTimer.isActive() ? tr("user") : tr("time out"))); } @@ -371,7 +382,7 @@ void PyLSConfigureAssistant::openDocumentWithPython(const FilePath &python, && infoBar->canInfoBeAdded(installPylsInfoBarId)) { auto message = tr("Install and set up Python language server (PyLS) for %1 (%2). " - "The language server provides Python specific completions and annotations.") + "The language server provides Python specific completion and annotation.") .arg(pythonName(python), python.toUserOutput()); Core::InfoBarEntry info(installPylsInfoBarId, message, @@ -383,7 +394,7 @@ void PyLSConfigureAssistant::openDocumentWithPython(const FilePath &python, } else if (lsState.state == PythonLanguageServerState::AlreadyInstalled && infoBar->canInfoBeAdded(startPylsInfoBarId)) { auto message = tr("Found a Python language server for %1 (%2). " - "Should this one be set up for this document?") + "Set it up for this document?") .arg(pythonName(python), python.toUserOutput()); Core::InfoBarEntry info(startPylsInfoBarId, message, diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index c645a96774..df5d381511 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -298,6 +298,7 @@ extend_qtc_plugin(QmlDesigner extend_qtc_plugin(QmlDesigner SOURCES_PREFIX components/propertyeditor SOURCES + aligndistribute.cpp aligndistribute.h designerpropertymap.cpp designerpropertymap.h fileresourcesmodel.cpp fileresourcesmodel.h itemfiltermodel.cpp itemfiltermodel.h diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp b/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp index d06ea3c495..72bdf4be13 100644 --- a/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditor.cpp @@ -113,9 +113,20 @@ QToolBar *CurveEditor::createToolBar() durationWidget->setLayout(durationBox); bar->addWidget(durationWidget); + auto *cfspin = new QSpinBox; + cfspin->setMinimum(0); + cfspin->setMaximum(std::numeric_limits<int>::max()); + + auto intSignal = static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged); + connect(cfspin, intSignal, [this](int val) { m_view->setCurrentFrame(val, false); }); + connect(m_view, &GraphicsView::notifyFrameChanged, [cfspin](int val) { + QSignalBlocker blocker(cfspin); + cfspin->setValue(val); + }); + auto *positionBox = new QHBoxLayout; positionBox->addWidget(new QLabel(tr("Current Frame"))); - positionBox->addWidget(new QSpinBox); + positionBox->addWidget(cfspin); auto *positionWidget = new QWidget; positionWidget->setLayout(positionBox); bar->addWidget(positionWidget); diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp index 7a711923cc..f225128a01 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp @@ -184,11 +184,14 @@ void GraphicsView::setZoomY(double zoom, const QPoint &pivot) viewport()->update(); } -void GraphicsView::setCurrentFrame(int frame) +void GraphicsView::setCurrentFrame(int frame, bool notify) { int clampedFrame = clamp(frame, m_model->minimumTime(), m_model->maximumTime()); m_playhead.moveToFrame(clampedFrame, this); viewport()->update(); + + if (notify) + notifyFrameChanged(frame); } void GraphicsView::scrollContent(double x, double y) @@ -251,6 +254,7 @@ void GraphicsView::mousePressEvent(QMouseEvent *event) QPointF pos = mapToScene(event->pos()); if (timeScaleRect().contains(pos)) { setCurrentFrame(std::round(mapXtoTime(pos.x()))); + m_playhead.setMoving(true); event->accept(); return; } diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.h b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.h index af138429bf..d7c2f14da0 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.h +++ b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.h @@ -45,6 +45,9 @@ class GraphicsView : public QGraphicsView friend class Playhead; +signals: + void notifyFrameChanged(int frame); + public: GraphicsView(CurveEditorModel *model, QWidget *parent = nullptr); @@ -94,7 +97,7 @@ public: void setZoomY(double zoom, const QPoint &pivot = QPoint()); - void setCurrentFrame(int frame); + void setCurrentFrame(int frame, bool notify = true); void scrollContent(double x, double y); diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/playhead.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/playhead.cpp index e2e6d21274..7b25bbb9af 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/playhead.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/detail/playhead.cpp @@ -56,6 +56,11 @@ int Playhead::currentFrame() const return m_frame; } +void Playhead::setMoving(bool moving) +{ + m_moving = moving; +} + void Playhead::moveToFrame(int frame, GraphicsView *view) { m_frame = frame; diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/playhead.h b/src/plugins/qmldesigner/components/curveeditor/detail/playhead.h index 3a785624bd..9f6295c34a 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/playhead.h +++ b/src/plugins/qmldesigner/components/curveeditor/detail/playhead.h @@ -45,6 +45,8 @@ public: void paint(QPainter *painter, GraphicsView *view) const; + void setMoving(bool moving); + void moveToFrame(int frame, GraphicsView *view); void resize(GraphicsView *view); diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/item-3D_model-icon.png b/src/plugins/qmldesigner/components/itemlibrary/images/item-3D_model-icon.png Binary files differindex 1a69afa777..bbdafae887 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/images/item-3D_model-icon.png +++ b/src/plugins/qmldesigner/components/itemlibrary/images/item-3D_model-icon.png diff --git a/src/plugins/qmldesigner/components/itemlibrary/images/item-3D_model-icon@2x.png b/src/plugins/qmldesigner/components/itemlibrary/images/item-3D_model-icon@2x.png Binary files differindex d3aa02218b..7ab1e27ac3 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/images/item-3D_model-icon@2x.png +++ b/src/plugins/qmldesigner/components/itemlibrary/images/item-3D_model-icon@2x.png diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index e82fbe9770..98735e5120 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -257,14 +257,15 @@ void static appendForcedNodes(const NodeListProperty &property, QList<ModelNode> QList<ModelNode> filteredList(const NodeListProperty &property, bool filter) { - if (!filter) - return property.toModelNodeList(); - QList<ModelNode> list; - list.append(Utils::filtered(property.toModelNodeList(), [] (const ModelNode &arg) { - return QmlItemNode::isValidQmlItemNode(arg) || NodeHints::fromModelNode(arg).visibleInNavigator(); - })); + if (filter) { + list.append(Utils::filtered(property.toModelNodeList(), [] (const ModelNode &arg) { + return QmlItemNode::isValidQmlItemNode(arg) || NodeHints::fromModelNode(arg).visibleInNavigator(); + })); + } else { + list = property.toModelNodeList(); + } appendForcedNodes(property, list); diff --git a/src/plugins/qmldesigner/components/propertyeditor/aligndistribute.cpp b/src/plugins/qmldesigner/components/propertyeditor/aligndistribute.cpp new file mode 100644 index 0000000000..d6ef557388 --- /dev/null +++ b/src/plugins/qmldesigner/components/propertyeditor/aligndistribute.cpp @@ -0,0 +1,696 @@ +/**************************************************************************** +** +** 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 "aligndistribute.h" + +#include <nodeabstractproperty.h> +#include <qmldesignerplugin.h> +#include <qmlmodelnodeproxy.h> + +#include <modelnode.h> +#include <variantproperty.h> + +#include <coreplugin/icore.h> + +#include <utils/algorithm.h> +#include <utils/checkablemessagebox.h> +#include <utils/qtcassert.h> + +#include <cmath> + +namespace QmlDesigner { + +AlignDistribute::AlignDistribute(QObject *parent) + : QObject(parent) +{} + +bool AlignDistribute::multiSelection() const +{ + if (!m_qmlObjectNode.isValid()) + return false; + + return m_qmlObjectNode.view()->selectedModelNodes().count() > 1; +} + +bool AlignDistribute::selectionHasAnchors() const +{ + if (!m_qmlObjectNode.isValid()) + return true; + + const auto selectionContext = SelectionContext(m_qmlObjectNode.view()); + for (const ModelNode &modelNode : selectionContext.selectedModelNodes()) { + QmlItemNode itemNode(modelNode); + if (itemNode.instanceHasAnchors()) + return true; + } + return false; +} + +bool AlignDistribute::selectionExclusivlyItems() const +{ + if (!m_qmlObjectNode.isValid()) + return false; + + const auto selectionContext = SelectionContext(m_qmlObjectNode.view()); + for (const ModelNode &modelNode : selectionContext.selectedModelNodes()) { + if (!QmlItemNode::isValidQmlItemNode(modelNode)) + return false; + } + return true; +} + +bool AlignDistribute::selectionContainsRootItem() const +{ + if (!m_qmlObjectNode.isValid()) + return true; + + const auto selectionContext = SelectionContext(m_qmlObjectNode.view()); + for (const ModelNode &modelNode : selectionContext.selectedModelNodes()) { + QmlItemNode itemNode(modelNode); + if (itemNode.isRootNode()) + return true; + } + return false; +} + +void AlignDistribute::setModelNodeBackend(const QVariant &modelNodeBackend) +{ + auto modelNodeBackendObject = modelNodeBackend.value<QObject *>(); + const auto backendObjectCasted = qobject_cast<const QmlModelNodeProxy *>(modelNodeBackendObject); + + if (backendObjectCasted) + m_qmlObjectNode = backendObjectCasted->qmlObjectNode(); + + emit modelNodeBackendChanged(); +} + +// The purpose of this function is to suppress the following warning: +// Warning: Property declaration modelNodeBackendProperty has no READ accessor +// function or associated MEMBER variable. The property will be invalid. +QVariant AlignDistribute::getModelNodeBackend() const +{ + return {}; +} + +void AlignDistribute::registerDeclarativeType() +{ + qmlRegisterType<AlignDistribute>("HelperWidgets", 2, 0, "AlignDistribute"); +} + +// utility functions + +inline qreal width(const QmlItemNode &qmlItemNode) +{ + return qmlItemNode.instanceSize().width(); +} +inline qreal halfWidth(const QmlItemNode &qmlItemNode) +{ + return qmlItemNode.instanceSize().width() * 0.5; +} +inline qreal height(const QmlItemNode &qmlItemNode) +{ + return qmlItemNode.instanceSize().height(); +} +inline qreal halfHeight(const QmlItemNode &qmlItemNode) +{ + return qmlItemNode.instanceSize().height() * 0.5; +} +inline qreal left(const QmlItemNode &qmlItemNode) +{ + return qmlItemNode.instanceScenePosition().x(); +} +inline qreal centerHorizontal(const QmlItemNode &qmlItemNode) +{ + return qmlItemNode.instanceScenePosition().x() + halfWidth(qmlItemNode); +} +inline qreal right(const QmlItemNode &qmlItemNode) +{ + return qmlItemNode.instanceScenePosition().x() + width(qmlItemNode); +} +inline qreal top(const QmlItemNode &qmlItemNode) +{ + return qmlItemNode.instanceScenePosition().y(); +} +inline qreal centerVertical(const QmlItemNode &qmlItemNode) +{ + return qmlItemNode.instanceScenePosition().y() + halfHeight(qmlItemNode); +} +inline qreal bottom(const QmlItemNode &qmlItemNode) +{ + return qmlItemNode.instanceScenePosition().y() + height(qmlItemNode); +} + +bool compareByLeft(const ModelNode &node1, const ModelNode &node2) +{ + const QmlItemNode itemNode1 = QmlItemNode(node1); + const QmlItemNode itemNode2 = QmlItemNode(node2); + if (itemNode1.isValid() && itemNode2.isValid()) + return left(itemNode1) < left(itemNode2); + return false; +} + +bool compareByCenterH(const ModelNode &node1, const ModelNode &node2) +{ + const QmlItemNode itemNode1 = QmlItemNode(node1); + const QmlItemNode itemNode2 = QmlItemNode(node2); + if (itemNode1.isValid() && itemNode2.isValid()) + return centerHorizontal(itemNode1) < centerHorizontal(itemNode2); + return false; +} + +bool compareByRight(const ModelNode &node1, const ModelNode &node2) +{ + const QmlItemNode itemNode1 = QmlItemNode(node1); + const QmlItemNode itemNode2 = QmlItemNode(node2); + if (itemNode1.isValid() && itemNode2.isValid()) + return right(itemNode1) < right(itemNode2); + return false; +} + +bool compareByTop(const ModelNode &node1, const ModelNode &node2) +{ + const QmlItemNode itemNode1 = QmlItemNode(node1); + const QmlItemNode itemNode2 = QmlItemNode(node2); + if (itemNode1.isValid() && itemNode2.isValid()) + return top(itemNode1) < top(itemNode2); + return false; +} + +bool compareByCenterV(const ModelNode &node1, const ModelNode &node2) +{ + const QmlItemNode itemNode1 = QmlItemNode(node1); + const QmlItemNode itemNode2 = QmlItemNode(node2); + if (itemNode1.isValid() && itemNode2.isValid()) + return centerVertical(itemNode1) < centerVertical(itemNode2); + return false; +} + +bool compareByBottom(const ModelNode &node1, const ModelNode &node2) +{ + const QmlItemNode itemNode1 = QmlItemNode(node1); + const QmlItemNode itemNode2 = QmlItemNode(node2); + if (itemNode1.isValid() && itemNode2.isValid()) + return bottom(itemNode1) < bottom(itemNode2); + return false; +} + +unsigned getDepth(const ModelNode &node) +{ + if (node.isRootNode()) + return 0; + + return 1 + getDepth(node.parentProperty().parentModelNode()); +} + +bool compareByDepth(const ModelNode &node1, const ModelNode &node2) +{ + if (node1.isValid() && node2.isValid()) + return getDepth(node1) < getDepth(node2); + return false; +} + +static inline QRectF getBoundingRect(const QList<ModelNode> &modelNodeList) +{ + QRectF boundingRect; + for (const ModelNode &modelNode : modelNodeList) { + if (QmlItemNode::isValidQmlItemNode(modelNode)) { + const QmlItemNode qmlItemNode(modelNode); + boundingRect = boundingRect.united(qmlItemNode.instanceSceneBoundingRect()); + } + } + return boundingRect; +} + +static inline QSizeF getSummedSize(const QList<ModelNode> &modelNodeList) +{ + QSizeF summedSize = QSizeF(0, 0); + for (const ModelNode &modelNode : modelNodeList) { + if (QmlItemNode::isValidQmlItemNode(modelNode)) { + const QmlItemNode qmlItemNode(modelNode); + summedSize += qmlItemNode.instanceSize(); + } + } + return summedSize; +} + +static inline qreal getInstanceSceneX(const QmlItemNode &qmlItemNode) +{ + const qreal x = qmlItemNode.modelValue("x").toReal(); + if (qmlItemNode.hasInstanceParentItem()) + return x + getInstanceSceneX(qmlItemNode.instanceParentItem()); + return x; +} + +static inline qreal getInstanceSceneY(const QmlItemNode &qmlItemNode) +{ + const qreal y = qmlItemNode.modelValue("y").toReal(); + if (qmlItemNode.hasInstanceParentItem()) + return y + getInstanceSceneY(qmlItemNode.instanceParentItem()); + return y; +} + +// utility functions + +void AlignDistribute::alignObjects(Target target, AlignTo alignTo, const QString &keyObject) +{ + QTC_ASSERT(m_qmlObjectNode.isValid(), return ); + + const auto selectionContext = SelectionContext(m_qmlObjectNode.view()); + if (selectionContext.selectedModelNodes().empty()) + return; + + AbstractView *view = selectionContext.view(); + QList<ModelNode> selectedNodes = selectionContext.selectedModelNodes(); + QRectF boundingRect; + QmlItemNode keyObjectQmlItemNode; + + switch (alignTo) { + case AlignTo::Selection: { + boundingRect = getBoundingRect(selectedNodes); + break; + } + case AlignTo::Root: { + const QmlItemNode rootQmlItemNode(selectionContext.view()->rootModelNode()); + boundingRect = rootQmlItemNode.instanceSceneBoundingRect(); + break; + } + case AlignTo::KeyObject: { + if (!view->hasId(keyObject)) + return; + + const auto keyObjectModelNode = view->modelNodeForId(keyObject); + keyObjectQmlItemNode = keyObjectModelNode; + boundingRect = keyObjectQmlItemNode.instanceSceneBoundingRect(); + break; + } + } + + Utils::sort(selectedNodes, compareByDepth); + + const QByteArray operationName = "align" + QVariant::fromValue(target).toByteArray(); + auto alignPosition = + [](Target target, const QRectF &boundingRect, const QmlItemNode &qmlItemNode) { + switch (target) { + case Target::Left: + return boundingRect.left(); + case Target::CenterH: + return boundingRect.center().x() - halfWidth(qmlItemNode); + case Target::Right: + return boundingRect.right() - width(qmlItemNode); + case Target::Top: + return boundingRect.top(); + case Target::CenterV: + return boundingRect.center().y() - halfHeight(qmlItemNode); + case Target::Bottom: + return boundingRect.bottom() - height(qmlItemNode); + } + return 0.0; + }; + + view->executeInTransaction("DesignerActionManager|" + operationName, [&]() { + for (const ModelNode &modelNode : selectedNodes) { + QTC_ASSERT(!modelNode.isRootNode(), continue); + if (QmlItemNode::isValidQmlItemNode(modelNode)) { + QmlItemNode qmlItemNode(modelNode); + qreal myPos; + qreal parentPos; + QByteArray propertyName; + switch (getDimension(target)) { + case Dimension::X: { + myPos = qmlItemNode.instanceScenePosition().x(); + parentPos = getInstanceSceneX(qmlItemNode.instanceParentItem()); + propertyName = "x"; + break; + } + case Dimension::Y: { + myPos = qmlItemNode.instanceScenePosition().y(); + parentPos = getInstanceSceneY(qmlItemNode.instanceParentItem()); + propertyName = "y"; + break; + } + } + if (alignTo == AlignTo::KeyObject && qmlItemNode == keyObjectQmlItemNode) + qmlItemNode.setVariantProperty(propertyName, myPos - parentPos); + else + qmlItemNode.setVariantProperty(propertyName, + qRound(alignPosition(target, + boundingRect, + qmlItemNode)) + - parentPos); + } + } + }); +} + +void AlignDistribute::distributeObjects(Target target, AlignTo alignTo, const QString &keyObject) +{ + QTC_ASSERT(m_qmlObjectNode.isValid(), return ); + + const auto selectionContext = SelectionContext(m_qmlObjectNode.view()); + if (selectionContext.selectedModelNodes().empty()) + return; + + AbstractView *view = selectionContext.view(); + QList<ModelNode> selectedNodes = selectionContext.selectedModelNodes(); + QRectF boundingRect; + + switch (alignTo) { + case AlignDistribute::AlignTo::Selection: { + boundingRect = getBoundingRect(selectedNodes); + break; + } + case AlignDistribute::AlignTo::Root: { + const QmlItemNode rootQmlItemNode(selectionContext.view()->rootModelNode()); + boundingRect = rootQmlItemNode.instanceSceneBoundingRect(); + break; + } + case AlignDistribute::AlignTo::KeyObject: { + if (!view->hasId(keyObject)) + return; + + // Remove key object from selected nodes list and set bounding box according to key object. + const auto keyObjectModelNode = view->modelNodeForId(keyObject); + selectedNodes.removeOne(keyObjectModelNode); + const QmlItemNode keyObjectQmlItemNode(keyObjectModelNode); + boundingRect = keyObjectQmlItemNode.instanceSceneBoundingRect(); + break; + } + } + + Utils::sort(selectedNodes, getCompareFunction(target)); + + auto getMargins = [](Target target, const QList<ModelNode> &nodes) { + switch (target) { + case Target::Left: + return QMarginsF(0, 0, width(QmlItemNode(nodes.last())), 0); + case Target::CenterH: + return QMarginsF(halfWidth(QmlItemNode(nodes.first())), + 0, + halfWidth(QmlItemNode(nodes.last())), + 0); + case Target::Right: + return QMarginsF(width(QmlItemNode(nodes.first())), 0, 0, 0); + case Target::Top: + return QMarginsF(0, 0, 0, height(QmlItemNode(nodes.last()))); + case Target::CenterV: + return QMarginsF(0, + halfHeight(QmlItemNode(nodes.first())), + 0, + halfHeight(QmlItemNode(nodes.last()))); + case Target::Bottom: + return QMarginsF(0, height(QmlItemNode(nodes.first())), 0, 0); + } + return QMarginsF(); + }; + + boundingRect -= getMargins(target, selectedNodes); + + auto distributePosition = [](Target target, const QmlItemNode &node) { + switch (target) { + case Target::Left: + return 0.0; + case Target::CenterH: + return halfWidth(node); + case Target::Right: + return width(node); + case Target::Top: + return 0.0; + case Target::CenterV: + return halfHeight(node); + case Target::Bottom: + return height(node); + } + return 0.0; + }; + + QPointF position = boundingRect.topLeft(); + const qreal equidistant = (getDimension(target) == Dimension::X) + ? boundingRect.width() / (selectedNodes.size() - 1) + : boundingRect.height() / (selectedNodes.size() - 1); + qreal tmp; + if (std::modf(equidistant, &tmp) != 0.0) { + if (!executePixelPerfectDialog()) + return; + } + + for (const ModelNode &modelNode : selectedNodes) { + if (QmlItemNode::isValidQmlItemNode(modelNode)) { + QmlItemNode qmlItemNode(modelNode); + qreal currentPosition; + if (getDimension(target) == Dimension::X) { + currentPosition = position.x(); + position.rx() += equidistant; + } else { + currentPosition = position.y(); + position.ry() += equidistant; + } + modelNode.setAuxiliaryData("tmp", + qRound(currentPosition + - distributePosition(target, qmlItemNode))); + } + } + + // Append key object to selected nodes list again. This needs to be done, so relative distribution + // will also work on nested item targets. Otherwise change of parents position will move the inner + // objects too. To compensate for that, the absolute parent position needs to be substracted. + if (alignTo == AlignTo::KeyObject) { + if (!view->hasId(keyObject)) + return; + + const auto keyObjectModelNode = view->modelNodeForId(keyObject); + const QmlItemNode keyObjectQmlItemNode(keyObjectModelNode); + const auto scenePosition = keyObjectQmlItemNode.instanceScenePosition(); + keyObjectModelNode.setAuxiliaryData("tmp", + (getDimension(target) == Dimension::X + ? scenePosition.x() + : scenePosition.y())); + selectedNodes.append(keyObjectModelNode); + } + + Utils::sort(selectedNodes, compareByDepth); + + const QByteArray operationName = "distribute" + QVariant::fromValue(target).toByteArray(); + + view->executeInTransaction("DesignerActionManager|" + operationName, [&]() { + for (const ModelNode &modelNode : selectedNodes) { + QTC_ASSERT(!modelNode.isRootNode(), continue); + if (QmlItemNode::isValidQmlItemNode(modelNode)) { + QmlItemNode qmlItemNode(modelNode); + qreal parentPosition; + QByteArray propertyName; + switch (getDimension(target)) { + case Dimension::X: { + parentPosition = getInstanceSceneX(qmlItemNode.instanceParentItem()); + propertyName = "x"; + break; + } + case Dimension::Y: { + parentPosition = getInstanceSceneY(qmlItemNode.instanceParentItem()); + propertyName = "y"; + break; + } + } + qmlItemNode.setVariantProperty(propertyName, + modelNode.auxiliaryData("tmp").toReal() + - parentPosition); + modelNode.removeAuxiliaryData("tmp"); + } + } + }); +} + +void AlignDistribute::distributeSpacing(Dimension dimension, + AlignTo alignTo, + const QString &keyObject, + const qreal &distance, + DistributeOrigin distributeOrigin) +{ + QTC_ASSERT(m_qmlObjectNode.isValid(), return ); + + const auto selectionContext = SelectionContext(m_qmlObjectNode.view()); + if (selectionContext.selectedModelNodes().empty()) + return; + + AbstractView *view = selectionContext.view(); + QList<ModelNode> selectedNodes = selectionContext.selectedModelNodes(); + QRectF boundingRect; + + switch (alignTo) { + case AlignDistribute::AlignTo::Selection: { + boundingRect = getBoundingRect(selectedNodes); + break; + } + case AlignDistribute::AlignTo::Root: { + const QmlItemNode rootQmlItemNode(selectionContext.view()->rootModelNode()); + boundingRect = rootQmlItemNode.instanceSceneBoundingRect(); + break; + } + case AlignDistribute::AlignTo::KeyObject: { + if (!view->hasId(keyObject)) + return; + + // Remove key object from selected nodes list and set bounding box according to key object. + const auto keyObjectModelNode = view->modelNodeForId(keyObject); + selectedNodes.removeOne(keyObjectModelNode); + const QmlItemNode keyObjectQmlItemNode(keyObjectModelNode); + boundingRect = keyObjectQmlItemNode.instanceSceneBoundingRect(); + break; + } + } + + Utils::sort(selectedNodes, (dimension == Dimension::X) ? compareByCenterH : compareByCenterV); + + // Calculate the space between the items and set a proper start position for the different + // distribution directions/origins. + QPointF position = boundingRect.topLeft(); + const QSizeF summedSize = getSummedSize(selectedNodes); + qreal equidistant = distance; + + if (distributeOrigin == DistributeOrigin::None) { + const qreal lengthDifference = (dimension == Dimension::X) + ? (boundingRect.width() - summedSize.width()) + : (boundingRect.height() - summedSize.height()); + equidistant = lengthDifference / (selectedNodes.size() - 1); + qreal tmp; + if (std::modf(equidistant, &tmp) != 0.0) { + if (!executePixelPerfectDialog()) + return; + } + } else if (distributeOrigin == DistributeOrigin::Center + || distributeOrigin == DistributeOrigin::BottomRight) { + const qreal multiplier = (distributeOrigin == DistributeOrigin::Center) ? 0.5 : 1.0; + if (dimension == Dimension::X) { + const qreal totalLength = summedSize.width() + (distance * (selectedNodes.size() - 1)); + position.rx() -= (totalLength - boundingRect.width()) * multiplier; + } else { + const qreal totalLength = summedSize.height() + (distance * (selectedNodes.size() - 1)); + position.ry() -= (totalLength - boundingRect.height()) * multiplier; + } + } + + for (const ModelNode &modelNode : selectedNodes) { + if (QmlItemNode::isValidQmlItemNode(modelNode)) { + const QmlItemNode qmlItemNode(modelNode); + qreal currentPosition; + if (dimension == Dimension::X) { + currentPosition = position.x(); + position.rx() += width(qmlItemNode) + equidistant; + } else { + currentPosition = position.y(); + position.ry() += height(qmlItemNode) + equidistant; + } + modelNode.setAuxiliaryData("tmp", qRound(currentPosition)); + } + } + + // Append key object to selected nodes list again. This needs to be done, so relative distribution + // will also work on nested item targets. Otherwise change of parents position will move the inner + // objects too. To compensate for that, the absolute parent position needs to be substracted. + if (alignTo == AlignTo::KeyObject) { + if (!view->hasId(keyObject)) + return; + + const auto keyObjectModelNode = view->modelNodeForId(keyObject); + const QmlItemNode keyObjectQmlItemNode(keyObjectModelNode); + const auto scenePosition = keyObjectQmlItemNode.instanceScenePosition(); + keyObjectModelNode.setAuxiliaryData("tmp", + (dimension == Dimension::X ? scenePosition.x() + : scenePosition.y())); + selectedNodes.append(keyObjectModelNode); + } + + Utils::sort(selectedNodes, compareByDepth); + + const QByteArray operationName = (dimension == Dimension::X) ? "distributeSpacingHorizontal" + : "distributeSpacingVertical"; + + view->executeInTransaction("DesignerActionManager|" + operationName, [&]() { + for (const ModelNode &modelNode : selectedNodes) { + QTC_ASSERT(!modelNode.isRootNode(), continue); + if (QmlItemNode::isValidQmlItemNode(modelNode)) { + QmlItemNode qmlItemNode(modelNode); + qreal parentPos; + QByteArray propertyName; + switch (dimension) { + case Dimension::X: { + parentPos = getInstanceSceneX(qmlItemNode.instanceParentItem()); + propertyName = "x"; + break; + } + case Dimension::Y: { + parentPos = getInstanceSceneY(qmlItemNode.instanceParentItem()); + propertyName = "y"; + break; + } + } + qmlItemNode.setVariantProperty(propertyName, + modelNode.auxiliaryData("tmp").toReal() - parentPos); + modelNode.removeAuxiliaryData("tmp"); + } + } + }); +} + +AlignDistribute::CompareFunction AlignDistribute::getCompareFunction(Target target) const +{ + static const std::map<Target, CompareFunction> cmpMap = {{Target::Left, compareByLeft}, + {Target::CenterH, compareByCenterH}, + {Target::Right, compareByRight}, + {Target::Top, compareByTop}, + {Target::CenterV, compareByCenterV}, + {Target::Bottom, compareByBottom}}; + return cmpMap.at(target); +} + +AlignDistribute::Dimension AlignDistribute::getDimension(Target target) const +{ + switch (target) { + case Target::Left: + case Target::CenterH: + case Target::Right: { + return Dimension::X; + } + case Target::Top: + case Target::CenterV: + case Target::Bottom: { + return Dimension::Y; + } + } + return Dimension::X; +} + +bool AlignDistribute::executePixelPerfectDialog() const +{ + QDialogButtonBox::StandardButton pressed = Utils::CheckableMessageBox::doNotAskAgainQuestion( + Core::ICore::dialogParent(), + tr("Cannot distribute perfectly"), + tr("These objects cannot be distributed to equal pixel values. " + "Do you want to distribute to the nearest possible values?"), + Core::ICore::settings(), + "WarnAboutPixelPerfectDistribution"); + return (pressed == QDialogButtonBox::Yes) ? true : false; +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/propertyeditor/aligndistribute.h b/src/plugins/qmldesigner/components/propertyeditor/aligndistribute.h new file mode 100644 index 0000000000..1b2714f750 --- /dev/null +++ b/src/plugins/qmldesigner/components/propertyeditor/aligndistribute.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ + +#ifndef ALIGNDISTRIBUTE_H +#define ALIGNDISTRIBUTE_H + +#include <QtQml> + +#include <selectioncontext.h> +#include <qmlitemnode.h> + +namespace QmlDesigner { + +class AlignDistribute : public QObject +{ + Q_OBJECT + + Q_PROPERTY(bool multiSelection READ multiSelection NOTIFY modelNodeBackendChanged) + Q_PROPERTY(bool selectionHasAnchors READ selectionHasAnchors NOTIFY modelNodeBackendChanged) + Q_PROPERTY( + bool selectionExclusivlyItems READ selectionExclusivlyItems NOTIFY modelNodeBackendChanged) + Q_PROPERTY(bool selectionContainsRootItem READ selectionContainsRootItem NOTIFY + modelNodeBackendChanged) + + Q_PROPERTY(QVariant modelNodeBackendProperty READ getModelNodeBackend WRITE setModelNodeBackend + NOTIFY modelNodeBackendChanged) + +public: + explicit AlignDistribute(QObject *parent = nullptr); + + enum AlignTo { Selection, Root, KeyObject }; + Q_ENUM(AlignTo) + + enum DistributeOrigin { None, TopLeft, Center, BottomRight }; + Q_ENUM(DistributeOrigin) + + enum Dimension { X, Y }; + Q_ENUM(Dimension) + + enum Target { Left, CenterH, Right, Top, CenterV, Bottom }; + Q_ENUM(Target) + + bool multiSelection() const; + bool selectionHasAnchors() const; + bool selectionExclusivlyItems() const; + bool selectionContainsRootItem() const; + + void setModelNodeBackend(const QVariant &modelNodeBackend); + QVariant getModelNodeBackend() const; + + static void registerDeclarativeType(); + + Q_INVOKABLE void alignObjects(Target target, AlignTo alignTo, const QString &keyObject); + Q_INVOKABLE void distributeObjects(Target target, AlignTo alignTo, const QString &keyObject); + Q_INVOKABLE void distributeSpacing(Dimension dimension, + AlignTo alignTo, + const QString &keyObject, + const qreal &distance, + DistributeOrigin distributeOrigin); + +signals: + void modelNodeBackendChanged(); + +private: + using CompareFunction = std::function<bool(const ModelNode &, const ModelNode &)>; + + CompareFunction getCompareFunction(Target target) const; + Dimension getDimension(Target target) const; + bool executePixelPerfectDialog() const; + + QmlObjectNode m_qmlObjectNode; +}; + +} // namespace QmlDesigner + +QML_DECLARE_TYPE(QmlDesigner::AlignDistribute) + +#endif //ALIGNDISTRIBUTE_H diff --git a/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.cpp index fab5366e6d..fab8cde66e 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.cpp @@ -34,7 +34,7 @@ #include <qmlmodelnodeproxy.h> ItemFilterModel::ItemFilterModel(QObject *parent) : - QObject(parent), m_typeFilter("QtQuick.Item"), m_lock(false) + QObject(parent), m_typeFilter("QtQuick.Item"), m_lock(false), m_selectionOnly(false) { } @@ -61,11 +61,24 @@ void ItemFilterModel::setTypeFilter(const QString &filter) } } +void ItemFilterModel::setSelectionOnly(bool value) +{ + if (m_selectionOnly != value) { + m_selectionOnly = value; + setupModel(); + } +} + QString ItemFilterModel::typeFilter() const { return m_typeFilter; } +bool ItemFilterModel::selectionOnly() const +{ + return m_selectionOnly; +} + void ItemFilterModel::registerDeclarativeType() { qmlRegisterType<ItemFilterModel>("HelperWidgets",2,0,"ItemFilterModel"); @@ -85,7 +98,9 @@ void ItemFilterModel::setupModel() m_lock = true; m_model.clear(); - for (const QmlDesigner::ModelNode &node : m_modelNode.view()->allModelNodes()) { + const auto nodes = m_selectionOnly ? m_modelNode.view()->selectedModelNodes() : m_modelNode.view()->allModelNodes(); + + for (const QmlDesigner::ModelNode &node : nodes) { if (node.hasId() && node.metaInfo().isValid() && node.metaInfo().isSubclassOf(m_typeFilter.toUtf8())) m_model.append(node.id()); } diff --git a/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.h b/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.h index 032bd2baff..a26cacc685 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.h +++ b/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.h @@ -40,13 +40,16 @@ class ItemFilterModel : public QObject Q_PROPERTY(QString typeFilter READ typeFilter WRITE setTypeFilter) Q_PROPERTY(QVariant modelNodeBackendProperty READ modelNodeBackend WRITE setModelNodeBackend NOTIFY modelNodeBackendChanged) Q_PROPERTY(QStringList itemModel READ itemModel NOTIFY itemModelChanged) + Q_PROPERTY(bool selectionOnly READ selectionOnly WRITE setSelectionOnly NOTIFY selectionOnlyChanged) public: explicit ItemFilterModel(QObject *parent = nullptr); void setModelNodeBackend(const QVariant &modelNodeBackend); void setTypeFilter(const QString &typeFilter); + void setSelectionOnly(bool value); QString typeFilter() const; + bool selectionOnly() const; void setupModel(); QStringList itemModel() const; @@ -55,6 +58,7 @@ public: signals: void modelNodeBackendChanged(); void itemModelChanged(); + void selectionOnlyChanged(); private: QVariant modelNodeBackend() const; @@ -64,6 +68,7 @@ private: bool m_lock; QStringList m_model; QmlDesigner::ModelNode m_modelNode; + bool m_selectionOnly; }; QML_DECLARE_TYPE(ItemFilterModel) diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditor.pri b/src/plugins/qmldesigner/components/propertyeditor/propertyeditor.pri index 0777202db4..1fb9a3981f 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditor.pri +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditor.pri @@ -19,7 +19,8 @@ SOURCES += propertyeditorview.cpp \ simplecolorpalette.cpp \ simplecolorpalettemodel.cpp \ simplecolorpalettesingleton.cpp \ - itemfiltermodel.cpp + itemfiltermodel.cpp \ + aligndistribute.cpp HEADERS += propertyeditorview.h \ qmlanchorbindingproxy.h \ @@ -40,6 +41,7 @@ HEADERS += propertyeditorview.h \ simplecolorpalette.h \ simplecolorpalettemodel.h \ simplecolorpalettesingleton.h \ - itemfiltermodel.h + itemfiltermodel.h \ + aligndistribute.h QT += qml quick diff --git a/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp index 7ff25cad8e..3987435802 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/quick2propertyeditorview.cpp @@ -35,6 +35,7 @@ #include "bindingeditor/bindingeditor.h" #include "qmlanchorbindingproxy.h" #include "theme.h" +#include "aligndistribute.h" namespace QmlDesigner { @@ -59,6 +60,7 @@ void Quick2PropertyEditorView::registerQmlTypes() SimpleColorPaletteModel::registerDeclarativeType(); Internal::QmlAnchorBindingProxy::registerDeclarativeType(); BindingEditor::registerDeclarativeType(); + AlignDistribute::registerDeclarativeType(); } } diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp index 8ad8499d17..a233e19aad 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp @@ -272,7 +272,7 @@ void TimelineToolBar::createLeftControls() auto *curveEditorAction = createAction(TimelineConstants::C_CURVE_EDITOR, TimelineIcons::CURVE_EDITORDIALOG.icon(), - tr("Curve Editor"), + tr("Animation Curve Editor"), QKeySequence(Qt::Key_C)); connect(curveEditorAction, @@ -396,10 +396,10 @@ void TimelineToolBar::createCenterControls() auto *curvePicker = createAction(TimelineConstants::C_CURVE_PICKER, TimelineIcons::CURVE_EDITOR.icon(), - tr("Curve Picker"), + tr("Easing Curve Editor"), QKeySequence(Qt::Key_C)); - curvePicker->setObjectName("Curve Picker"); + curvePicker->setObjectName("Easing Curve Editor"); connect(curvePicker, &QAction::triggered, this, &TimelineToolBar::openEasingCurveEditor); addAction(curvePicker); diff --git a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h index 2d19cf6b95..ba2f6b283c 100644 --- a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h +++ b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h @@ -46,7 +46,7 @@ class Target; namespace QmlDesigner { -class NodeInstanceServerInterface; +class NodeInstanceServerProxy; class CreateSceneCommand; class CreateInstancesCommand; class ClearSceneCommand; @@ -195,7 +195,7 @@ private: //variables QHash<ModelNode, NodeInstance> m_nodeInstanceHash; QHash<ModelNode, QImage> m_statePreviewImage; - QPointer<NodeInstanceServerInterface> m_nodeInstanceServer; + QPointer<NodeInstanceServerProxy> m_nodeInstanceServer; QImage m_baseStatePreviewImage; QElapsedTimer m_lastCrashTime; NodeInstanceServerInterface::RunModus m_runModus; diff --git a/src/plugins/qmldesigner/designercore/include/qmlitemnode.h b/src/plugins/qmldesigner/designercore/include/qmlitemnode.h index 88afc72cb1..0c6693f505 100644 --- a/src/plugins/qmldesigner/designercore/include/qmlitemnode.h +++ b/src/plugins/qmldesigner/designercore/include/qmlitemnode.h @@ -98,6 +98,7 @@ public: bool modelIsInLayout() const; QRectF instanceBoundingRect() const; + QRectF instanceSceneBoundingRect() const; QRectF instancePaintedBoundingRect() const; QRectF instanceContentItemBoundingRect() const; QTransform instanceTransform() const; diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index c51b40f728..899dc5caee 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -1074,11 +1074,14 @@ ChangeValuesCommand NodeInstanceView::createChangeValueCommand(const QList<Varia { QVector<PropertyValueContainer> containerList; + const bool reflectionFlag = m_puppetTransaction.isValid(); + foreach (const VariantProperty &property, propertyList) { ModelNode node = property.parentModelNode(); if (node.isValid() && hasInstanceForModelNode(node)) { NodeInstance instance = instanceForModelNode(node); PropertyValueContainer container(instance.instanceId(), property.name(), property.value(), property.dynamicTypeName()); + container.setReflectionFlag(reflectionFlag); containerList.append(container); } @@ -1222,8 +1225,6 @@ void NodeInstanceView::valuesModified(const ValuesModifiedCommand &command) if (command.transactionOption == ValuesModifiedCommand::TransactionOption::Start) startPuppetTransaction(); - else if (command.transactionOption == ValuesModifiedCommand::TransactionOption::End) - endPuppetTransaction(); for (const PropertyValueContainer &container : command.valueChanges()) { if (hasInstanceForId(container.instanceId())) { @@ -1236,6 +1237,9 @@ void NodeInstanceView::valuesModified(const ValuesModifiedCommand &command) } } } + + if (command.transactionOption == ValuesModifiedCommand::TransactionOption::End) + endPuppetTransaction(); } void NodeInstanceView::pixmapChanged(const PixmapChangedCommand &command) diff --git a/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp index 0b33aa655a..2fc530ff10 100644 --- a/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp @@ -384,6 +384,11 @@ QRectF QmlItemNode::instanceBoundingRect() const return QRectF(QPointF(0, 0), nodeInstance().size()); } +QRectF QmlItemNode::instanceSceneBoundingRect() const +{ + return QRectF(instanceScenePosition(), nodeInstance().size()); +} + QRectF QmlItemNode::instancePaintedBoundingRect() const { return nodeInstance().boundingRect(); diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp index 69bc9ff0f9..a05c3b674a 100644 --- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp @@ -355,11 +355,14 @@ bool compareJavaScriptExpression(const QString &expression1, const QString &expr } bool smartVeryFuzzyCompare(const QVariant &value1, const QVariant &value2) -{ //we ignore slight changes on doubles and only check three digits - if ((value1.type() == QMetaType::Double) - || (value2.type() == QMetaType::Double) - || (value1.type() == QMetaType::Float) - || (value2.type() == QMetaType::Float)) { +{ + //we ignore slight changes on doubles and only check three digits + const auto type1 = static_cast<QMetaType::Type>(value1.type()); + const auto type2 = static_cast<QMetaType::Type>(value2.type()); + if (type1 == QMetaType::Double + || type2 == QMetaType::Double + || type1 == QMetaType::Float + || type2 == QMetaType::Float) { bool ok1, ok2; qreal a = value1.toDouble(&ok1); qreal b = value2.toDouble(&ok2); diff --git a/src/plugins/qmldesigner/designersettings.cpp b/src/plugins/qmldesigner/designersettings.cpp index 5870927d52..f1afe3cf66 100644 --- a/src/plugins/qmldesigner/designersettings.cpp +++ b/src/plugins/qmldesigner/designersettings.cpp @@ -77,6 +77,7 @@ void DesignerSettings::fromSettings(QSettings *settings) restoreValue(settings, DesignerSettingsKey::STANDALONE_MODE, false); restoreValue(settings, DesignerSettingsKey::ENABLE_TIMELINEVIEW, false); restoreValue(settings, DesignerSettingsKey::SIMPLE_COLOR_PALETTE_CONTENT, QStringList()); + restoreValue(settings, DesignerSettingsKey::ALWAYS_DESIGN_MODE, true); settings->endGroup(); settings->endGroup(); diff --git a/src/plugins/qmldesigner/designersettings.h b/src/plugins/qmldesigner/designersettings.h index 410abc267e..ec4dc1f7e5 100644 --- a/src/plugins/qmldesigner/designersettings.h +++ b/src/plugins/qmldesigner/designersettings.h @@ -66,6 +66,7 @@ const char IGNORE_DEVICE_PIXEL_RATIO[] = "IgnoreDevicePixelRaio"; /* The setting const char STANDALONE_MODE[] = "StandAloneMode"; const char ENABLE_TIMELINEVIEW[] = "EnableTimelineView"; const char SIMPLE_COLOR_PALETTE_CONTENT[] = "SimpleColorPaletteContent"; +const char ALWAYS_DESIGN_MODE[] = "AlwaysDesignMode"; } class DesignerSettings : public QHash<QByteArray, QVariant> diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index 3ce4512fe1..2dbf40a7bb 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -96,7 +96,9 @@ QtQuickDesignerFactory::QtQuickDesignerFactory() addMimeType(QmlJSTools::Constants::QMLUI_MIMETYPE); setDocumentCreator([this]() { auto document = new QmlJSEditor::QmlJSEditorDocument(id()); - document->setIsDesignModePreferred(true); + document->setIsDesignModePreferred( + QmlDesigner::DesignerSettings::getValue( + QmlDesigner::DesignerSettingsKey::ALWAYS_DESIGN_MODE).toBool()); return document; }); } diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index 0d7b54c68e..f2fdd76598 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -568,6 +568,8 @@ Project { "navigator/navigatorview.h", "navigator/navigatorwidget.cpp", "navigator/navigatorwidget.h", + "propertyeditor/aligndistribute.cpp", + "propertyeditor/aligndistribute.h", "propertyeditor/designerpropertymap.cpp", "propertyeditor/designerpropertymap.h", "propertyeditor/fileresourcesmodel.cpp", diff --git a/src/plugins/qmldesigner/settingspage.cpp b/src/plugins/qmldesigner/settingspage.cpp index a7d6bc2bb0..6cfc1ebf45 100644 --- a/src/plugins/qmldesigner/settingspage.cpp +++ b/src/plugins/qmldesigner/settingspage.cpp @@ -161,6 +161,8 @@ DesignerSettings SettingsPageWidget::settings() const m_ui.showWarnExceptionsCheckBox->isChecked()); settings.insert(DesignerSettingsKey::ENABLE_TIMELINEVIEW, m_ui.featureTimelineEditorCheckBox->isChecked()); + settings.insert(DesignerSettingsKey::ALWAYS_DESIGN_MODE, + m_ui.designerAlwaysDesignModeCheckBox->isChecked()); return settings; } @@ -226,13 +228,15 @@ void SettingsPageWidget::setSettings(const DesignerSettings &settings) m_ui.controls2StyleComboBox->setCurrentText(m_ui.styleLineEdit->text()); + m_ui.designerAlwaysDesignModeCheckBox->setChecked(settings.value( + DesignerSettingsKey::ALWAYS_DESIGN_MODE).toBool()); m_ui.featureTimelineEditorCheckBox->setChecked(settings.value( DesignerSettingsKey::ENABLE_TIMELINEVIEW).toBool()); if (settings.value(DesignerSettingsKey::STANDALONE_MODE).toBool()) { m_ui.emulationGroupBox->hide(); m_ui.debugGroupBox->hide(); - m_ui.featuresGroupBox->hide(); + m_ui.featureTimelineEditorCheckBox->hide(); } } diff --git a/src/plugins/qmldesigner/settingspage.ui b/src/plugins/qmldesigner/settingspage.ui index 7da62b300a..dabe3df734 100644 --- a/src/plugins/qmldesigner/settingspage.ui +++ b/src/plugins/qmldesigner/settingspage.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>685</width> - <height>555</height> + <width>960</width> + <height>840</height> </rect> </property> <property name="windowTitle"> @@ -415,14 +415,21 @@ <property name="title"> <string>Features</string> </property> - <layout class="QVBoxLayout" name="verticalLayout_5"> - <item> + <layout class="QGridLayout" name="gridLayout_6"> + <item row="0" column="1"> <widget class="QCheckBox" name="featureTimelineEditorCheckBox"> <property name="text"> <string>Enable Timeline editor</string> </property> </widget> </item> + <item row="0" column="0"> + <widget class="QCheckBox" name="designerAlwaysDesignModeCheckBox"> + <property name="text"> + <string>Always open ui.qml files in Design mode</string> + </property> + </widget> + </item> </layout> </widget> </item> diff --git a/src/plugins/updateinfo/updateinfoplugin.cpp b/src/plugins/updateinfo/updateinfoplugin.cpp index 4644823ed5..c602136ef2 100644 --- a/src/plugins/updateinfo/updateinfoplugin.cpp +++ b/src/plugins/updateinfo/updateinfoplugin.cpp @@ -193,7 +193,7 @@ void UpdateInfoPlugin::checkForUpdatesFinished() d->m_progress->setKeepOnFinish(FutureProgress::HideOnFinish); emit newUpdatesAvailable(true); Core::InfoBarEntry info(InstallUpdates, - tr("New updates are available. Do you want to start the update?")); + tr("New updates are available. Start the update?")); info.setCustomButtonInfo(tr("Start Update"), [this] { Core::ICore::infoBar()->removeInfo(InstallUpdates); startUpdater(); @@ -202,7 +202,7 @@ void UpdateInfoPlugin::checkForUpdatesFinished() info.setDetailsWidgetCreator([updates]() -> QWidget * { const QString updateText = updates.join("</li><li>"); auto label = new QLabel; - label->setText("<qt><p>" + tr("Available Updates:") + "<ul><li>" + updateText + label->setText("<qt><p>" + tr("Available updates:") + "<ul><li>" + updateText + "</li></ul></p></qt>"); label->setContentsMargins(0, 0, 0, 8); return label; |