diff options
Diffstat (limited to 'src/tools/uic')
-rw-r--r-- | src/tools/uic/CMakeLists.txt | 16 | ||||
-rw-r--r-- | src/tools/uic/cpp/cppwritedeclaration.cpp | 16 | ||||
-rw-r--r-- | src/tools/uic/cpp/cppwriteincludes.cpp | 4 | ||||
-rw-r--r-- | src/tools/uic/cpp/cppwriteinitialization.cpp | 402 | ||||
-rw-r--r-- | src/tools/uic/cpp/cppwriteinitialization.h | 5 | ||||
-rw-r--r-- | src/tools/uic/customwidgetsinfo.cpp | 88 | ||||
-rw-r--r-- | src/tools/uic/customwidgetsinfo.h | 5 | ||||
-rw-r--r-- | src/tools/uic/driver.cpp | 9 | ||||
-rw-r--r-- | src/tools/uic/main.cpp | 148 | ||||
-rw-r--r-- | src/tools/uic/option.h | 15 | ||||
-rw-r--r-- | src/tools/uic/python/pythonwriteimports.cpp | 74 | ||||
-rw-r--r-- | src/tools/uic/python/pythonwriteimports.h | 3 | ||||
-rw-r--r-- | src/tools/uic/qclass_lib_map.h | 1 | ||||
-rw-r--r-- | src/tools/uic/shared/language.cpp | 165 | ||||
-rw-r--r-- | src/tools/uic/shared/language.h | 8 | ||||
-rw-r--r-- | src/tools/uic/ui4.cpp | 39 | ||||
-rw-r--r-- | src/tools/uic/ui4.h | 16 | ||||
-rw-r--r-- | src/tools/uic/uic.cpp | 31 | ||||
-rw-r--r-- | src/tools/uic/utils.h | 2 |
19 files changed, 743 insertions, 304 deletions
diff --git a/src/tools/uic/CMakeLists.txt b/src/tools/uic/CMakeLists.txt index aab6ecfe28..9f47ec8b4b 100644 --- a/src/tools/uic/CMakeLists.txt +++ b/src/tools/uic/CMakeLists.txt @@ -1,4 +1,5 @@ -# Generated from uic.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## uic Tool: @@ -6,9 +7,10 @@ qt_get_tool_target_name(target_name uic) qt_internal_add_tool(${target_name} + TRY_RUN TARGET_DESCRIPTION "Qt User Interface Compiler" INSTALL_DIR "${INSTALL_LIBEXECDIR}" - TOOLS_TARGET Widgets # special case + TOOLS_TARGET Widgets SOURCES cpp/cppwritedeclaration.cpp cpp/cppwritedeclaration.h cpp/cppwriteincludes.cpp cpp/cppwriteincludes.h @@ -30,6 +32,7 @@ qt_internal_add_tool(${target_name} DEFINES QT_NO_CAST_FROM_ASCII QT_NO_FOREACH + QT_USE_NODISCARD_FILE_OPEN QT_UIC INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR} @@ -37,14 +40,5 @@ qt_internal_add_tool(${target_name} cpp python shared - #PUBLIC_LIBRARIES # special case remove - #Qt::Gui # special case remove ) qt_internal_return_unless_building_tools() - -#### Keys ignored in scope 1:.:.:uic.pro:<TRUE>: -# QMAKE_TARGET_DESCRIPTION = "Qt User Interface Compiler" -# _OPTION = "host_build" - -## Scopes: -##################################################################### diff --git a/src/tools/uic/cpp/cppwritedeclaration.cpp b/src/tools/uic/cpp/cppwritedeclaration.cpp index 2730ef9797..8261963cfa 100644 --- a/src/tools/uic/cpp/cppwritedeclaration.cpp +++ b/src/tools/uic/cpp/cppwritedeclaration.cpp @@ -55,7 +55,7 @@ void WriteDeclaration::acceptUI(DomUI *node) exportMacro.append(u' '); QStringList namespaceList = qualifiedClassName.split("::"_L1); - if (namespaceList.count()) { + if (namespaceList.size()) { className = namespaceList.last(); namespaceList.removeLast(); } @@ -65,15 +65,15 @@ void WriteDeclaration::acceptUI(DomUI *node) // is a User using Qt-in-namespace having his own classes not in a namespace. // In this case the generated Ui helper classes will also end up in // the Qt namespace (which is harmless, but not "pretty") - const bool needsMacro = namespaceList.count() == 0 - || namespaceList[0] == "qdesigner_internal"_L1; + const bool needsMacro = m_option.qtNamespace && + (namespaceList.size() == 0 || namespaceList[0] == "qdesigner_internal"_L1); if (needsMacro) m_output << "QT_BEGIN_NAMESPACE\n\n"; openNameSpaces(namespaceList, m_output); - if (namespaceList.count()) + if (namespaceList.size()) m_output << "\n"; m_output << "class " << exportMacro << m_option.prefix << className << "\n" @@ -98,7 +98,7 @@ void WriteDeclaration::acceptUI(DomUI *node) closeNameSpaces(namespaceList, m_output); - if (namespaceList.count()) + if (namespaceList.size()) m_output << "\n"; if (m_option.generateNamespace && !m_option.prefix.isEmpty()) { @@ -110,7 +110,7 @@ void WriteDeclaration::acceptUI(DomUI *node) closeNameSpaces(namespaceList, m_output); - if (namespaceList.count()) + if (namespaceList.size()) m_output << "\n"; } @@ -120,7 +120,7 @@ void WriteDeclaration::acceptUI(DomUI *node) void WriteDeclaration::acceptWidget(DomWidget *node) { - QString className = "QWidget"_L1; + QString className = u"QWidget"_s; if (node->hasAttributeClass()) className = node->attributeClass(); @@ -137,7 +137,7 @@ void WriteDeclaration::acceptSpacer(DomSpacer *node) void WriteDeclaration::acceptLayout(DomLayout *node) { - QString className = "QLayout"_L1; + QString className = u"QLayout"_s; if (node->hasAttributeClass()) className = node->attributeClass(); diff --git a/src/tools/uic/cpp/cppwriteincludes.cpp b/src/tools/uic/cpp/cppwriteincludes.cpp index 8a0b755f83..7cf7c4e59e 100644 --- a/src/tools/uic/cpp/cppwriteincludes.cpp +++ b/src/tools/uic/cpp/cppwriteincludes.cpp @@ -37,7 +37,7 @@ WriteIncludes::WriteIncludes(Uic *uic) : WriteIncludesBase(uic), // When possible (no namespace) use the "QtModule/QClass" convention // and create a re-mapping of the old header "qclass.h" to it. Do not do this // for the "Phonon::Someclass" classes, however. - const QString namespaceDelimiter = "::"_L1; + const QLatin1StringView namespaceDelimiter = "::"_L1; for (const auto &e : classInfoEntries()) { const QString klass = QLatin1StringView(e.klass); const QString module = QLatin1StringView(e.module); @@ -90,7 +90,7 @@ void WriteIncludes::insertIncludeForClass(const QString &className, QString head // Quick check by class name to detect includehints provided for custom widgets. // Remove namespaces QString lowerClassName = className.toLower(); - static const QString namespaceSeparator = "::"_L1; + static const auto namespaceSeparator = "::"_L1; const int namespaceIndex = lowerClassName.lastIndexOf(namespaceSeparator); if (namespaceIndex != -1) lowerClassName.remove(0, namespaceIndex + namespaceSeparator.size()); diff --git a/src/tools/uic/cpp/cppwriteinitialization.cpp b/src/tools/uic/cpp/cppwriteinitialization.cpp index 4d43e904e1..14ec778d65 100644 --- a/src/tools/uic/cpp/cppwriteinitialization.cpp +++ b/src/tools/uic/cpp/cppwriteinitialization.cpp @@ -24,6 +24,34 @@ QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; namespace { + + // Expand "Horizontal", "Qt::Horizontal" to "Qt::Orientation::Horizontal" + QString expandEnum(QString value, const QString &prefix) + { + if (value.startsWith(prefix)) + return value; + const auto pos = value.lastIndexOf("::"_L1); + if (pos == -1) + return prefix + "::"_L1 + value; + value.replace(0, pos, prefix); + return value; + } + + inline QString expandSizePolicyEnum(const QString &value) + { + return expandEnum(value, "QSizePolicy::Policy"_L1); + } + + inline QString expandToolBarArea(const QString &value) + { + return expandEnum(value, "Qt::ToolBarArea"_L1); + } + + inline QString expandDockWidgetArea(const QString &value) + { + return expandEnum(value, "Qt::DockWidgetArea"_L1); + } + // figure out the toolbar area of a DOM attrib list. // By legacy, it is stored as an integer. As of 4.3.0, it is the enumeration value. QString toolBarAreaStringFromDOMAttributes(const CPP::WriteInitialization::DomPropertyMap &attributes) { @@ -33,7 +61,7 @@ namespace { return result; switch (pstyle->kind()) { case DomProperty::Number: - result = QLatin1StringView(language::toolbarArea(pstyle->elementNumber())); + result = language::toolbarArea(pstyle->elementNumber()); break; case DomProperty::Enum: result = pstyle->elementEnum(); @@ -41,9 +69,7 @@ namespace { default: break; } - if (!result.startsWith("Qt::"_L1)) - result.prepend("Qt::"_L1); - return result + ", "_L1; + return expandToolBarArea(result) + ", "_L1; } // Write a statement to create a spacer item. @@ -62,27 +88,17 @@ namespace { output << w << ", " << h << ", "; // size type - QString sizeType; - if (const DomProperty *st = properties.value("sizeType"_L1)) { - const QString value = st->elementEnum(); - if (value.startsWith("QSizePolicy::"_L1)) - sizeType = value; - else - sizeType = "QSizePolicy::"_L1 + value; - } else { - sizeType = QStringLiteral("QSizePolicy::Expanding"); - } + const DomProperty *st = properties.value("sizeType"_L1); + QString horizType = st != nullptr ? st->elementEnum() : "Expanding"_L1; + QString vertType = "Minimum"_L1; // orientation - bool isVspacer = false; - if (const DomProperty *o = properties.value("orientation"_L1)) { - const QString orientation = o->elementEnum(); - if (orientation == "Qt::Vertical"_L1 || orientation == "Vertical"_L1) - isVspacer = true; - } - const QString horizType = isVspacer ? "QSizePolicy::Minimum"_L1 : sizeType; - const QString vertType = isVspacer ? sizeType : "QSizePolicy::Minimum"_L1; - output << language::enumValue(horizType) << ", " << language::enumValue(vertType) << ')'; + const DomProperty *o = properties.value("orientation"_L1); + if (o != nullptr && o->elementEnum().endsWith("Vertical"_L1)) + std::swap(horizType, vertType); + + output << language::enumValue(expandSizePolicyEnum(horizType)) << ", " + << language::enumValue(expandSizePolicyEnum(vertType)) << ')'; } @@ -111,16 +127,63 @@ namespace { return iconHasStatePixmaps(i) || !i->attributeTheme().isEmpty(); } + // Checks on property names + bool isIdentifier(QChar c) { return c.isLetterOrNumber() || c == u'_'; } + + bool checkPropertyName(const QString &name) + { + return !name.isEmpty() && name.at(0).isLetter() + && std::all_of(name.cbegin(), name.cend(), isIdentifier); + } + + // Basic checks on enum/flag values + static bool isValidEnumValue(QChar c) + { + if (c.isLetterOrNumber()) + return true; + switch (c.unicode()) { + case '|': + case ' ': + case ':': + case '_': + return true; + default: + break; + } + return false; + } + + bool checkEnumValue(const QString &value) + { + return std::all_of(value.cbegin(), value.cend(), isValidEnumValue); + } + + QString msgInvalidValue(const QString &name, const QString &value) + { + return "uic: Invalid property value: \""_L1 + name + "\": \""_L1 + value + u'"'; + } + // Check on properties. Filter out empty legacy pixmap/icon properties // as Designer pre 4.4 used to remove missing resource references. // This can no longer be handled by the code as we have 'setIcon(QIcon())' as well as 'QIcon icon' static bool checkProperty(const CustomWidgetsInfo *customWidgetsInfo, const QString &fileName, const QString &className, const DomProperty *p) { + + const QString &name = p->attributeName(); + if (!checkPropertyName(name)) { + qWarning("uic: Invalid property name: \"%s\".", qPrintable(name)); + return false; + } + switch (p->kind()) { // ### fixme Qt 7 remove this: Exclude deprecated properties of Qt 5. case DomProperty::Set: - if (p->attributeName() == u"features" + if (!checkEnumValue(p->elementSet())) { + qWarning("%s", qPrintable(msgInvalidValue(name, p->elementSet()))); + return false; + } + if (name == u"features" && customWidgetsInfo->extends(className, "QDockWidget") && p->elementSet() == u"QDockWidget::AllDockWidgetFeatures") { const QString msg = fileName + ": Warning: Deprecated enum value QDockWidget::AllDockWidgetFeatures was encountered."_L1; @@ -129,7 +192,11 @@ namespace { } break; case DomProperty::Enum: - if (p->attributeName() == u"sizeAdjustPolicy" + if (!checkEnumValue(p->elementEnum())) { + qWarning("%s", qPrintable(msgInvalidValue(name, p->elementEnum()))); + return false; + } + if (name == u"sizeAdjustPolicy" && customWidgetsInfo->extends(className, "QComboBox") && p->elementEnum() == u"QComboBox::AdjustToMinimumContentsLength") { const QString msg = fileName + ": Warning: Deprecated enum value QComboBox::AdjustToMinimumContentsLength was encountered."_L1; @@ -142,7 +209,7 @@ namespace { if (!isIconFormat44(dri)) { if (dri->text().isEmpty()) { const QString msg = QString::fromLatin1("%1: Warning: An invalid icon property '%2' was encountered.") - .arg(fileName, p->attributeName()); + .arg(fileName, name); qWarning("%s", qPrintable(msg)); return false; } @@ -153,7 +220,7 @@ namespace { if (const DomResourcePixmap *drp = p->elementPixmap()) if (drp->text().isEmpty()) { const QString msg = QString::fromUtf8("%1: Warning: An invalid pixmap property '%2' was encountered.") - .arg(fileName, p->attributeName()); + .arg(fileName, name); qWarning("%s", qPrintable(msg)); return false; } @@ -180,6 +247,15 @@ FontHandle::FontHandle(const DomFont *domFont) : { } +static QString fontWeight(const DomFont *domFont) +{ + if (domFont->hasElementFontWeight()) + return domFont->elementFontWeight(); + if (domFont->hasElementBold()) + return domFont->elementBold() ? u"Bold"_s : u"Normal"_s; + return {}; +} + int FontHandle::compare(const FontHandle &rhs) const { const QString family = m_domFont->hasElementFamily() ? m_domFont->elementFamily() : QString(); @@ -194,10 +270,10 @@ int FontHandle::compare(const FontHandle &rhs) const if (const int crc = compareInt(pointSize, rhsPointSize)) return crc; - const int bold = m_domFont->hasElementBold() ? (m_domFont->elementBold() ? 1 : 0) : -1; - const int rhsBold = rhs.m_domFont->hasElementBold() ? (rhs.m_domFont->elementBold() ? 1 : 0) : -1; - if (const int crc = compareInt(bold, rhsBold)) - return crc; + const QString fontWeight = CPP::fontWeight(m_domFont); + const QString rhsFontWeight = CPP::fontWeight(rhs.m_domFont); + if (const int wrc = fontWeight.compare(rhsFontWeight)) + return wrc; const int italic = m_domFont->hasElementItalic() ? (m_domFont->elementItalic() ? 1 : 0) : -1; const int rhsItalic = rhs.m_domFont->hasElementItalic() ? (rhs.m_domFont->elementItalic() ? 1 : 0) : -1; @@ -209,11 +285,6 @@ int FontHandle::compare(const FontHandle &rhs) const if (const int crc = compareInt(underline, rhsUnderline)) return crc; - const int weight = m_domFont->hasElementWeight() ? m_domFont->elementWeight() : -1; - const int rhsWeight = rhs.m_domFont->hasElementWeight() ? rhs.m_domFont->elementWeight() : -1; - if (const int crc = compareInt(weight, rhsWeight)) - return crc; - const int strikeOut = m_domFont->hasElementStrikeOut() ? (m_domFont->elementStrikeOut() ? 1 : 0) : -1; const int rhsStrikeOut = rhs.m_domFont->hasElementStrikeOut() ? (rhs.m_domFont->elementStrikeOut() ? 1 : 0) : -1; if (const int crc = compareInt(strikeOut, rhsStrikeOut)) @@ -235,6 +306,13 @@ int FontHandle::compare(const FontHandle &rhs) const if (const int src = styleStrategy.compare(rhsStyleStrategy)) return src; + const QString hintingPreference = m_domFont->hasElementHintingPreference() + ? m_domFont->elementHintingPreference() : QString(); + const QString rhsHintingPreference = rhs.m_domFont->hasElementHintingPreference() + ? rhs.m_domFont->elementHintingPreference() : QString(); + if (const int src = hintingPreference.compare(rhsHintingPreference)) + return src; + return 0; } @@ -513,7 +591,7 @@ void WriteInitialization::acceptUI(DomUI *node) if (!m_buddies.empty()) m_output << language::openQtConfig(shortcutConfigKey()); - for (const Buddy &b : qAsConst(m_buddies)) { + for (const Buddy &b : std::as_const(m_buddies)) { const QString buddyVarName = m_driver->widgetVariableName(b.buddyAttributeName); if (buddyVarName.isEmpty()) { fprintf(stderr, "%s: Warning: Buddy assignment: '%s' is not a valid widget.\n", @@ -601,7 +679,7 @@ void WriteInitialization::addWizardPage(const QString &pageVarName, const DomWid void WriteInitialization::acceptWidget(DomWidget *node) { - m_layoutMarginType = m_widgetChain.count() == 1 ? TopLevelMargin : ChildMargin; + m_layoutMarginType = m_widgetChain.size() == 1 ? TopLevelMargin : ChildMargin; const QString className = node->attributeClass(); const QString varName = m_driver->findOrInsertWidget(node); @@ -669,7 +747,7 @@ void WriteInitialization::acceptWidget(DomWidget *node) const DomPropertyMap attributes = propertyMap(node->elementAttribute()); - const QString pageDefaultString = "Page"_L1; + const QString pageDefaultString = u"Page"_s; if (cwi->extends(parentClass, "QMainWindow")) { if (cwi->extends(className, "QMenuBar")) { @@ -690,8 +768,8 @@ void WriteInitialization::acceptWidget(DomWidget *node) } else if (cwi->extends(className, "QDockWidget")) { m_output << m_indent << parentWidget << language::derefPointer << "addDockWidget("; if (DomProperty *pstyle = attributes.value("dockWidgetArea"_L1)) { - m_output << "Qt" << language::qualifier - << language::dockWidgetArea(pstyle->elementNumber()) << ", "; + QString a = expandDockWidgetArea(language::dockWidgetArea(pstyle->elementNumber())); + m_output << language::enumValue(a) << ", "; } m_output << varName << ")" << language::eol; } else if (m_uic->customWidgetsInfo()->extends(className, "QStatusBar")) { @@ -781,10 +859,10 @@ void WriteInitialization::acceptWidget(DomWidget *node) }; static const QStringList trees = { - "QTreeView"_L1, "QTreeWidget"_L1 + u"QTreeView"_s, u"QTreeWidget"_s }; static const QStringList tables = { - "QTableView"_L1, "QTableWidget"_L1 + u"QTableView"_s, u"QTableWidget"_s }; if (cwi->extendsOneOf(className, trees)) { @@ -864,7 +942,7 @@ void WriteInitialization::addButtonGroup(const DomWidget *buttonNode, const QStr const QString groupName = m_driver->findOrInsertButtonGroup(group); // Create on demand if (!m_buttonGroups.contains(groupName)) { - const QString className = "QButtonGroup"_L1; + const QString className = u"QButtonGroup"_s; m_output << m_indent; if (createGroupOnTheFly) m_output << className << " *"; @@ -977,7 +1055,7 @@ void WriteInitialization::writePropertyList(const QString &varName, if (value.isEmpty()) return; const QStringList list = value.split(u','); - const int count = list.count(); + const int count = list.size(); for (int i = 0; i < count; i++) { if (list.at(i) != defaultValue) { m_output << m_indent << varName << language::derefPointer << setFunction @@ -1002,7 +1080,7 @@ static inline QString formLayoutRole(int column, int colspan) static QString layoutAddMethod(DomLayoutItem::Kind kind, const QString &layoutClass) { - const QString methodPrefix = layoutClass == "QFormLayout"_L1 ? "set"_L1 : "add"_L1; + const auto methodPrefix = layoutClass == "QFormLayout"_L1 ? "set"_L1 : "add"_L1; switch (kind) { case DomLayoutItem::Widget: return methodPrefix + "Widget"_L1; @@ -1128,18 +1206,35 @@ QString WriteInitialization::writeStringListProperty(const DomStringList *list) { QString propertyValue; QTextStream str(&propertyValue); - str << "QStringList()"; + char trailingDelimiter = '}'; + switch (language::language()) { + case Language::Cpp: + str << "QStringList{"; + break; + case Language::Python: + str << '['; + trailingDelimiter = ']'; + break; + } const QStringList values = list->elementString(); - if (values.isEmpty()) - return propertyValue; - if (needsTranslation(list)) { - const QString comment = list->attributeComment(); - for (int i = 0; i < values.size(); ++i) - str << '\n' << m_indent << " << " << trCall(values.at(i), comment); - } else { - for (int i = 0; i < values.size(); ++i) - str << " << " << language::qstring(values.at(i), m_dindent); + if (!values.isEmpty()) { + if (needsTranslation(list)) { + const QString comment = list->attributeComment(); + const qsizetype last = values.size() - 1; + for (qsizetype i = 0; i <= last; ++i) { + str << '\n' << m_indent << " " << trCall(values.at(i), comment); + if (i != last) + str << ','; + } + } else { + for (qsizetype i = 0; i < values.size(); ++i) { + if (i) + str << ", "; + str << language::qstring(values.at(i), m_dindent); + } + } } + str << trailingDelimiter; return propertyValue; } @@ -1163,7 +1258,7 @@ void WriteInitialization::writeProperties(const QString &varName, const DomPropertyList &lst, unsigned flags) { - const bool isTopLevel = m_widgetChain.count() == 1; + const bool isTopLevel = m_widgetChain.size() == 1; if (m_uic->customWidgetsInfo()->extends(className, "QAxWidget")) { DomPropertyMap properties = propertyMap(lst); @@ -1220,8 +1315,8 @@ void WriteInitialization::writeProperties(const QString &varName, continue; } static const QStringList currentIndexWidgets = { - "QComboBox"_L1, "QStackedWidget"_L1, - "QTabWidget"_L1, "QToolBox"_L1 + u"QComboBox"_s, u"QStackedWidget"_s, + u"QTabWidget"_s, u"QToolBox"_s }; if (propertyName == "currentIndex"_L1 // set currentIndex later && (m_uic->customWidgetsInfo()->extendsOneOf(className, currentIndexWidgets))) { @@ -1256,9 +1351,9 @@ void WriteInitialization::writeProperties(const QString &varName, } else if (propertyName == "orientation"_L1 && m_uic->customWidgetsInfo()->extends(className, "Line")) { // Line support - QString shape = "QFrame::HLine"_L1; - if (p->elementEnum() == "Qt::Vertical"_L1) - shape = "QFrame::VLine"_L1; + QString shape = u"QFrame::Shape::HLine"_s; + if (p->elementEnum().endsWith("::Vertical"_L1)) + shape = u"QFrame::Shape::VLine"_s; m_output << m_indent << varName << language::derefPointer << "setFrameShape(" << language::enumValue(shape) << ')' << language::eol; @@ -1266,7 +1361,7 @@ void WriteInitialization::writeProperties(const QString &varName, if (!frameShadowEncountered) { m_output << m_indent << varName << language::derefPointer << "setFrameShadow(" - << language::enumValue("QFrame::Sunken"_L1) + << language::enumValue("QFrame::Shadow::Sunken"_L1) << ')' << language::eol; } continue; @@ -1333,11 +1428,12 @@ void WriteInitialization::writeProperties(const QString &varName, Buddy buddy = { varName, p->elementCstring() }; m_buddies.append(std::move(buddy)); } else { + const bool useQByteArray = !stdset && language::language() == Language::Cpp; QTextStream str(&propertyValue); - if (!stdset) + if (useQByteArray) str << "QByteArray("; str << language::charliteral(p->elementCstring(), m_dindent); - if (!stdset) + if (useQByteArray) str << ')'; } break; @@ -1348,8 +1444,8 @@ void WriteInitialization::writeProperties(const QString &varName, case DomProperty::CursorShape: if (p->hasAttributeStdset() && !p->attributeStdset()) varNewName += language::derefPointer + "viewport()"_L1; - propertyValue = "QCursor(Qt"_L1 + language::qualifier - + p->elementCursorShape() + u')'; + propertyValue = "QCursor(Qt"_L1 + language::qualifier + "CursorShape"_L1 + + language::qualifier + p->elementCursorShape() + u')'; break; case DomProperty::Enum: propertyValue = p->elementEnum(); @@ -1565,12 +1661,18 @@ QString WriteInitialization::writeSizePolicy(const DomSizePolicy *sp) m_sizePolicyNameMap.insert(sizePolicyHandle, spName); m_output << m_indent << language::stackVariableWithInitParameters("QSizePolicy", spName); + QString horizPolicy; + QString vertPolicy; if (sp->hasElementHSizeType() && sp->hasElementVSizeType()) { - m_output << "QSizePolicy" << language::qualifier << language::sizePolicy(sp->elementHSizeType()) - << ", QSizePolicy" << language::qualifier << language::sizePolicy(sp->elementVSizeType()); + horizPolicy = language::sizePolicy(sp->elementHSizeType()); + vertPolicy = language::sizePolicy(sp->elementVSizeType()); } else if (sp->hasAttributeHSizeType() && sp->hasAttributeVSizeType()) { - m_output << "QSizePolicy" << language::qualifier << sp->attributeHSizeType() - << ", QSizePolicy" << language::qualifier << sp->attributeVSizeType(); + horizPolicy = sp->attributeHSizeType(); + vertPolicy = sp->attributeVSizeType(); + } + if (!horizPolicy.isEmpty() && !vertPolicy.isEmpty()) { + m_output << language::enumValue(expandSizePolicyEnum(horizPolicy)) + << ", " << language::enumValue(expandSizePolicyEnum(vertPolicy)); } m_output << ')' << language::eol; @@ -1609,10 +1711,14 @@ QString WriteInitialization::writeFontProperties(const DomFont *f) << ")" << language::eol; } - if (f->hasElementBold()) { + if (f->hasElementFontWeight()) { + m_output << m_indent << fontName << ".setWeight(QFont" + << language::qualifier << f->elementFontWeight() << ')' << language::eol; + } else if (f->hasElementBold()) { m_output << m_indent << fontName << ".setBold(" << language::boolValue(f->elementBold()) << ')' << language::eol; } + if (f->hasElementItalic()) { m_output << m_indent << fontName << ".setItalic(" << language::boolValue(f->elementItalic()) << ')' << language::eol; @@ -1639,6 +1745,11 @@ QString WriteInitialization::writeFontProperties(const DomFont *f) m_output << m_indent << fontName << ".setStyleStrategy(QFont" << language::qualifier << f->elementStyleStrategy() << ')' << language::eol; } + if (f->hasElementHintingPreference()) { + m_output << m_indent << fontName << ".setHintingPreference(QFont" + << language::qualifier << f->elementHintingPreference() << ')' << language::eol; + } + return fontName; } @@ -1648,8 +1759,9 @@ static void writeIconAddFile(QTextStream &output, const QString &indent, { output << indent << iconName << ".addFile(" << language::qstring(fileName, indent) << ", QSize(), QIcon" - << language::qualifier << mode << ", QIcon" << language::qualifier - << state << ')' << language::eol; + << language::qualifier << "Mode" << language::qualifier << mode + << ", QIcon" << language::qualifier << "State" << language::qualifier << state + << ')' << language::eol; } // Post 4.4 write resource icon @@ -1697,7 +1809,8 @@ static void writeIconAddPixmap(QTextStream &output, const QString &indent, const char *mode, const char *state) { output << indent << iconName << ".addPixmap(" << call << ", QIcon" - << language::qualifier << mode << ", QIcon" << language::qualifier + << language::qualifier << "Mode" << language::qualifier << mode + << ", QIcon" << language::qualifier << "State" << language::qualifier << state << ')' << language::eol; } @@ -1748,6 +1861,59 @@ void WriteInitialization::writePixmapFunctionIcon(QTextStream &output, } } +// Write QIcon::fromTheme() (value from enum or variable) +struct iconFromTheme +{ + explicit iconFromTheme(const QString &theme) : m_theme(theme) {} + + QString m_theme; +}; + +QTextStream &operator<<(QTextStream &str, const iconFromTheme &i) +{ + str << "QIcon" << language::qualifier << "fromTheme(" << i.m_theme << ')'; + return str; +} + +// Write QIcon::fromTheme() for an XDG icon from string literal +struct iconFromThemeStringLiteral +{ + explicit iconFromThemeStringLiteral(const QString &theme) : m_theme(theme) {} + + QString m_theme; +}; + +QTextStream &operator<<(QTextStream &str, const iconFromThemeStringLiteral &i) +{ + str << "QIcon" << language::qualifier << "fromTheme(" << language::qstring(i.m_theme) << ')'; + return str; +} + +// Write QIcon::fromTheme() with a path as fallback, add a check using +// QIcon::hasThemeIcon(). +void WriteInitialization::writeThemeIconCheckAssignment(const QString &themeValue, + const QString &iconName, + const DomResourceIcon *i) + +{ + const bool isCpp = language::language() == Language::Cpp; + m_output << m_indent << "if "; + if (isCpp) + m_output << '('; + m_output << "QIcon" << language::qualifier << "hasThemeIcon(" + << themeValue << ')' << (isCpp ? ") {" : ":") << '\n' + << m_dindent << iconName << " = " << iconFromTheme(themeValue) + << language::eol; + m_output << m_indent << (isCpp ? "} else {" : "else:") << '\n'; + if (m_uic->pixmapFunction().isEmpty()) + writeResourceIcon(m_output, iconName, m_dindent, i); + else + writePixmapFunctionIcon(m_output, iconName, m_dindent, i); + if (isCpp) + m_output << m_indent << '}'; + m_output << '\n'; +} + QString WriteInitialization::writeIconProperties(const DomResourceIcon *i) { // check cache @@ -1772,7 +1938,8 @@ QString WriteInitialization::writeIconProperties(const DomResourceIcon *i) } // 4.4 onwards - if (i->attributeTheme().isEmpty()) { + QString theme = i->attributeTheme(); + if (theme.isEmpty()) { // No theme: Write resource icon as is m_output << m_indent << language::stackVariable("QIcon", iconName) << language::eol; @@ -1783,12 +1950,21 @@ QString WriteInitialization::writeIconProperties(const DomResourceIcon *i) return iconName; } + const bool isThemeEnum = theme.startsWith("QIcon::"_L1); + if (isThemeEnum) + theme = language::enumValue(theme); + // Theme: Generate code to check the theme and default to resource if (iconHasStatePixmaps(i)) { // Theme + default state pixmaps: // Generate code to check the theme and default to state pixmaps m_output << m_indent << language::stackVariable("QIcon", iconName) << language::eol; - const char themeNameStringVariableC[] = "iconThemeName"; + if (isThemeEnum) { + writeThemeIconCheckAssignment(theme, iconName, i); + return iconName; + } + + static constexpr auto themeNameStringVariableC = "iconThemeName"_L1; // Store theme name in a variable m_output << m_indent; if (m_firstThemeIcon) { // Declare variable string @@ -1797,32 +1973,19 @@ QString WriteInitialization::writeIconProperties(const DomResourceIcon *i) m_firstThemeIcon = false; } m_output << themeNameStringVariableC << " = " - << language::qstring(i->attributeTheme()) << language::eol; - m_output << m_indent << "if "; - if (isCpp) - m_output << '('; - m_output << "QIcon" << language::qualifier << "hasThemeIcon(" - << themeNameStringVariableC << ')' << (isCpp ? ") {" : ":") << '\n' - << m_dindent << iconName << " = QIcon" << language::qualifier << "fromTheme(" - << themeNameStringVariableC << ')' << language::eol - << m_indent << (isCpp ? "} else {" : "else:") << '\n'; - if (m_uic->pixmapFunction().isEmpty()) - writeResourceIcon(m_output, iconName, m_dindent, i); - else - writePixmapFunctionIcon(m_output, iconName, m_dindent, i); - m_output << m_indent; - if (isCpp) - m_output << '}'; - m_output << '\n'; + << language::qstring(theme) << language::eol; + writeThemeIconCheckAssignment(themeNameStringVariableC, iconName, i); return iconName; } // Theme, but no state pixmaps: Construct from theme directly. m_output << m_indent - << language::stackVariableWithInitParameters("QIcon", iconName) - << "QIcon" << language::qualifier << "fromTheme(" - << language::qstring(i->attributeTheme()) << "))" - << language::eol; + << language::stackVariableWithInitParameters("QIcon", iconName); + if (isThemeEnum) + m_output << iconFromTheme(theme); + else + m_output << iconFromThemeStringLiteral(theme); + m_output << ')' << language::eol; return iconName; } @@ -1913,7 +2076,7 @@ QString WriteInitialization::writeBrushInitialization(const DomBrush *brush) void WriteInitialization::writeBrush(const DomBrush *brush, const QString &brushName) { - QString style = "SolidPattern"_L1; + QString style = u"SolidPattern"_s; if (brush->hasAttributeBrushStyle()) style = brush->attributeBrushStyle(); @@ -2031,7 +2194,8 @@ QString WriteInitialization::iconCall(const DomProperty *icon) QString WriteInitialization::pixCall(const DomProperty *p) const { - QString type, s; + QLatin1StringView type; + QString s; switch (p->kind()) { case DomProperty::IconSet: type = "QIcon"_L1; @@ -2042,7 +2206,7 @@ QString WriteInitialization::pixCall(const DomProperty *p) const s = p->elementPixmap()->text(); break; default: - qWarning("%s: Warning: Unknown icon format encountered. The ui-file was generated with a too-recent version of Designer.", + qWarning("%s: Warning: Unknown icon format encountered. The ui-file was generated with a too-recent version of Qt Widgets Designer.", qPrintable(m_option.messagePrefix())); return "QIcon()"_L1; break; @@ -2050,23 +2214,22 @@ QString WriteInitialization::pixCall(const DomProperty *p) const return pixCall(type, s); } -QString WriteInitialization::pixCall(const QString &t, const QString &text) const +QString WriteInitialization::pixCall(QLatin1StringView t, const QString &text) const { - QString type = t; - if (text.isEmpty()) { - type += "()"_L1; - return type; - } + if (text.isEmpty()) + return t % "()"_L1; - QTextStream str(&type); + QString result; + QTextStream str(&result); + str << t; str << '('; - QString pixFunc = m_uic->pixmapFunction(); + const QString pixFunc = m_uic->pixmapFunction(); if (pixFunc.isEmpty()) str << language::qstring(text, m_dindent); else str << pixFunc << '(' << language::charliteral(text, m_dindent) << ')'; str << ')'; - return type; + return result; } void WriteInitialization::initializeComboBox(DomWidget *w) @@ -2312,7 +2475,7 @@ void WriteInitialization::initializeTreeWidget(DomWidget *w) QString tempName = disableSorting(w, varName); const auto items = initializeTreeWidgetItems(w->elementItem()); - for (int i = 0; i < items.count(); i++) { + for (int i = 0; i < items.size(); i++) { Item *itm = items[i]; itm->writeSetupUi(varName); QString parentPath; @@ -2615,14 +2778,21 @@ void WriteInitialization::acceptConnection(DomConnection *connection) return; } const QString senderSignature = connection->elementSignal(); + const QString slotSignature = connection->elementSlot(); + const bool senderAmbiguous = m_uic->customWidgetsInfo()->isAmbiguousSignal(senderDecl.className, + senderSignature); + const bool slotAmbiguous = m_uic->customWidgetsInfo()->isAmbiguousSlot(receiverDecl.className, + slotSignature); + language::SignalSlotOptions signalOptions; - if (m_uic->customWidgetsInfo()->isAmbiguousSignal(senderDecl.className, senderSignature)) - signalOptions.setFlag(language::SignalSlotOption::Ambiguous); + signalOptions.setFlag(language::SignalSlotOption::Ambiguous, senderAmbiguous); + language::SignalSlotOptions slotOptions; + slotOptions.setFlag(language::SignalSlotOption::Ambiguous, slotAmbiguous); language::SignalSlot theSignal{senderDecl.name, senderSignature, senderDecl.className, signalOptions}; - language::SignalSlot theSlot{receiverDecl.name, connection->elementSlot(), - receiverDecl.className, {}}; + language::SignalSlot theSlot{receiverDecl.name, slotSignature, + receiverDecl.className, slotOptions}; m_output << m_indent; language::formatConnection(m_output, theSignal, theSlot, @@ -2717,7 +2887,7 @@ QString WriteInitialization::Item::writeSetupUi(const QString &parent, Item::Emp m_setupUiStream << language::closeQtConfig(it.key()); ++it; } - for (Item *child : qAsConst(m_children)) + for (Item *child : std::as_const(m_children)) child->writeSetupUi(uniqueName); return uniqueName; } diff --git a/src/tools/uic/cpp/cppwriteinitialization.h b/src/tools/uic/cpp/cppwriteinitialization.h index c066c6fbae..0973def52d 100644 --- a/src/tools/uic/cpp/cppwriteinitialization.h +++ b/src/tools/uic/cpp/cppwriteinitialization.h @@ -5,7 +5,6 @@ #define CPPWRITEINITIALIZATION_H #include "treewalker.h" -#include <qpair.h> #include <qhash.h> #include <qset.h> #include <qmap.h> @@ -119,7 +118,7 @@ private: QString iconCall(const DomProperty *prop); QString pixCall(const DomProperty *prop) const; - QString pixCall(const QString &type, const QString &text) const; + QString pixCall(QLatin1StringView type, const QString &text) const; QString trCall(const QString &str, const QString &comment = QString(), const QString &id = QString()) const; QString trCall(DomString *str, const QString &defaultString = QString()) const; QString noTrCall(DomString *str, const QString &defaultString = QString()) const; @@ -210,6 +209,8 @@ private: private: QString writeFontProperties(const DomFont *f); QString writeIconProperties(const DomResourceIcon *i); + void writeThemeIconCheckAssignment(const QString &themeValue, const QString &iconName, + const DomResourceIcon *i); void writePixmapFunctionIcon(QTextStream &output, const QString &iconName, const QString &indent, const DomResourceIcon *i) const; QString writeSizePolicy(const DomSizePolicy *sp); diff --git a/src/tools/uic/customwidgetsinfo.cpp b/src/tools/uic/customwidgetsinfo.cpp index 35689b8115..6ec418634c 100644 --- a/src/tools/uic/customwidgetsinfo.cpp +++ b/src/tools/uic/customwidgetsinfo.cpp @@ -78,25 +78,95 @@ bool CustomWidgetsInfo::isCustomWidgetContainer(const QString &className) const return false; } +// FIXME in 7.0 - QTBUG-124241 +// Remove isAmbiguous logic when widget slots have been disambiguated. +bool CustomWidgetsInfo::isAmbiguous(const QString &className, const QString &signature, + QMetaMethod::MethodType type) const +{ + using TypeMap = QHash<QString, QMetaMethod::MethodType>; + struct AmbiguousInClass { + QLatin1StringView className; + TypeMap methodMap; + }; + + static const QList<AmbiguousInClass> ambiguousList = { + + {"QAction"_L1, {{"triggered"_L1, QMetaMethod::Signal}}}, + {"QCommandLinkButton"_L1, {{"triggered"_L1, QMetaMethod::Signal}, + {"clicked"_L1, QMetaMethod::Signal}}}, + {"QPushButton"_L1, {{"triggered"_L1, QMetaMethod::Signal}, + {"clicked"_L1, QMetaMethod::Signal}}}, + {"QCheckBox"_L1, {{"triggered"_L1, QMetaMethod::Signal}, + {"clicked"_L1, QMetaMethod::Signal}}}, + {"QRadioButton"_L1, {{"triggered"_L1, QMetaMethod::Signal}, + {"clicked"_L1, QMetaMethod::Signal}}}, + {"QToolButton"_L1, {{"triggered"_L1, QMetaMethod::Signal}, + {"clicked"_L1, QMetaMethod::Signal}}}, + {"QLabel"_L1, {{"setNum"_L1, QMetaMethod::Slot}}}, + {"QGraphicsView"_L1, {{"invalidateScene"_L1, QMetaMethod::Slot}}}, + {"QListView"_L1, {{"dataChanged"_L1, QMetaMethod::Slot}}}, + {"QColumnView"_L1, {{"dataChanged"_L1, QMetaMethod::Slot}}}, + {"QListWidget"_L1, {{"dataChanged"_L1, QMetaMethod::Slot}, + {"scrollToItem"_L1, QMetaMethod::Slot}}}, + {"QTableView"_L1, {{"dataChanged"_L1, QMetaMethod::Slot}}}, + {"QTableWidget"_L1, {{"dataChanged"_L1, QMetaMethod::Slot}, + {"scrollToItem"_L1, QMetaMethod::Slot}}}, + {"QTreeView"_L1, {{"dataChanged"_L1, QMetaMethod::Slot}, + {"verticalScrollbarValueChanged"_L1, QMetaMethod::Slot}, + {"expandRecursively"_L1, QMetaMethod::Slot}}}, + {"QTreeWidget"_L1, {{"dataChanged"_L1, QMetaMethod::Slot}, + {"verticalScrollbarValueChanged"_L1, QMetaMethod::Slot} + ,{"expandRecursively"_L1, QMetaMethod::Slot} + ,{"scrollToItem"_L1, QMetaMethod::Slot}}}, + {"QUndoView"_L1, {{"dataChanged"_L1, QMetaMethod::Slot}}}, + {"QLCDNumber"_L1, {{"display"_L1, QMetaMethod::Slot}}}, + {"QMenuBar"_L1, {{"setVisible"_L1, QMetaMethod::Slot}}}, + {"QTextBrowser"_L1, {{"setSource"_L1, QMetaMethod::Slot}}}, + + /* + The following widgets with ambiguities are not used in the widget designer: + + {"QSplashScreen"_L1, {{"showMessage"_L1, QMetaMethod::Slot}}}, + {"QCompleter"_L1, {{"activated"_L1, QMetaMethod::Signal}, + {"highlighted"_L1, QMetaMethod::Signal}}}, + {"QSystemTrayIcon"_L1, {{"showMessage"_L1, QMetaMethod::Slot}}}, + {"QStyledItemDelegate"_L1, {{"closeEditor"_L1, QMetaMethod::Signal}}}, + {"QErrorMessage"_L1, {{"showMessage"_L1, QMetaMethod::Slot}}}, + {"QGraphicsDropShadowEffect"_L1, {{"setOffset"_L1, QMetaMethod::Slot}}}, + {"QGraphicsScene"_L1, {{"invalidate"_L1, QMetaMethod::Slot}}}, + {"QItemDelegate"_L1, {{"closeEditor"_L1, QMetaMethod::Signal}}} + */ + }; + + for (auto it = ambiguousList.constBegin(); it != ambiguousList.constEnd(); ++it) { + if (extends(className, it->className)) { + const qsizetype pos = signature.indexOf(u'('); + const QString method = signature.left(pos); + const auto methodIterator = it->methodMap.find(method); + return methodIterator != it->methodMap.constEnd() && type == methodIterator.value(); + } + } + return false; +} + // Is it ambiguous, resulting in different signals for Python // "QAbstractButton::clicked(checked=false)" bool CustomWidgetsInfo::isAmbiguousSignal(const QString &className, const QString &signalSignature) const { - if (signalSignature.startsWith(u"triggered") && extends(className, "QAction")) - return true; - if (signalSignature.startsWith(u"clicked(") - && extendsOneOf(className, {u"QCommandLinkButton"_s, u"QCheckBox"_s, - u"QPushButton"_s, u"QRadioButton"_s, u"QToolButton"_s})) { - return true; - } - return false; + return isAmbiguous(className, signalSignature, QMetaMethod::Signal); +} + +bool CustomWidgetsInfo::isAmbiguousSlot(const QString &className, + const QString &signalSignature) const +{ + return isAmbiguous(className, signalSignature, QMetaMethod::Slot); } QString CustomWidgetsInfo::realClassName(const QString &className) const { if (className == "Line"_L1) - return "QFrame"_L1; + return u"QFrame"_s; return className; } diff --git a/src/tools/uic/customwidgetsinfo.h b/src/tools/uic/customwidgetsinfo.h index 4bd004bdc7..f336292f2a 100644 --- a/src/tools/uic/customwidgetsinfo.h +++ b/src/tools/uic/customwidgetsinfo.h @@ -7,6 +7,7 @@ #include "treewalker.h" #include <qstringlist.h> #include <qmap.h> +#include <QtCore/qmetaobject.h> QT_BEGIN_NAMESPACE @@ -38,10 +39,14 @@ public: bool isAmbiguousSignal(const QString &className, const QString &signalSignature) const; + bool isAmbiguousSlot(const QString &className, + const QString &slotSignature) const; private: using NameCustomWidgetMap = QMap<QString, DomCustomWidget*>; NameCustomWidgetMap m_customWidgets; + bool isAmbiguous(const QString &className, const QString &signature, + QMetaMethod::MethodType type) const; }; QT_END_NAMESPACE diff --git a/src/tools/uic/driver.cpp b/src/tools/uic/driver.cpp index a91a95ca0b..110764ee07 100644 --- a/src/tools/uic/driver.cpp +++ b/src/tools/uic/driver.cpp @@ -196,7 +196,7 @@ QString Driver::headerFileName() const QString Driver::headerFileName(const QString &fileName) { if (fileName.isEmpty()) - return headerFileName("noname"_L1); + return headerFileName(u"noname"_s); QFileInfo info(fileName); QString baseName = info.baseName(); @@ -245,9 +245,10 @@ bool Driver::uic(const QString &fileName, DomUI *ui, QTextStream *out) bool Driver::uic(const QString &fileName, QTextStream *out) { QFile f; - if (fileName.isEmpty()) - f.open(stdin, QIODevice::ReadOnly); - else { + if (fileName.isEmpty()) { + if (!f.open(stdin, QIODevice::ReadOnly)) + return false; + } else { f.setFileName(fileName); if (!f.open(QIODevice::ReadOnly)) return false; diff --git a/src/tools/uic/main.cpp b/src/tools/uic/main.cpp index 01712da485..d46b788419 100644 --- a/src/tools/uic/main.cpp +++ b/src/tools/uic/main.cpp @@ -13,17 +13,49 @@ #include <qcoreapplication.h> #include <qcommandlineoption.h> #include <qcommandlineparser.h> +#include <qfileinfo.h> QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; +static const char pythonPathVar[] = "PYTHONPATH"; + +// From the Python paths, find the component the UI file is under +static QString pythonRoot(const QString &pythonPath, const QString &uiFileIn) +{ +#ifdef Q_OS_WIN + static const Qt::CaseSensitivity fsSensitivity = Qt::CaseInsensitive; +#else + static const Qt::CaseSensitivity fsSensitivity = Qt::CaseSensitive; +#endif + + if (pythonPath.isEmpty() || uiFileIn.isEmpty()) + return {}; + const QString uiFile = QFileInfo(uiFileIn).canonicalFilePath(); + if (uiFile.isEmpty()) + return {}; + const auto uiFileSize = uiFile.size(); + const auto paths = pythonPath.split(QDir::listSeparator(), Qt::SkipEmptyParts); + for (const auto &path : paths) { + const QString canonicalPath = QFileInfo(path).canonicalFilePath(); + const auto canonicalPathSize = canonicalPath.size(); + if (uiFileSize > canonicalPathSize + && uiFile.at(canonicalPathSize) == u'/' + && uiFile.startsWith(canonicalPath, fsSensitivity)) { + return canonicalPath; + } + } + return {}; +} + int runUic(int argc, char *argv[]) { - qSetGlobalQHashSeed(0); // set the hash seed to 0 + QHashSeed::setDeterministicGlobalSeed(); QCoreApplication app(argc, argv); - QCoreApplication::setApplicationVersion(QString::fromLatin1(QT_VERSION_STR)); + const QString version = QString::fromLatin1(qVersion()); + QCoreApplication::setApplicationVersion(version); Driver driver; @@ -31,70 +63,89 @@ int runUic(int argc, char *argv[]) // If you use this code as an example for a translated app, make sure to translate the strings. QCommandLineParser parser; parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); - parser.setApplicationDescription(QStringLiteral("Qt User Interface Compiler version %1").arg(QString::fromLatin1(QT_VERSION_STR))); + parser.setApplicationDescription(u"Qt User Interface Compiler version %1"_s.arg(version)); parser.addHelpOption(); parser.addVersionOption(); - QCommandLineOption dependenciesOption(QStringList() << QStringLiteral("d") << QStringLiteral("dependencies")); - dependenciesOption.setDescription(QStringLiteral("Display the dependencies.")); + QCommandLineOption dependenciesOption(QStringList{u"d"_s, u"dependencies"_s}); + dependenciesOption.setDescription(u"Display the dependencies."_s); parser.addOption(dependenciesOption); - QCommandLineOption outputOption(QStringList() << QStringLiteral("o") << QStringLiteral("output")); - outputOption.setDescription(QStringLiteral("Place the output into <file>")); - outputOption.setValueName(QStringLiteral("file")); + QCommandLineOption outputOption(QStringList{u"o"_s, u"output"_s}); + outputOption.setDescription(u"Place the output into <file>"_s); + outputOption.setValueName(u"file"_s); parser.addOption(outputOption); - QCommandLineOption noAutoConnectionOption(QStringList() << QStringLiteral("a") << QStringLiteral("no-autoconnection")); - noAutoConnectionOption.setDescription(QStringLiteral("Do not generate a call to QObject::connectSlotsByName().")); + QCommandLineOption noAutoConnectionOption(QStringList{u"a"_s, u"no-autoconnection"_s}); + noAutoConnectionOption.setDescription(u"Do not generate a call to QObject::connectSlotsByName()."_s); parser.addOption(noAutoConnectionOption); - QCommandLineOption noProtOption(QStringList() << QStringLiteral("p") << QStringLiteral("no-protection")); - noProtOption.setDescription(QStringLiteral("Disable header protection.")); + QCommandLineOption noProtOption(QStringList{u"p"_s, u"no-protection"_s}); + noProtOption.setDescription(u"Disable header protection."_s); parser.addOption(noProtOption); - QCommandLineOption noImplicitIncludesOption(QStringList() << QStringLiteral("n") << QStringLiteral("no-implicit-includes")); - noImplicitIncludesOption.setDescription(QStringLiteral("Disable generation of #include-directives.")); + QCommandLineOption noImplicitIncludesOption(QStringList{u"n"_s, u"no-implicit-includes"_s}); + noImplicitIncludesOption.setDescription(u"Disable generation of #include-directives."_s); parser.addOption(noImplicitIncludesOption); - QCommandLineOption postfixOption(QStringLiteral("postfix")); - postfixOption.setDescription(QStringLiteral("Postfix to add to all generated classnames.")); - postfixOption.setValueName(QStringLiteral("postfix")); + QCommandLineOption postfixOption(u"postfix"_s); + postfixOption.setDescription(u"Postfix to add to all generated classnames."_s); + postfixOption.setValueName(u"postfix"_s); parser.addOption(postfixOption); - QCommandLineOption translateOption(QStringList() << QStringLiteral("tr") << QStringLiteral("translate")); - translateOption.setDescription(QStringLiteral("Use <function> for i18n.")); - translateOption.setValueName(QStringLiteral("function")); + QCommandLineOption noQtNamespaceOption(u"no-qt-namespace"_s); + noQtNamespaceOption.setDescription( + u"Disable wrapping the definition of the generated class in QT_{BEGIN,END}_NAMESPACE."_s); + parser.addOption(noQtNamespaceOption); + + QCommandLineOption translateOption(QStringList{u"tr"_s, u"translate"_s}); + translateOption.setDescription(u"Use <function> for i18n."_s); + translateOption.setValueName(u"function"_s); parser.addOption(translateOption); - QCommandLineOption includeOption(QStringList() << QStringLiteral("include")); - includeOption.setDescription(QStringLiteral("Add #include <include-file> to <file>.")); - includeOption.setValueName(QStringLiteral("include-file")); + QCommandLineOption includeOption(QStringList{u"include"_s}); + includeOption.setDescription(u"Add #include <include-file> to <file>."_s); + includeOption.setValueName(u"include-file"_s); parser.addOption(includeOption); - QCommandLineOption generatorOption(QStringList() << QStringLiteral("g") << QStringLiteral("generator")); - generatorOption.setDescription(QStringLiteral("Select generator.")); - generatorOption.setValueName(QStringLiteral("python|cpp")); + QCommandLineOption generatorOption(QStringList{u"g"_s, u"generator"_s}); + generatorOption.setDescription(u"Select generator."_s); + generatorOption.setValueName(u"python|cpp"_s); parser.addOption(generatorOption); - QCommandLineOption connectionsOption(QStringList{QStringLiteral("c"), QStringLiteral("connections")}); - connectionsOption.setDescription(QStringLiteral("Connection syntax.")); - connectionsOption.setValueName(QStringLiteral("pmf|string")); + QCommandLineOption connectionsOption(QStringList{u"c"_s, u"connections"_s}); + connectionsOption.setDescription(u"Connection syntax."_s); + connectionsOption.setValueName(u"pmf|string"_s); parser.addOption(connectionsOption); - QCommandLineOption idBasedOption(QStringLiteral("idbased")); - idBasedOption.setDescription(QStringLiteral("Use id based function for i18n")); + QCommandLineOption idBasedOption(u"idbased"_s); + idBasedOption.setDescription(u"Use id based function for i18n"_s); parser.addOption(idBasedOption); - QCommandLineOption fromImportsOption(QStringLiteral("from-imports")); - fromImportsOption.setDescription(QStringLiteral("Python: generate imports relative to '.'")); + QCommandLineOption fromImportsOption(u"from-imports"_s); + fromImportsOption.setDescription(u"Python: generate imports relative to '.'"_s); parser.addOption(fromImportsOption); + QCommandLineOption absoluteImportsOption(u"absolute-imports"_s); + absoluteImportsOption.setDescription(u"Python: generate absolute imports"_s); + parser.addOption(absoluteImportsOption); + + // FIXME Qt 7: Flip the default? + QCommandLineOption rcPrefixOption(u"rc-prefix"_s); + rcPrefixOption.setDescription(uR"(Python: Generate "rc_file" instead of "file_rc" import)"_s); + parser.addOption(rcPrefixOption); + // FIXME Qt 7: Remove? - QCommandLineOption useStarImportsOption(QStringLiteral("star-imports")); - useStarImportsOption.setDescription(QStringLiteral("Python: Use * imports")); + QCommandLineOption useStarImportsOption(u"star-imports"_s); + useStarImportsOption.setDescription(u"Python: Use * imports"_s); parser.addOption(useStarImportsOption); - parser.addPositionalArgument(QStringLiteral("[uifile]"), QStringLiteral("Input file (*.ui), otherwise stdin.")); + QCommandLineOption pythonPathOption(u"python-paths"_s); + pythonPathOption.setDescription(u"Python paths for --absolute-imports."_s); + pythonPathOption.setValueName(u"pathlist"_s); + parser.addOption(pythonPathOption); + + parser.addPositionalArgument(u"[uifile]"_s, u"Input file (*.ui), otherwise stdin."_s); parser.process(app); @@ -103,9 +154,8 @@ int runUic(int argc, char *argv[]) driver.option().autoConnection = !parser.isSet(noAutoConnectionOption); driver.option().headerProtection = !parser.isSet(noProtOption); driver.option().implicitIncludes = !parser.isSet(noImplicitIncludesOption); + driver.option().qtNamespace = !parser.isSet(noQtNamespaceOption); driver.option().idBased = parser.isSet(idBasedOption); - driver.option().fromImports = parser.isSet(fromImportsOption); - driver.option().useStarImports = parser.isSet(useStarImportsOption); driver.option().postfix = parser.value(postfixOption); driver.option().translateFunction = parser.value(translateOption); driver.option().includeFile = parser.value(includeOption); @@ -117,17 +167,31 @@ int runUic(int argc, char *argv[]) driver.option().forceStringConnectionSyntax = 1; } + const QString inputFile = parser.positionalArguments().value(0); + Language language = Language::Cpp; if (parser.isSet(generatorOption)) { if (parser.value(generatorOption).compare("python"_L1) == 0) language = Language::Python; } language::setLanguage(language); + if (language == Language::Python) { + if (parser.isSet(fromImportsOption)) + driver.option().pythonResourceImport = Option::PythonResourceImport::FromDot; + else if (parser.isSet(absoluteImportsOption)) + driver.option().pythonResourceImport = Option::PythonResourceImport::Absolute; + driver.option().useStarImports = parser.isSet(useStarImportsOption); + if (parser.isSet(rcPrefixOption)) + driver.option().rcPrefix = 1; + QString pythonPaths; + if (parser.isSet(pythonPathOption)) + pythonPaths = parser.value(pythonPathOption); + else if (qEnvironmentVariableIsSet(pythonPathVar)) + pythonPaths = QString::fromUtf8(qgetenv(pythonPathVar)); + driver.option().pythonRoot = pythonRoot(pythonPaths, inputFile); + } - QString inputFile; - if (!parser.positionalArguments().isEmpty()) - inputFile = parser.positionalArguments().at(0); - else // reading from stdin + if (inputFile.isEmpty()) // reading from stdin driver.option().headerProtection = false; if (driver.option().dependencies) { diff --git a/src/tools/uic/option.h b/src/tools/uic/option.h index 277655b3ad..cfdd90fda3 100644 --- a/src/tools/uic/option.h +++ b/src/tools/uic/option.h @@ -11,6 +11,12 @@ QT_BEGIN_NAMESPACE struct Option { + enum class PythonResourceImport { + Default, // "import rc_file" + FromDot, // "from . import rc_file" + Absolute // "import path.rc_file" + }; + unsigned int headerProtection : 1; unsigned int copyrightHeader : 1; unsigned int generateImplemetation : 1; @@ -20,10 +26,11 @@ struct Option unsigned int limitXPM_LineLength : 1; unsigned int implicitIncludes: 1; unsigned int idBased: 1; - unsigned int fromImports: 1; unsigned int forceMemberFnPtrConnectionSyntax: 1; unsigned int forceStringConnectionSyntax: 1; unsigned int useStarImports: 1; + unsigned int rcPrefix: 1; // Python: Generate "rc_file" instead of "file_rc" import + unsigned int qtNamespace: 1; QString inputFile; QString outputFile; @@ -33,6 +40,9 @@ struct Option QString postfix; QString translateFunction; QString includeFile; + QString pythonRoot; + + PythonResourceImport pythonResourceImport = PythonResourceImport::Default; Option() : headerProtection(1), @@ -44,10 +54,11 @@ struct Option limitXPM_LineLength(0), implicitIncludes(1), idBased(0), - fromImports(0), forceMemberFnPtrConnectionSyntax(0), forceStringConnectionSyntax(0), useStarImports(0), + rcPrefix(0), + qtNamespace(1), prefix(QLatin1StringView("Ui_")) { indent.fill(u' ', 4); } diff --git a/src/tools/uic/python/pythonwriteimports.cpp b/src/tools/uic/python/pythonwriteimports.cpp index a894a00a8d..74eeab8387 100644 --- a/src/tools/uic/python/pythonwriteimports.cpp +++ b/src/tools/uic/python/pythonwriteimports.cpp @@ -10,6 +10,8 @@ #include <ui4.h> +#include <QtCore/qdir.h> +#include <QtCore/qfileinfo.h> #include <QtCore/qtextstream.h> #include <algorithm> @@ -54,20 +56,6 @@ static WriteImports::ClassesPerModule defaultClasses() }; } -// Change the name of a qrc file "dir/foo.qrc" file to the Python -// module name "foo_rc" according to project conventions. -static QString pythonResource(QString resource) -{ - const qsizetype lastSlash = resource.lastIndexOf(u'/'); - if (lastSlash != -1) - resource.remove(0, lastSlash + 1); - if (resource.endsWith(".qrc"_L1)) { - resource.chop(4); - resource.append("_rc"_L1); - } - return resource; -} - // Helpers for WriteImports::ClassesPerModule maps static void insertClass(const QString &module, const QString &className, WriteImports::ClassesPerModule *c) @@ -140,17 +128,57 @@ void WriteImports::acceptUI(DomUI *node) const auto includes = resources->elementInclude(); for (auto include : includes) { if (include->hasAttributeLocation()) - writeImport(pythonResource(include->attributeLocation())); + writeResourceImport(include->attributeLocation()); } output << '\n'; } } -void WriteImports::writeImport(const QString &module) +QString WriteImports::resourceAbsolutePath(QString resource) const { - if (uic()->option().fromImports) - uic()->output() << "from . "; - uic()->output() << "import " << module << '\n'; + // If we know the project root, generate an absolute Python import + // to the resource. options. pythonRoot is the Python path component + // under which the UI file is. + const auto &options = uic()->option(); + if (!options.inputFile.isEmpty() && !options.pythonRoot.isEmpty()) { + resource = QDir::cleanPath(QFileInfo(options.inputFile).canonicalPath() + u'/' + resource); + if (resource.size() > options.pythonRoot.size()) + resource.remove(0, options.pythonRoot.size() + 1); + } + // If nothing is known, we assume the directory pointed by "../" is the root + while (resource.startsWith(u"../")) + resource.remove(0, 3); + resource.replace(u'/', u'.'); + return resource; +} + +void WriteImports::writeResourceImport(const QString &module) +{ + const auto &options = uic()->option(); + auto &str = uic()->output(); + + QString resource = QDir::cleanPath(module); + if (resource.endsWith(u".qrc")) + resource.chop(4); + const qsizetype basePos = resource.lastIndexOf(u'/') + 1; + // Change the name of a qrc file "dir/foo.qrc" file to the Python + // module name "foo_rc" according to project conventions. + if (options.rcPrefix) + resource.insert(basePos, u"rc_"); + else + resource.append(u"_rc"); + + switch (options.pythonResourceImport) { + case Option::PythonResourceImport::Default: + str << "import " << QStringView{resource}.sliced(basePos) << '\n'; + break; + case Option::PythonResourceImport::FromDot: + str << "from . import " << QStringView{resource}.sliced(basePos) << '\n'; + break; + case Option::PythonResourceImport::Absolute: + str << "import " << resourceAbsolutePath(resource) << '\n'; + break; + } } void WriteImports::doAdd(const QString &className, const DomCustomWidget *dcw) @@ -201,9 +229,13 @@ void WriteImports::addPythonCustomWidget(const QString &className, const DomCust QString modulePath = node->elementHeader()->text(); // Replace the '/' by '.' modulePath.replace(u'/', u'.'); - // '.h' is added by default on headers for <customwidget> - if (modulePath.endsWith(".h"_L1)) + // '.h' is added by default on headers for <customwidget>. + if (modulePath.endsWith(".h"_L1, Qt::CaseInsensitive)) modulePath.chop(2); + else if (modulePath.endsWith(".hh"_L1)) + modulePath.chop(3); + else if (modulePath.endsWith(".hpp"_L1)) + modulePath.chop(4); insertClass(modulePath, className, &m_customWidgets); } } diff --git a/src/tools/uic/python/pythonwriteimports.h b/src/tools/uic/python/pythonwriteimports.h index 14aefd4f2a..4497b8dc33 100644 --- a/src/tools/uic/python/pythonwriteimports.h +++ b/src/tools/uic/python/pythonwriteimports.h @@ -31,7 +31,8 @@ private: void addPythonCustomWidget(const QString &className, const DomCustomWidget *dcw); bool addQtClass(const QString &className); void addEnumBaseClass(const QString &v); - void writeImport(const QString &module); + void writeResourceImport(const QString &module); + QString resourceAbsolutePath(QString resource) const; QHash<QString, QString> m_classToModule; // Module->class (modules sorted) diff --git a/src/tools/uic/qclass_lib_map.h b/src/tools/uic/qclass_lib_map.h index 236fd97449..e9e4cfde12 100644 --- a/src/tools/uic/qclass_lib_map.h +++ b/src/tools/uic/qclass_lib_map.h @@ -837,6 +837,7 @@ QT_CLASS_LIB(QGraphicsSvgItem, QtSvgWidgets, qgraphicssvgitem.h) QT_CLASS_LIB(QSvgWidget, QtSvgWidgets, qsvgwidget.h) QT_CLASS_LIB(QSvgGenerator, QtSvg, qsvggenerator.h) QT_CLASS_LIB(QSvgRenderer, QtSvg, qsvgrenderer.h) +QT_CLASS_LIB(QPdfView, QtPdfWidgets, qpdfview.h) QT_CLASS_LIB(QQuickWidget, QtQuickWidgets, qquickwidget.h) QT_CLASS_LIB(QVideoWidget, QtMultimediaWidgets, qvideowidget.h) QT_CLASS_LIB(QWebEngineView, QtWebEngineWidgets, qwebengineview.h) diff --git a/src/tools/uic/shared/language.cpp b/src/tools/uic/shared/language.cpp index a3ca704b1b..d59688e346 100644 --- a/src/tools/uic/shared/language.cpp +++ b/src/tools/uic/shared/language.cpp @@ -4,6 +4,7 @@ #include "language.h" #include <QtCore/qtextstream.h> +#include <QtCore/QList> namespace language { @@ -58,9 +59,9 @@ QString self; QString eol; QString emptyString; -QString cppQualifier = "::"_L1; -QString cppTrue = "true"_L1; -QString cppFalse = "false"_L1; +QString cppQualifier = u"::"_s; +QString cppTrue = u"true"_s; +QString cppFalse = u"false"_s; QTextStream &operator<<(QTextStream &str, const qtConfig &c) { @@ -83,19 +84,19 @@ 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; } @@ -106,74 +107,74 @@ QString fixClassName(QString className) 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); } @@ -370,17 +371,40 @@ 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) +{ + 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); @@ -388,11 +412,24 @@ static void formatMemberFnPtr(QTextStream &str, const SignalSlot &s, 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; @@ -405,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 << ')'; } diff --git a/src/tools/uic/shared/language.h b/src/tools/uic/shared/language.h index 52b3a0c201..de39122ee8 100644 --- a/src/tools/uic/shared/language.h +++ b/src/tools/uic/shared/language.h @@ -75,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 }; diff --git a/src/tools/uic/ui4.cpp b/src/tools/uic/ui4.cpp index 42ee4fbefa..b6a8f4eb4b 100644 --- a/src/tools/uic/ui4.cpp +++ b/src/tools/uic/ui4.cpp @@ -77,7 +77,8 @@ void DomUI::read(QXmlStreamReader &reader) setElementAuthor(reader.readElementText()); continue; } - if (!tag.compare(u"comment"_s, Qt::CaseInsensitive)) { + if (!tag.compare(u"comment"_s, Qt::CaseInsensitive) + || !tag.compare(u"legal"_s, Qt::CaseInsensitive)) { setElementComment(reader.readElementText()); continue; } @@ -3121,6 +3122,14 @@ void DomFont::read(QXmlStreamReader &reader) setElementKerning(reader.readElementText() == u"true"_s); continue; } + if (!tag.compare(u"hintingpreference"_s, Qt::CaseInsensitive)) { + setElementHintingPreference(reader.readElementText()); + continue; + } + if (!tag.compare(u"fontweight"_s, Qt::CaseInsensitive)) { + setElementFontWeight(reader.readElementText()); + continue; + } reader.raiseError("Unexpected element "_L1 + tag); } break; @@ -3166,6 +3175,12 @@ void DomFont::write(QXmlStreamWriter &writer, const QString &tagName) const if (m_children & Kerning) writer.writeTextElement(u"kerning"_s, (m_kerning ? u"true"_s : u"false"_s)); + if (m_children & HintingPreference) + writer.writeTextElement(u"hintingpreference"_s, m_hintingPreference); + + if (m_children & FontWeight) + writer.writeTextElement(u"fontweight"_s, m_fontWeight); + writer.writeEndElement(); } @@ -3229,6 +3244,18 @@ void DomFont::setElementKerning(bool a) m_kerning = a; } +void DomFont::setElementHintingPreference(const QString &a) +{ + m_children |= HintingPreference; + m_hintingPreference = a; +} + +void DomFont::setElementFontWeight(const QString &a) +{ + m_children |= FontWeight; + m_fontWeight = a; +} + void DomFont::clearElementFamily() { m_children &= ~Family; @@ -3279,6 +3306,16 @@ void DomFont::clearElementKerning() m_children &= ~Kerning; } +void DomFont::clearElementHintingPreference() +{ + m_children &= ~HintingPreference; +} + +void DomFont::clearElementFontWeight() +{ + m_children &= ~FontWeight; +} + DomPoint::~DomPoint() = default; void DomPoint::read(QXmlStreamReader &reader) diff --git a/src/tools/uic/ui4.h b/src/tools/uic/ui4.h index 577baa3766..333f7f4e6a 100644 --- a/src/tools/uic/ui4.h +++ b/src/tools/uic/ui4.h @@ -1645,6 +1645,16 @@ public: inline bool hasElementKerning() const { return m_children & Kerning; } void clearElementKerning(); + inline QString elementHintingPreference() const { return m_hintingPreference; } + void setElementHintingPreference(const QString &a); + inline bool hasElementHintingPreference() const { return m_children & HintingPreference; } + void clearElementHintingPreference(); + + inline QString elementFontWeight() const { return m_fontWeight; } + void setElementFontWeight(const QString &a); + inline bool hasElementFontWeight() const { return m_children & FontWeight; } + void clearElementFontWeight(); + private: // child element data @@ -1659,6 +1669,8 @@ private: bool m_antialiasing = false; QString m_styleStrategy; bool m_kerning = false; + QString m_hintingPreference; + QString m_fontWeight; enum Child { Family = 1, @@ -1670,7 +1682,9 @@ private: StrikeOut = 64, Antialiasing = 128, StyleStrategy = 256, - Kerning = 512 + Kerning = 512, + HintingPreference = 1024, + FontWeight = 2048 }; }; diff --git a/src/tools/uic/uic.cpp b/src/tools/uic/uic.cpp index 9c61ae4778..1b10e1d722 100644 --- a/src/tools/uic/uic.cpp +++ b/src/tools/uic/uic.cpp @@ -38,9 +38,10 @@ bool Uic::printDependencies() QString fileName = opt.inputFile; QFile f; - if (fileName.isEmpty()) - f.open(stdin, QIODevice::ReadOnly); - else { + if (fileName.isEmpty()) { + if (!f.open(stdin, QIODevice::ReadOnly)) + return false; + } else { f.setFileName(fileName); if (!f.open(QIODevice::ReadOnly)) return false; @@ -146,7 +147,7 @@ void Uic::writeCopyrightHeaderPython(const DomUI *ui) const static double versionFromUiAttribute(QXmlStreamReader &reader) { const QXmlStreamAttributes attributes = reader.attributes(); - const QString versionAttribute = "version"_L1; + const auto versionAttribute = "version"_L1; if (!attributes.hasAttribute(versionAttribute)) return 4.0; const QStringView version = attributes.value(versionAttribute); @@ -157,14 +158,14 @@ DomUI *Uic::parseUiFile(QXmlStreamReader &reader) { DomUI *ui = nullptr; - const QString uiElement = "ui"_L1; + const auto uiElement = "ui"_L1; while (!reader.atEnd()) { if (reader.readNext() == QXmlStreamReader::StartElement) { if (reader.name().compare(uiElement, Qt::CaseInsensitive) == 0 && !ui) { const double version = versionFromUiAttribute(reader); if (version < 4.0) { - const QString msg = QString::fromLatin1("uic: File generated with too old version of Qt Designer (%1)").arg(version); + const QString msg = QString::fromLatin1("uic: File generated with too old version of Qt Widgets Designer (%1)").arg(version); fprintf(stderr, "%s\n", qPrintable(msg)); return nullptr; } @@ -201,7 +202,7 @@ bool Uic::write(QIODevice *in) double version = ui->attributeVersion().toDouble(); if (version < 4.0) { - fprintf(stderr, "uic: File generated with too old version of Qt Designer\n"); + fprintf(stderr, "uic: File generated with too old version of Qt Widgets Designer\n"); return false; } @@ -291,9 +292,9 @@ void Uic::writeHeaderProtectionEnd() bool Uic::isButton(const QString &className) const { static const QStringList buttons = { - "QRadioButton"_L1, "QToolButton"_L1, - "QCheckBox"_L1, "QPushButton"_L1, - "QCommandLinkButton"_L1 + u"QRadioButton"_s, u"QToolButton"_s, + u"QCheckBox"_s, u"QPushButton"_s, + u"QCommandLinkButton"_s }; return customWidgetsInfo()->extendsOneOf(className, buttons); } @@ -301,10 +302,10 @@ bool Uic::isButton(const QString &className) const bool Uic::isContainer(const QString &className) const { static const QStringList containers = { - "QStackedWidget"_L1, "QToolBox"_L1, - "QTabWidget"_L1, "QScrollArea"_L1, - "QMdiArea"_L1, "QWizard"_L1, - "QDockWidget"_L1 + u"QStackedWidget"_s, u"QToolBox"_s, + u"QTabWidget"_s, u"QScrollArea"_s, + u"QMdiArea"_s, u"QWizard"_s, + u"QDockWidget"_s }; return customWidgetsInfo()->extendsOneOf(className, containers); @@ -313,7 +314,7 @@ bool Uic::isContainer(const QString &className) const bool Uic::isMenu(const QString &className) const { static const QStringList menus = { - "QMenu"_L1, "QPopupMenu"_L1 + u"QMenu"_s, u"QPopupMenu"_s }; return customWidgetsInfo()->extendsOneOf(className, menus); } diff --git a/src/tools/uic/utils.h b/src/tools/uic/utils.h index d8a563c0c6..37247cdea6 100644 --- a/src/tools/uic/utils.h +++ b/src/tools/uic/utils.h @@ -12,7 +12,7 @@ QT_BEGIN_NAMESPACE inline bool toBool(const QString &str) -{ return str.toLower() == QLatin1StringView("true"); } +{ return QString::compare(str, QLatin1StringView("true"), Qt::CaseInsensitive) == 0; } inline QString toString(const DomString *str) { return str ? str->text() : QString(); } |