diff options
Diffstat (limited to 'src/tools/uic/shared')
-rw-r--r-- | src/tools/uic/shared/language.cpp | 260 | ||||
-rw-r--r-- | src/tools/uic/shared/language.h | 47 | ||||
-rw-r--r-- | src/tools/uic/shared/writeincludesbase.cpp | 135 | ||||
-rw-r--r-- | src/tools/uic/shared/writeincludesbase.h | 74 |
4 files changed, 370 insertions, 146 deletions
diff --git a/src/tools/uic/shared/language.cpp b/src/tools/uic/shared/language.cpp index 48f5830760..d59688e346 100644 --- a/src/tools/uic/shared/language.cpp +++ b/src/tools/uic/shared/language.cpp @@ -1,37 +1,15 @@ -/**************************************************************************** -** -** Copyright (C) 2018 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** 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. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "language.h" #include <QtCore/qtextstream.h> +#include <QtCore/QList> namespace language { +using namespace Qt::StringLiterals; + static Encoding encoding = Encoding::Utf8; static Language _language = Language::Cpp; @@ -42,31 +20,37 @@ void setLanguage(Language l) _language = l; switch (_language) { case Language::Cpp: - derefPointer = QLatin1String("->"); - nullPtr = QLatin1String("nullptr"); - operatorNew = QLatin1String("new "); - qtQualifier = QLatin1String("Qt::"); - qualifier = QLatin1String("::"); - self = QLatin1String(""); // for testing: change to "this->"; - eol = QLatin1String(";\n"); - emptyString = QLatin1String("QString()"); + derefPointer = u"->"_s; + listStart = '{'; + listEnd = '}'; + nullPtr = u"nullptr"_s; + operatorNew = u"new "_s; + qtQualifier = u"Qt::"_s; + qualifier = u"::"_s; + self = u""_s; // for testing: change to "this->"; + eol = u";\n"_s; + emptyString = u"QString()"_s; encoding = Encoding::Utf8; break; case Language::Python: - derefPointer = QLatin1String("."); - nullPtr = QLatin1String("None"); - operatorNew = QLatin1String(""); - qtQualifier = QLatin1String("Qt."); - qualifier = QLatin1String("."); - self = QLatin1String("self."); - eol = QLatin1String("\n"); - emptyString = QLatin1String("\"\""); + derefPointer = u"."_s; + listStart = '['; + listEnd = ']'; + nullPtr = u"None"_s; + operatorNew = u""_s; + qtQualifier = u"Qt."_s; + qualifier = u"."_s; + self = u"self."_s; + eol = u"\n"_s; + emptyString = u"\"\""_s; encoding = Encoding::Unicode; break; } } QString derefPointer; +char listStart; +char listEnd; QString nullPtr; QString operatorNew; QString qtQualifier; @@ -75,9 +59,9 @@ QString self; QString eol; QString emptyString; -QString cppQualifier = QLatin1String("::"); -QString cppTrue = QLatin1String("true"); -QString cppFalse = QLatin1String("false"); +QString cppQualifier = u"::"_s; +QString cppTrue = u"true"_s; +QString cppFalse = u"false"_s; QTextStream &operator<<(QTextStream &str, const qtConfig &c) { @@ -100,97 +84,97 @@ QTextStream &operator<<(QTextStream &str, const closeQtConfig &c) struct EnumLookup { int value; - const char *valueString; + QLatin1StringView valueString; }; template <int N> -const char *lookupEnum(const EnumLookup(&array)[N], int value, int defaultIndex = 0) +QLatin1StringView lookupEnum(const EnumLookup(&array)[N], int value, int defaultIndex = 0) { for (int i = 0; i < N; ++i) { if (value == array[i].value) return array[i].valueString; } - const char *defaultValue = array[defaultIndex].valueString; + auto defaultValue = array[defaultIndex].valueString; qWarning("uic: Warning: Invalid enumeration value %d, defaulting to %s", - value, defaultValue); + value, defaultValue.data()); return defaultValue; } QString fixClassName(QString className) { if (language() == Language::Python) - className.replace(cppQualifier, QLatin1String("_")); + className.replace(cppQualifier, "_"_L1); return className; } -const char *toolbarArea(int v) +QLatin1StringView toolbarArea(int v) { static const EnumLookup toolBarAreas[] = { - {0, "NoToolBarArea"}, - {0x1, "LeftToolBarArea"}, - {0x2, "RightToolBarArea"}, - {0x4, "TopToolBarArea"}, - {0x8, "BottomToolBarArea"}, - {0xf, "AllToolBarAreas"} + {0, "NoToolBarArea"_L1}, + {0x1, "LeftToolBarArea"_L1}, + {0x2, "RightToolBarArea"_L1}, + {0x4, "TopToolBarArea"_L1}, + {0x8, "BottomToolBarArea"_L1}, + {0xf, "AllToolBarAreas"_L1} }; return lookupEnum(toolBarAreas, v); } -const char *sizePolicy(int v) +QLatin1StringView sizePolicy(int v) { static const EnumLookup sizePolicies[] = { - {0, "Fixed"}, - {0x1, "Minimum"}, - {0x4, "Maximum"}, - {0x5, "Preferred"}, - {0x3, "MinimumExpanding"}, - {0x7, "Expanding"}, - {0xD, "Ignored"} + {0, "Fixed"_L1}, + {0x1, "Minimum"_L1}, + {0x4, "Maximum"_L1}, + {0x5, "Preferred"_L1}, + {0x3, "MinimumExpanding"_L1}, + {0x7, "Expanding"_L1}, + {0xD, "Ignored"_L1} }; return lookupEnum(sizePolicies, v, 3); } -const char *dockWidgetArea(int v) +QLatin1StringView dockWidgetArea(int v) { static const EnumLookup dockWidgetAreas[] = { - {0, "NoDockWidgetArea"}, - {0x1, "LeftDockWidgetArea"}, - {0x2, "RightDockWidgetArea"}, - {0x4, "TopDockWidgetArea"}, - {0x8, "BottomDockWidgetArea"}, - {0xf, "AllDockWidgetAreas"} + {0, "NoDockWidgetArea"_L1}, + {0x1, "LeftDockWidgetArea"_L1}, + {0x2, "RightDockWidgetArea"_L1}, + {0x4, "TopDockWidgetArea"_L1}, + {0x8, "BottomDockWidgetArea"_L1}, + {0xf, "AllDockWidgetAreas"_L1} }; return lookupEnum(dockWidgetAreas, v); } -const char *paletteColorRole(int v) +QLatin1StringView paletteColorRole(int v) { static const EnumLookup colorRoles[] = { - {0, "WindowText"}, - {1, "Button"}, - {2, "Light"}, - {3, "Midlight"}, - {4, "Dark"}, - {5, "Mid"}, - {6, "Text"}, - {7, "BrightText"}, - {8, "ButtonText"}, - {9, "Base"}, - {10, "Window"}, - {11, "Shadow"}, - {12, "Highlight"}, - {13, "HighlightedText"}, - {14, "Link"}, - {15, "LinkVisited"}, - {16, "AlternateBase"}, - {17, "NoRole"}, - {18, "ToolTipBase"}, - {19, "ToolTipText"}, - {20, "PlaceholderText"}, + {0, "WindowText"_L1}, + {1, "Button"_L1}, + {2, "Light"_L1}, + {3, "Midlight"_L1}, + {4, "Dark"_L1}, + {5, "Mid"_L1}, + {6, "Text"_L1}, + {7, "BrightText"_L1}, + {8, "ButtonText"_L1}, + {9, "Base"_L1}, + {10, "Window"_L1}, + {11, "Shadow"_L1}, + {12, "Highlight"_L1}, + {13, "HighlightedText"_L1}, + {14, "Link"_L1}, + {15, "LinkVisited"_L1}, + {16, "AlternateBase"_L1}, + {17, "NoRole"_L1}, + {18, "ToolTipBase"_L1}, + {19, "ToolTipText"_L1}, + {20, "PlaceholderText"_L1}, }; return lookupEnum(colorRoles, v); } @@ -211,7 +195,7 @@ static int formatEscapedNumber(QTextStream &str, ushort value, int base, int wid const auto oldFieldWidth = str.fieldWidth(); const auto oldFieldAlignment = str.fieldAlignment(); const auto oldIntegerBase = str.integerBase(); - str.setPadChar(QLatin1Char('0')); + str.setPadChar(u'0'); str.setFieldWidth(width); str.setFieldAlignment(QTextStream::AlignRight); str.setIntegerBase(base); @@ -387,29 +371,65 @@ void _formatStackVariable(QTextStream &str, const char *className, QStringView v } } -enum OverloadUse { - UseOverload, - UseOverloadWhenNoArguments, // Use overload only when the argument list is empty, - // in this case there is no chance of connecting - // mismatching T against const T & - DontUseOverload +enum class OverloadUse { + Always, + WhenAmbiguousOrEmpty, // Use overload if + // - signal/slot is ambiguous + // - argument list is empty (chance of connecting mismatching T against const T &) + Never, }; // Format a member function for a signal slot connection -static void formatMemberFnPtr(QTextStream &str, const SignalSlot &s, - OverloadUse useQOverload = DontUseOverload) +static bool isConstRef(const QStringView &arg) { - const int parenPos = s.signature.indexOf(QLatin1Char('(')); + return arg.startsWith(u'Q') && arg != "QPoint"_L1 && arg != "QSize"_L1; +} + +static QString formatOverload(const QStringView ¶meters) +{ + QString result = "qOverload<"_L1; + const auto args = QStringView{parameters}.split(u','); + for (qsizetype i = 0, size = args.size(); i < size; ++i) { + const auto &arg = args.at(i); + if (i > 0) + result += u','; + const bool constRef = isConstRef(arg); + if (constRef) + result += "const "_L1; + result += arg; + if (constRef) + result += u'&'; + } + result += u'>'; + return result; +} + +static void formatMemberFnPtr(QTextStream &str, const SignalSlot &s, OverloadUse useQOverload) +{ + const qsizetype parenPos = s.signature.indexOf(u'('); Q_ASSERT(parenPos >= 0); const auto functionName = QStringView{s.signature}.left(parenPos); const auto parameters = QStringView{s.signature}.mid(parenPos + 1, s.signature.size() - parenPos - 2); - const bool withOverload = useQOverload == UseOverload || - (useQOverload == UseOverloadWhenNoArguments && parameters.isEmpty()); + + const bool isAmbiguous = s.options.testFlag(SignalSlotOption::Ambiguous); + bool withOverload = false; // just to silence the compiler + + switch (useQOverload) { + case OverloadUse::Always: + withOverload = true; + break; + case OverloadUse::Never: + withOverload = false; + break; + case OverloadUse::WhenAmbiguousOrEmpty: + withOverload = parameters.empty() || isAmbiguous; + break; + } if (withOverload) - str << "qOverload<" << parameters << ">("; + str << formatOverload(parameters) << '('; str << '&' << s.className << "::" << functionName; @@ -422,9 +442,9 @@ static void formatMemberFnPtrConnection(QTextStream &str, const SignalSlot &receiver) { str << "QObject::connect(" << sender.name << ", "; - formatMemberFnPtr(str, sender); + formatMemberFnPtr(str, sender, OverloadUse::Never); str << ", " << receiver.name << ", "; - formatMemberFnPtr(str, receiver, UseOverloadWhenNoArguments); + formatMemberFnPtr(str, receiver, OverloadUse::WhenAmbiguousOrEmpty); str << ')'; } @@ -450,12 +470,22 @@ void formatConnection(QTextStream &str, const SignalSlot &sender, const SignalSl break; } break; - case Language::Python: - str << sender.name << '.' - << QStringView{sender.signature}.left(sender.signature.indexOf(QLatin1Char('('))) - << ".connect(" << receiver.name << '.' - << QStringView{receiver.signature}.left(receiver.signature.indexOf(QLatin1Char('('))) + case Language::Python: { + const auto paren = sender.signature.indexOf(u'('); + auto senderSignature = QStringView{sender.signature}; + str << sender.name << '.' << senderSignature.left(paren); + // Signals like "QAbstractButton::clicked(checked=false)" require + // the parameter if it is used. + if (sender.options.testFlag(SignalSlotOption::Ambiguous)) { + const QStringView parameters = + senderSignature.mid(paren + 1, senderSignature.size() - paren - 2); + if (!parameters.isEmpty() && !parameters.contains(u',')) + str << "[\"" << parameters << "\"]"; + } + str << ".connect(" << receiver.name << '.' + << QStringView{receiver.signature}.left(receiver.signature.indexOf(u'(')) << ')'; + } break; } } diff --git a/src/tools/uic/shared/language.h b/src/tools/uic/shared/language.h index fcc2d5d258..de39122ee8 100644 --- a/src/tools/uic/shared/language.h +++ b/src/tools/uic/shared/language.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2018 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** 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. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef LANGUAGE_H #define LANGUAGE_H @@ -48,6 +23,8 @@ ConnectionSyntax connectionSyntax(); void setConnectionSyntax(ConnectionSyntax cs); extern QString derefPointer; +extern char listStart; +extern char listEnd; extern QString nullPtr; extern QString operatorNew; extern QString qtQualifier; @@ -98,10 +75,10 @@ QTextStream &operator<<(QTextStream &, const closeQtConfig &c); QString fixClassName(QString className); -const char *toolbarArea(int v); -const char *sizePolicy(int v); -const char *dockWidgetArea(int v); -const char *paletteColorRole(int v); +QLatin1StringView toolbarArea(int v); +QLatin1StringView sizePolicy(int v); +QLatin1StringView dockWidgetArea(int v); +QLatin1StringView paletteColorRole(int v); enum class Encoding { Utf8, Unicode }; @@ -196,11 +173,19 @@ inline QTextStream &operator<<(QTextStream &str, const _stackVariable<withInitPa using stackVariable = _stackVariable<false>; using stackVariableWithInitParameters = _stackVariable<true>; +enum class SignalSlotOption +{ + Ambiguous = 0x1 +}; + +Q_DECLARE_FLAGS(SignalSlotOptions, SignalSlotOption) + struct SignalSlot { QString name; QString signature; QString className; + SignalSlotOptions options; }; void formatConnection(QTextStream &str, const SignalSlot &sender, const SignalSlot &receiver, diff --git a/src/tools/uic/shared/writeincludesbase.cpp b/src/tools/uic/shared/writeincludesbase.cpp new file mode 100644 index 0000000000..78f69d5391 --- /dev/null +++ b/src/tools/uic/shared/writeincludesbase.cpp @@ -0,0 +1,135 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "writeincludesbase.h" +#include "ui4.h" +#include <uic.h> +#include <databaseinfo.h> + +QT_BEGIN_NAMESPACE + +static const ClassInfoEntry qclass_lib_map[] = { +#define QT_CLASS_LIB(klass, module, header) { #klass, #module, #header }, +#include "qclass_lib_map.h" +#undef QT_CLASS_LIB +}; + +ClassInfoEntries classInfoEntries() +{ + const ClassInfoEntry *classLibEnd = qclass_lib_map + sizeof(qclass_lib_map)/sizeof(ClassInfoEntry); + return {qclass_lib_map, classLibEnd}; +} + +// Base class for implementing a class that determines includes and equivalents +// in other languages by implementing doAdd(). It makes sure all dependent +// classes are known. +WriteIncludesBase::WriteIncludesBase(Uic *uic) : m_uic(uic) +{ +} + +void WriteIncludesBase::acceptUI(DomUI *node) +{ + m_knownClasses.clear(); + m_laidOut = false; + + if (node->elementIncludes()) + acceptIncludes(node->elementIncludes()); + + // Populate known custom widgets first + if (node->elementCustomWidgets()) + TreeWalker::acceptCustomWidgets(node->elementCustomWidgets()); + + add(QStringLiteral("QApplication")); + add(QStringLiteral("QVariant")); + + if (node->elementButtonGroups()) + add(QStringLiteral("QButtonGroup")); + + TreeWalker::acceptUI(node); +} + +void WriteIncludesBase::acceptWidget(DomWidget *node) +{ + add(node->attributeClass()); + TreeWalker::acceptWidget(node); +} + +void WriteIncludesBase::acceptLayout(DomLayout *node) +{ + add(node->attributeClass()); + m_laidOut = true; + TreeWalker::acceptLayout(node); +} + +void WriteIncludesBase::acceptSpacer(DomSpacer *node) +{ + add(QStringLiteral("QSpacerItem")); + TreeWalker::acceptSpacer(node); +} + +void WriteIncludesBase::acceptProperty(DomProperty *node) +{ + if (node->kind() == DomProperty::Date) + add(QStringLiteral("QDate")); + if (node->kind() == DomProperty::Locale) + add(QStringLiteral("QLocale")); + if (node->kind() == DomProperty::IconSet) + add(QStringLiteral("QIcon")); + TreeWalker::acceptProperty(node); +} + +void WriteIncludesBase::add(const QString &className, const DomCustomWidget *dcw) +{ + if (className.isEmpty() || m_knownClasses.contains(className)) + return; + + m_knownClasses.insert(className); + + const CustomWidgetsInfo *cwi = m_uic->customWidgetsInfo(); + static const QStringList treeViewsWithHeaders = { + QStringLiteral("QTreeView"), QStringLiteral("QTreeWidget"), + QStringLiteral("QTableView"), QStringLiteral("QTableWidget") + }; + if (cwi->extendsOneOf(className, treeViewsWithHeaders)) + add(QStringLiteral("QHeaderView")); + + if (!m_laidOut && cwi->extends(className, "QToolBox")) + add(QStringLiteral("QLayout")); // spacing property of QToolBox) + + if (className == QStringLiteral("Line")) { // ### hmm, deprecate me! + add(QStringLiteral("QFrame")); + return; + } + + if (cwi->extends(className, "QDialogButtonBox")) + add(QStringLiteral("QAbstractButton")); // for signal "clicked(QAbstractButton*)" + + doAdd(className, dcw); +} + +void WriteIncludesBase::acceptCustomWidget(DomCustomWidget *node) +{ + const QString className = node->elementClass(); + if (!className.isEmpty()) + add(className, node); +} + +void WriteIncludesBase::acceptActionGroup(DomActionGroup *node) +{ + add(QStringLiteral("QActionGroup")); + TreeWalker::acceptActionGroup(node); +} + +void WriteIncludesBase::acceptAction(DomAction *node) +{ + add(QStringLiteral("QAction")); + TreeWalker::acceptAction(node); +} + +void WriteIncludesBase::acceptActionRef(DomActionRef *node) +{ + add(QStringLiteral("QAction")); + TreeWalker::acceptActionRef(node); +} + +QT_END_NAMESPACE diff --git a/src/tools/uic/shared/writeincludesbase.h b/src/tools/uic/shared/writeincludesbase.h new file mode 100644 index 0000000000..71ddcc80d9 --- /dev/null +++ b/src/tools/uic/shared/writeincludesbase.h @@ -0,0 +1,74 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef WRITEINCLUDES_BASE_H +#define WRITEINCLUDES_BASE_H + +#include <treewalker.h> + +#include <QtCore/qset.h> +#include <QtCore/qstring.h> + +QT_BEGIN_NAMESPACE + +class DomCustomWidget; +class Uic; + +struct ClassInfoEntry +{ + const char *klass; + const char *module; + const char *header; +}; + +struct ClassInfoEntries +{ + const ClassInfoEntry *begin() const { return m_begin; } + const ClassInfoEntry *end() const { return m_end; } + + const ClassInfoEntry *m_begin; + const ClassInfoEntry *m_end; +}; + +ClassInfoEntries classInfoEntries(); + +class WriteIncludesBase : public TreeWalker +{ +public: + explicit WriteIncludesBase(Uic *uic); + + void acceptUI(DomUI *node) override; + void acceptWidget(DomWidget *node) override; + void acceptLayout(DomLayout *node) override; + void acceptSpacer(DomSpacer *node) override; + void acceptProperty(DomProperty *node) override; + + // + // actions + // + void acceptActionGroup(DomActionGroup *node) override; + void acceptAction(DomAction *node) override; + void acceptActionRef(DomActionRef *node) override; + + // + // custom widgets + // + void acceptCustomWidget(DomCustomWidget *node) override; + +protected: + void add(const QString &className, const DomCustomWidget *dcw = nullptr); + + virtual void doAdd(const QString &className, const DomCustomWidget *dcw = nullptr) = 0; + + const Uic *uic() const { return m_uic; } + Uic *uic() { return m_uic; } + +private: + QSet<QString> m_knownClasses; + Uic *m_uic; + bool m_laidOut = false; +}; + +QT_END_NAMESPACE + +#endif // WRITEINCLUDES_BASE_H |