diff options
author | Eike Ziller <eike.ziller@qt.io> | 2017-07-28 15:24:14 +0200 |
---|---|---|
committer | Eike Ziller <eike.ziller@qt.io> | 2017-07-28 15:24:14 +0200 |
commit | c01ddc4660c10e8ddc605602fd623135fb607de0 (patch) | |
tree | fdf50dee801ce09d2a6d671d558b73d8769870d9 /src/libs | |
parent | 712297cbf0b73d8af8db3921c646ed252b0c41d7 (diff) | |
parent | 36968528805d99a746d27f2632cabc1a132e535f (diff) |
Merge remote-tracking branch 'origin/4.4'
Conflicts:
qbs/modules/qtc/qtc.qbs
qtcreator.pri
src/plugins/qbsprojectmanager/qbsproject.h
Change-Id: I6b9cdf704be95ade02488c8b19582b6621282fb8
Diffstat (limited to 'src/libs')
20 files changed, 618 insertions, 47 deletions
diff --git a/src/libs/3rdparty/cplusplus/ASTPatternBuilder.cpp b/src/libs/3rdparty/cplusplus/ASTPatternBuilder.cpp deleted file mode 100644 index 0c1549e51b8..00000000000 --- a/src/libs/3rdparty/cplusplus/ASTPatternBuilder.cpp +++ /dev/null @@ -1,2 +0,0 @@ - -#include "ASTPatternBuilder.h" diff --git a/src/libs/3rdparty/cplusplus/ObjectiveCAtKeywords.cpp b/src/libs/3rdparty/cplusplus/ObjectiveCAtKeywords.cpp index d05222c681a..8177368d7f1 100644 --- a/src/libs/3rdparty/cplusplus/ObjectiveCAtKeywords.cpp +++ b/src/libs/3rdparty/cplusplus/ObjectiveCAtKeywords.cpp @@ -1,3 +1,22 @@ +// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. #include "Lexer.h" #include "Token.h" diff --git a/src/libs/3rdparty/cplusplus/ObjectiveCTypeQualifiers.cpp b/src/libs/3rdparty/cplusplus/ObjectiveCTypeQualifiers.cpp index 6b85bf4a1b1..6005fe574fc 100644 --- a/src/libs/3rdparty/cplusplus/ObjectiveCTypeQualifiers.cpp +++ b/src/libs/3rdparty/cplusplus/ObjectiveCTypeQualifiers.cpp @@ -1,3 +1,22 @@ +// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. #include "ObjectiveCTypeQualifiers.h" diff --git a/src/libs/3rdparty/cplusplus/ObjectiveCTypeQualifiers.h b/src/libs/3rdparty/cplusplus/ObjectiveCTypeQualifiers.h index ac46bd6070f..3f920e5bfc2 100644 --- a/src/libs/3rdparty/cplusplus/ObjectiveCTypeQualifiers.h +++ b/src/libs/3rdparty/cplusplus/ObjectiveCTypeQualifiers.h @@ -1,9 +1,27 @@ -#ifndef CPLUSPLUS_OBJC_TYPEQUALIFIERS_H -#define CPLUSPLUS_OBJC_TYPEQUALIFIERS_H +// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#pragma once #include "CPlusPlusForwardDeclarations.h" - namespace CPlusPlus { enum { @@ -27,6 +45,3 @@ enum { CPLUSPLUS_EXPORT int classifyObjectiveCContextKeyword(const char *s, int n); } // namespace CPlusPlus - - -#endif // CPLUSPLUS_OBJC_TYPEQUALIFIERS_H diff --git a/src/libs/3rdparty/cplusplus/QtContextKeywords.cpp b/src/libs/3rdparty/cplusplus/QtContextKeywords.cpp index 87403aed14f..ce7bd0a1dde 100644 --- a/src/libs/3rdparty/cplusplus/QtContextKeywords.cpp +++ b/src/libs/3rdparty/cplusplus/QtContextKeywords.cpp @@ -1,3 +1,22 @@ +// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. #include "QtContextKeywords.h" diff --git a/src/libs/3rdparty/cplusplus/QtContextKeywords.h b/src/libs/3rdparty/cplusplus/QtContextKeywords.h index edef73a7ee8..42dce9b917d 100644 --- a/src/libs/3rdparty/cplusplus/QtContextKeywords.h +++ b/src/libs/3rdparty/cplusplus/QtContextKeywords.h @@ -1,3 +1,22 @@ +// Copyright (c) 2008 Roberto Raggi <roberto.raggi@gmail.com> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. #pragma once diff --git a/src/libs/3rdparty/cplusplus/SafeMatcher.h b/src/libs/3rdparty/cplusplus/SafeMatcher.h index 98219eeffdc..98fbbae2aa2 100644 --- a/src/libs/3rdparty/cplusplus/SafeMatcher.h +++ b/src/libs/3rdparty/cplusplus/SafeMatcher.h @@ -23,8 +23,7 @@ ** ****************************************************************************/ -#ifndef CPLUSPLUS_SAFETYPEMATCHER_H -#define CPLUSPLUS_SAFETYPEMATCHER_H +#pragma once #include "Matcher.h" @@ -56,5 +55,3 @@ private: }; } // CPlusPlus namespace - -#endif // CPLUSPLUS_SAFETYPEMATCHER_H diff --git a/src/libs/3rdparty/cplusplus/cplusplus.pri b/src/libs/3rdparty/cplusplus/cplusplus.pri index 025519ef89c..2a4f71a7122 100644 --- a/src/libs/3rdparty/cplusplus/cplusplus.pri +++ b/src/libs/3rdparty/cplusplus/cplusplus.pri @@ -40,7 +40,6 @@ SOURCES += \ $$PWD/ASTMatch0.cpp \ $$PWD/ASTVisitor.cpp \ $$PWD/ASTClone.cpp \ - $$PWD/ASTPatternBuilder.cpp \ $$PWD/ASTMatcher.cpp \ $$PWD/Matcher.cpp \ $$PWD/Control.cpp \ diff --git a/src/libs/cplusplus/cplusplus.qbs b/src/libs/cplusplus/cplusplus.qbs index c9aae72b3e3..a0e0d66178c 100644 --- a/src/libs/cplusplus/cplusplus.qbs +++ b/src/libs/cplusplus/cplusplus.qbs @@ -30,7 +30,6 @@ Project { "ASTMatch0.cpp", "ASTMatcher.cpp", "ASTMatcher.h", - "ASTPatternBuilder.cpp", "ASTPatternBuilder.h", "ASTVisit.cpp", "ASTVisitor.cpp", diff --git a/src/libs/extensionsystem/pluginspec.cpp b/src/libs/extensionsystem/pluginspec.cpp index cde1903099f..8fd64007a29 100644 --- a/src/libs/extensionsystem/pluginspec.cpp +++ b/src/libs/extensionsystem/pluginspec.cpp @@ -32,6 +32,7 @@ #include <utils/algorithm.h> #include <utils/qtcassert.h> +#include <utils/stringutils.h> #include <QCoreApplication> #include <QDebug> @@ -631,26 +632,6 @@ static inline QString msgInvalidFormat(const char *key, const QString &content) .arg(QLatin1String(key), content); } -bool PluginSpec::readMultiLineString(const QJsonValue &value, QString *out) -{ - QTC_ASSERT(out, return false); - if (value.isString()) { - *out = value.toString(); - } else if (value.isArray()) { - QJsonArray array = value.toArray(); - QStringList lines; - foreach (const QJsonValue &v, array) { - if (!v.isString()) - return false; - lines.append(v.toString()); - } - *out = lines.join(QLatin1Char('\n')); - } else { - return false; - } - return true; -} - /*! \internal */ @@ -735,7 +716,7 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &pluginMetaData) copyright = value.toString(); value = metaData.value(QLatin1String(DESCRIPTION)); - if (!value.isUndefined() && !PluginSpec::readMultiLineString(value, &description)) + if (!value.isUndefined() && !Utils::readMultiLineString(value, &description)) return reportError(msgValueIsNotAString(DESCRIPTION)); value = metaData.value(QLatin1String(URL)); @@ -749,7 +730,7 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &pluginMetaData) category = value.toString(); value = metaData.value(QLatin1String(LICENSE)); - if (!value.isUndefined() && !PluginSpec::readMultiLineString(value, &license)) + if (!value.isUndefined() && !Utils::readMultiLineString(value, &license)) return reportError(msgValueIsNotAMultilineString(LICENSE)); value = metaData.value(QLatin1String(PLATFORM)); @@ -799,7 +780,7 @@ bool PluginSpecPrivate::readMetaData(const QJsonObject &pluginMetaData) } else if (typeValue.toLower() == QLatin1String(DEPENDENCY_TYPE_TEST)) { dep.type = PluginDependency::Test; } else { - return reportError(tr("Dependency: \"%1\" must be \"%2\" or \"%3\" (is \"%4\")") + return reportError(tr("Dependency: \"%1\" must be \"%2\" or \"%3\" (is \"%4\").") .arg(QLatin1String(DEPENDENCY_TYPE), QLatin1String(DEPENDENCY_TYPE_HARD), QLatin1String(DEPENDENCY_TYPE_SOFT), diff --git a/src/libs/extensionsystem/pluginspec.h b/src/libs/extensionsystem/pluginspec.h index da89ff6029f..0462acddefe 100644 --- a/src/libs/extensionsystem/pluginspec.h +++ b/src/libs/extensionsystem/pluginspec.h @@ -131,8 +131,6 @@ public: bool hasError() const; QString errorString() const; - static bool readMultiLineString(const QJsonValue &value, QString *out); - private: PluginSpec(); diff --git a/src/libs/modelinglib/qmt/model_controller/modelcontroller.cpp b/src/libs/modelinglib/qmt/model_controller/modelcontroller.cpp index ddaeafc29f1..614069e0b37 100644 --- a/src/libs/modelinglib/qmt/model_controller/modelcontroller.cpp +++ b/src/libs/modelinglib/qmt/model_controller/modelcontroller.cpp @@ -758,6 +758,13 @@ void ModelController::moveObject(MPackage *newOwner, MObject *object) QMT_ASSERT(object, return); QMT_ASSERT(object != m_rootPackage, return); + // verify that newOwner is not a child of object + MObject *newOwnerObject = newOwner; + while (newOwnerObject && newOwnerObject != object) + newOwnerObject = newOwnerObject->owner(); + if (newOwnerObject == object) + return; + if (newOwner != object->owner()) { int formerRow = 0; MObject *formerOwner = object->owner(); diff --git a/src/libs/qtcreatorcdbext/qtcreatorcdbext.qbs b/src/libs/qtcreatorcdbext/qtcreatorcdbext.qbs index 1e1edbefb32..2243c217586 100644 --- a/src/libs/qtcreatorcdbext/qtcreatorcdbext.qbs +++ b/src/libs/qtcreatorcdbext/qtcreatorcdbext.qbs @@ -2,6 +2,8 @@ import qbs import qbs.Environment import qbs.File import qbs.FileInfo +import qbs.Process +import qbs.Utilities QtcLibrary { condition: qbs.toolchain.contains("msvc") && cdbPath @@ -45,11 +47,98 @@ QtcLibrary { } return undefined; } - cpp.includePaths: [FileInfo.joinPaths(cdbPath, "inc")] - cpp.dynamicLibraries: [ - "user32.lib", - FileInfo.joinPaths(cdbLibPath, "dbgeng.lib") - ] + + property string pythonInstallDir: Environment.getEnv("PYTHON_INSTALL_DIR") + + Probe { + id: pythonDllProbe + condition: product.condition + property string pythonDir: pythonInstallDir // Input + property string buildVariant: qbs.buildVariant // Input + property string fileNamePrefix // Output + configure: { + function printWarning(msg) { + console.warn(msg + " The python dumpers for cdb will not be available."); + } + + if (!pythonDir) { + printWarning("PYTHON_INSTALL_DIR not set."); + return; + } + if (!File.exists(pythonDir)) { + printWarning("The provided python installation directory '" + pythonDir + + "' does not exist."); + return; + } + var p = new Process(); + try { + var pythonFilePath = FileInfo.joinPaths(pythonDir, "python.exe"); + p.exec(pythonFilePath, ["--version"], true); + var output = p.readStdOut().trim(); + var magicPrefix = "Python "; + if (!output.startsWith(magicPrefix)) { + printWarning("Unexpected python output when checking for version: '" + + output + "'"); + return; + } + var versionNumberString = output.slice(magicPrefix.length); + var versionNumbers = versionNumberString.split('.'); + if (versionNumbers.length < 2) { + printWarning("Unexpected python output when checking for version: '" + + output + "'"); + return; + } + if (Utilities.versionCompare(versionNumberString, "3.5") < 0) { + printWarning("The python installation at '" + pythonDir + + "' has version " + versionNumberString + ", but 3.5 or higher " + + "is required."); + return; + } + found = true; + fileNamePrefix = "python" + versionNumbers[0] + versionNumbers[1]; + if (buildVariant === "debug") + fileNamePrefix += "_d" + } finally { + p.close(); + } + + } + } + + Group { + name: "pythonDumper" + condition: pythonDllProbe.found + files: [ + "pycdbextmodule.cpp", + "pycdbextmodule.h", + "pyfield.cpp", + "pyfield.h", + "pystdoutredirect.cpp", + "pystdoutredirect.h", + "pytype.cpp", + "pytype.h", + "pyvalue.cpp", + "pyvalue.h", + ] + } + + Properties { + condition: pythonDllProbe.found + cpp.defines: ["WITH_PYTHON=1"] + } + cpp.includePaths: { + var paths = [FileInfo.joinPaths(cdbPath, "inc")]; + if (pythonDllProbe.found) + paths.push(FileInfo.joinPaths(pythonInstallDir, "include")); + return paths; + } + cpp.dynamicLibraries: { + var libs = [ "user32.lib", FileInfo.joinPaths(cdbLibPath, "dbgeng.lib") ]; + if (pythonDllProbe.found) + libs.push(FileInfo.joinPaths(pythonInstallDir, "libs", + pythonDllProbe.fileNamePrefix + ".lib")); + return libs; + } cpp.linkerFlags: ["/DEF:" + FileInfo.toWindowsSeparators( FileInfo.joinPaths(product.sourceDirectory, "qtcreatorcdbext.def"))] @@ -61,6 +150,16 @@ QtcLibrary { dirName += "32"; return FileInfo.joinPaths(qtc.libDirName, dirName); } + + Group { + condition: pythonDllProbe.found + files: [FileInfo.joinPaths(pythonInstallDir, pythonDllProbe.fileNamePrefix + ".dll")] + qbs.install: true + qbs.installDir: installDir + } + + useNonGuiPchFile: false + files: [ "common.cpp", "common.h", diff --git a/src/libs/utils/highlightingitemdelegate.cpp b/src/libs/utils/highlightingitemdelegate.cpp new file mode 100644 index 00000000000..fe2525122c8 --- /dev/null +++ b/src/libs/utils/highlightingitemdelegate.cpp @@ -0,0 +1,305 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "highlightingitemdelegate.h" + +#include <QApplication> +#include <QModelIndex> +#include <QPainter> + +const int kMinimumLineNumberDigits = 6; + +namespace Utils { + +HighlightingItemDelegate::HighlightingItemDelegate(int tabWidth, QObject *parent) + : QItemDelegate(parent) +{ + setTabWidth(tabWidth); +} + +void HighlightingItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + static const int iconSize = 16; + + painter->save(); + + const QStyleOptionViewItem opt = setOptions(index, option); + painter->setFont(opt.font); + + QItemDelegate::drawBackground(painter, opt, index); + + // ---- do the layout + QRect checkRect; + QRect pixmapRect; + QRect textRect; + + // check mark + const bool checkable = (index.model()->flags(index) & Qt::ItemIsUserCheckable); + Qt::CheckState checkState = Qt::Unchecked; + if (checkable) { + QVariant checkStateData = index.data(Qt::CheckStateRole); + checkState = static_cast<Qt::CheckState>(checkStateData.toInt()); + checkRect = doCheck(opt, opt.rect, checkStateData); + } + + // icon + const QIcon icon = index.model()->data(index, Qt::DecorationRole).value<QIcon>(); + if (!icon.isNull()) { + const QSize size = icon.actualSize(QSize(iconSize, iconSize)); + pixmapRect = QRect(0, 0, size.width(), size.height()); + } + + // text + textRect = opt.rect.adjusted(0, 0, checkRect.width() + pixmapRect.width(), 0); + + // do layout + doLayout(opt, &checkRect, &pixmapRect, &textRect, false); + // ---- draw the items + // icon + if (!icon.isNull()) + icon.paint(painter, pixmapRect, option.decorationAlignment); + + // line numbers + const int lineNumberAreaWidth = drawLineNumber(painter, opt, textRect, index); + textRect.adjust(lineNumberAreaWidth, 0, 0, 0); + + // text and focus/selection + drawText(painter, opt, textRect, index); + QItemDelegate::drawFocus(painter, opt, opt.rect); + + // check mark + if (checkable) + QItemDelegate::drawCheck(painter, opt, checkRect, checkState); + + painter->restore(); +} + +void HighlightingItemDelegate::setTabWidth(int width) +{ + m_tabString = QString(width, ' '); +} + +// returns the width of the line number area +int HighlightingItemDelegate::drawLineNumber(QPainter *painter, const QStyleOptionViewItem &option, + const QRect &rect, + const QModelIndex &index) const +{ + static const int lineNumberAreaHorizontalPadding = 4; + const int lineNumber = index.model()->data(index, int(HighlightingItemRole::LineNumber)).toInt(); + if (lineNumber < 1) + return 0; + const bool isSelected = option.state & QStyle::State_Selected; + const QString lineText = QString::number(lineNumber); + const int minimumLineNumberDigits = qMax(kMinimumLineNumberDigits, lineText.count()); + const int fontWidth = painter->fontMetrics().width(QString(minimumLineNumberDigits, '0')); + const int lineNumberAreaWidth = lineNumberAreaHorizontalPadding + fontWidth + + lineNumberAreaHorizontalPadding; + QRect lineNumberAreaRect(rect); + lineNumberAreaRect.setWidth(lineNumberAreaWidth); + + QPalette::ColorGroup cg = QPalette::Normal; + if (!(option.state & QStyle::State_Active)) + cg = QPalette::Inactive; + else if (!(option.state & QStyle::State_Enabled)) + cg = QPalette::Disabled; + + painter->fillRect(lineNumberAreaRect, QBrush(isSelected ? + option.palette.brush(cg, QPalette::Highlight) : + option.palette.color(cg, QPalette::Base).darker(111))); + + QStyleOptionViewItem opt = option; + opt.displayAlignment = Qt::AlignRight | Qt::AlignVCenter; + opt.palette.setColor(cg, QPalette::Text, Qt::darkGray); + + const QStyle *style = QApplication::style(); + const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, 0) + 1; + + const QRect rowRect + = lineNumberAreaRect.adjusted(-textMargin, 0, + textMargin - lineNumberAreaHorizontalPadding, 0); + QItemDelegate::drawDisplay(painter, opt, rowRect, lineText); + + return lineNumberAreaWidth; +} + +void HighlightingItemDelegate::drawText(QPainter *painter, + const QStyleOptionViewItem &option, + const QRect &rect, + const QModelIndex &index) const +{ + QString text = index.model()->data(index, Qt::DisplayRole).toString(); + // show number of subresults in displayString + if (index.model()->hasChildren(index)) + text += " (" + QString::number(index.model()->rowCount(index)) + ')'; + + int searchTermStart = index.model()->data(index, int(HighlightingItemRole::StartColumn)).toInt(); + int searchTermLength = index.model()->data(index, int(HighlightingItemRole::Length)).toInt(); + if (searchTermStart < 0 || searchTermStart >= text.length() || searchTermLength < 1) { + drawDisplay(painter, option, rect, text.replace('\t', m_tabString), {}); + return; + } + + // replace tabs with searchTerm bookkeeping + int searchTermEnd = searchTermStart + searchTermLength; + const int tabDiff = m_tabString.size() - 1; + for (int i = 0; i < text.length(); i++) { + if (text.at(i) == '\t') { + text.replace(i, 1, m_tabString); + if (i < searchTermStart) { + searchTermStart += tabDiff; + searchTermEnd += tabDiff; + } else if (i < searchTermEnd) { + searchTermEnd += tabDiff; + searchTermLength += tabDiff; + } + i += tabDiff; + } + } + + const QColor highlightForeground = + index.model()->data(index, int(HighlightingItemRole::Foreground)).value<QColor>(); + const QColor highlightBackground = + index.model()->data(index, int(HighlightingItemRole::Background)).value<QColor>(); + QTextCharFormat highlightFormat; + highlightFormat.setForeground(highlightForeground); + highlightFormat.setBackground(highlightBackground); + + drawDisplay(painter, option, rect, text, {{searchTermStart, searchTermLength, highlightFormat}}); +} + +// copied from QItemDelegate for drawDisplay +static QString replaceNewLine(QString text) +{ + static const QChar nl = '\n'; + for (int i = 0; i < text.count(); ++i) + if (text.at(i) == nl) + text[i] = QChar::LineSeparator; + return text; +} + +// copied from QItemDelegate for drawDisplay +QSizeF doTextLayout(QTextLayout *textLayout, int lineWidth) +{ + qreal height = 0; + qreal widthUsed = 0; + textLayout->beginLayout(); + while (true) { + QTextLine line = textLayout->createLine(); + if (!line.isValid()) + break; + line.setLineWidth(lineWidth); + line.setPosition(QPointF(0, height)); + height += line.height(); + widthUsed = qMax(widthUsed, line.naturalTextWidth()); + } + textLayout->endLayout(); + return QSizeF(widthUsed, height); +} + +// copied from QItemDelegate to be able to add the 'format' parameter +void HighlightingItemDelegate::drawDisplay(QPainter *painter, + const QStyleOptionViewItem &option, + const QRect &rect, const QString &text, + const QVector<QTextLayout::FormatRange> &format) const +{ + QPalette::ColorGroup cg = option.state & QStyle::State_Enabled + ? QPalette::Normal : QPalette::Disabled; + if (cg == QPalette::Normal && !(option.state & QStyle::State_Active)) + cg = QPalette::Inactive; + if (option.state & QStyle::State_Selected) { + painter->fillRect(rect, option.palette.brush(cg, QPalette::Highlight)); + painter->setPen(option.palette.color(cg, QPalette::HighlightedText)); + } else { + painter->setPen(option.palette.color(cg, QPalette::Text)); + } + + if (text.isEmpty()) + return; + + if (option.state & QStyle::State_Editing) { + painter->save(); + painter->setPen(option.palette.color(cg, QPalette::Text)); + painter->drawRect(rect.adjusted(0, 0, -1, -1)); + painter->restore(); + } + + const QStyleOptionViewItem opt = option; + + const QWidget *widget = option.widget; + QStyle *style = widget ? widget->style() : QApplication::style(); + const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, widget) + 1; + QRect textRect = rect.adjusted(textMargin, 0, -textMargin, 0); // remove width padding + const bool wrapText = opt.features & QStyleOptionViewItem::WrapText; + QTextOption textOption; + textOption.setWrapMode(wrapText ? QTextOption::WordWrap : QTextOption::ManualWrap); + textOption.setTextDirection(option.direction); + textOption.setAlignment(QStyle::visualAlignment(option.direction, option.displayAlignment)); + QTextLayout textLayout; + textLayout.setTextOption(textOption); + textLayout.setFont(option.font); + textLayout.setText(replaceNewLine(text)); + + QSizeF textLayoutSize = doTextLayout(&textLayout, textRect.width()); + + if (textRect.width() < textLayoutSize.width() + || textRect.height() < textLayoutSize.height()) { + QString elided; + int start = 0; + int end = text.indexOf(QChar::LineSeparator, start); + if (end == -1) { + elided += option.fontMetrics.elidedText(text, option.textElideMode, textRect.width()); + } else { + while (end != -1) { + elided += option.fontMetrics.elidedText(text.mid(start, end - start), + option.textElideMode, textRect.width()); + elided += QChar::LineSeparator; + start = end + 1; + end = text.indexOf(QChar::LineSeparator, start); + } + // let's add the last line (after the last QChar::LineSeparator) + elided += option.fontMetrics.elidedText(text.mid(start), + option.textElideMode, textRect.width()); + } + textLayout.setText(elided); + textLayoutSize = doTextLayout(&textLayout, textRect.width()); + } + + const QSize layoutSize(textRect.width(), int(textLayoutSize.height())); + const QRect layoutRect = QStyle::alignedRect(option.direction, option.displayAlignment, + layoutSize, textRect); + // if we still overflow even after eliding the text, enable clipping + if (!hasClipping() && (textRect.width() < textLayoutSize.width() + || textRect.height() < textLayoutSize.height())) { + painter->save(); + painter->setClipRect(layoutRect); + textLayout.draw(painter, layoutRect.topLeft(), format, layoutRect); + painter->restore(); + } else { + textLayout.draw(painter, layoutRect.topLeft(), format, layoutRect); + } +} + +} // namespace Utils diff --git a/src/libs/utils/highlightingitemdelegate.h b/src/libs/utils/highlightingitemdelegate.h new file mode 100644 index 00000000000..b9cfb617ddf --- /dev/null +++ b/src/libs/utils/highlightingitemdelegate.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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. +** +****************************************************************************/ + +#pragma once + +#include "utils_global.h" + +#include <QItemDelegate> +#include <QTextLayout> + +namespace Utils { + +enum class HighlightingItemRole { + LineNumber = Qt::UserRole, + StartColumn, + Length, + Foreground, + Background, + User +}; + +class QTCREATOR_UTILS_EXPORT HighlightingItemDelegate : public QItemDelegate +{ +public: + HighlightingItemDelegate(int tabWidth, QObject *parent = 0); + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; + void setTabWidth(int width); + +private: + int drawLineNumber(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect, const QModelIndex &index) const; + void drawText(QPainter *painter, const QStyleOptionViewItem &option, + const QRect &rect, const QModelIndex &index) const; + using QItemDelegate::drawDisplay; + void drawDisplay(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect, + const QString &text, const QVector<QTextLayout::FormatRange> &format) const; + QString m_tabString; +}; + +} // namespace Utils diff --git a/src/libs/utils/icon.cpp b/src/libs/utils/icon.cpp index e3a9a92ee89..f451d9697e2 100644 --- a/src/libs/utils/icon.cpp +++ b/src/libs/utils/icon.cpp @@ -36,6 +36,7 @@ #include <QPainter> #include <QPaintEngine> #include <QWidget> +#include <QDebug> namespace Utils { @@ -67,7 +68,12 @@ static MasksAndColors masksAndColors(const Icon &icon, int dpr) const QColor color = creatorTheme()->color(i.second); const QString dprFileName = StyleHelper::availableImageResolutions(i.first).contains(dpr) ? StyleHelper::imageFileWithResolution(fileName, dpr) : fileName; - result.append(qMakePair(QPixmap(dprFileName), color)); + QPixmap pixmap; + if (!pixmap.load(dprFileName)) { + pixmap = QPixmap(1, 1); + qWarning() << "Could not load image: " << dprFileName; + } + result.append({pixmap, color}); } return result; } diff --git a/src/libs/utils/stringutils.cpp b/src/libs/utils/stringutils.cpp index b69bfe6f971..f2a13991cb2 100644 --- a/src/libs/utils/stringutils.cpp +++ b/src/libs/utils/stringutils.cpp @@ -28,8 +28,11 @@ #include "hostosinfo.h" #include <utils/algorithm.h> +#include <utils/qtcassert.h> #include <QDir> +#include <QJsonArray> +#include <QJsonValue> #include <QRegularExpression> #include <QSet> @@ -246,4 +249,24 @@ QTCREATOR_UTILS_EXPORT QString stripAccelerator(const QString &text) return res; } +QTCREATOR_UTILS_EXPORT bool readMultiLineString(const QJsonValue &value, QString *out) +{ + QTC_ASSERT(out, return false); + if (value.isString()) { + *out = value.toString(); + } else if (value.isArray()) { + QJsonArray array = value.toArray(); + QStringList lines; + foreach (const QJsonValue &v, array) { + if (!v.isString()) + return false; + lines.append(v.toString()); + } + *out = lines.join(QLatin1Char('\n')); + } else { + return false; + } + return true; +} + } // namespace Utils diff --git a/src/libs/utils/stringutils.h b/src/libs/utils/stringutils.h index 8ff42bac6a4..0723e76656f 100644 --- a/src/libs/utils/stringutils.h +++ b/src/libs/utils/stringutils.h @@ -28,6 +28,7 @@ #include "utils_global.h" QT_BEGIN_NAMESPACE +class QJsonValue; class QStringList; QT_END_NAMESPACE @@ -53,6 +54,8 @@ QTCREATOR_UTILS_EXPORT QString withTildeHomePath(const QString &path); // Removes first unescaped ampersand in text QTCREATOR_UTILS_EXPORT QString stripAccelerator(const QString &text); +QTCREATOR_UTILS_EXPORT bool readMultiLineString(const QJsonValue &value, QString *out); + class QTCREATOR_UTILS_EXPORT AbstractMacroExpander { public: diff --git a/src/libs/utils/utils-lib.pri b/src/libs/utils/utils-lib.pri index 3a6aa0a09af..578e0a8d5e4 100644 --- a/src/libs/utils/utils-lib.pri +++ b/src/libs/utils/utils-lib.pri @@ -113,7 +113,8 @@ SOURCES += $$PWD/environment.cpp \ $$PWD/port.cpp \ $$PWD/runextensions.cpp \ $$PWD/utilsicons.cpp \ - $$PWD/guard.cpp + $$PWD/guard.cpp \ + $$PWD/highlightingitemdelegate.cpp win32:SOURCES += $$PWD/consoleprocess_win.cpp else:SOURCES += $$PWD/consoleprocess_unix.cpp @@ -239,8 +240,9 @@ HEADERS += \ $$PWD/asconst.h \ $$PWD/smallstringfwd.h \ $$PWD/optional.h \ + $$PWD/../3rdparty/optional/optional.hpp \ $$PWD/qtcfallthrough.h \ - $$PWD/../3rdparty/optional/optional.hpp + $$PWD/highlightingitemdelegate.cpp FORMS += $$PWD/filewizardpage.ui \ $$PWD/projectintropage.ui \ diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index 6d68683fdd5..0c0562acaf7 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -117,6 +117,8 @@ Project { "functiontraits.h", "guard.cpp", "guard.h", + "highlightingitemdelegate.cpp", + "highlightingitemdelegate.h", "historycompleter.cpp", "historycompleter.h", "hostosinfo.h", |