diff options
Diffstat (limited to 'src/tools/uic')
-rw-r--r-- | src/tools/uic/CMakeLists.txt | 15 | ||||
-rw-r--r-- | src/tools/uic/cpp/cppwritedeclaration.cpp | 4 | ||||
-rw-r--r-- | src/tools/uic/cpp/cppwriteinitialization.cpp | 252 | ||||
-rw-r--r-- | src/tools/uic/cpp/cppwriteinitialization.h | 3 | ||||
-rw-r--r-- | src/tools/uic/customwidgetsinfo.cpp | 86 | ||||
-rw-r--r-- | src/tools/uic/customwidgetsinfo.h | 5 | ||||
-rw-r--r-- | src/tools/uic/driver.cpp | 7 | ||||
-rw-r--r-- | src/tools/uic/main.cpp | 57 | ||||
-rw-r--r-- | src/tools/uic/option.h | 13 | ||||
-rw-r--r-- | src/tools/uic/python/pythonwriteimports.cpp | 78 | ||||
-rw-r--r-- | src/tools/uic/python/pythonwriteimports.h | 3 | ||||
-rw-r--r-- | src/tools/uic/shared/language.cpp | 159 | ||||
-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 | 11 |
16 files changed, 554 insertions, 202 deletions
diff --git a/src/tools/uic/CMakeLists.txt b/src/tools/uic/CMakeLists.txt index fcdfa60939..9f47ec8b4b 100644 --- a/src/tools/uic/CMakeLists.txt +++ b/src/tools/uic/CMakeLists.txt @@ -1,17 +1,16 @@ # Copyright (C) 2022 The Qt Company Ltd. # SPDX-License-Identifier: BSD-3-Clause -# Generated from uic.pro. - ##################################################################### ## uic Tool: ##################################################################### 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 @@ -33,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} @@ -40,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 910c4e2ee2..8261963cfa 100644 --- a/src/tools/uic/cpp/cppwritedeclaration.cpp +++ b/src/tools/uic/cpp/cppwritedeclaration.cpp @@ -65,8 +65,8 @@ 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.size() == 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"; diff --git a/src/tools/uic/cpp/cppwriteinitialization.cpp b/src/tools/uic/cpp/cppwriteinitialization.cpp index d87e56d20f..c9356a4111 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)) << ')'; } @@ -180,6 +196,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 +219,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 +234,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 +255,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; } @@ -690,8 +717,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")) { @@ -1273,9 +1300,9 @@ void WriteInitialization::writeProperties(const QString &varName, } else if (propertyName == "orientation"_L1 && m_uic->customWidgetsInfo()->extends(className, "Line")) { // Line support - QString shape = u"QFrame::HLine"_s; - if (p->elementEnum() == "Qt::Vertical"_L1) - shape = u"QFrame::VLine"_s; + 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; @@ -1283,7 +1310,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; @@ -1366,8 +1393,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(); @@ -1583,12 +1610,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; @@ -1627,10 +1660,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; @@ -1657,6 +1694,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; } @@ -1666,8 +1708,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 @@ -1715,7 +1758,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; } @@ -1766,6 +1810,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 @@ -1790,7 +1887,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; @@ -1801,12 +1899,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 @@ -1815,31 +1922,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); - if (isCpp) - m_output << m_indent << '}'; - 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; } @@ -2060,7 +2155,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; @@ -2632,14 +2727,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, diff --git a/src/tools/uic/cpp/cppwriteinitialization.h b/src/tools/uic/cpp/cppwriteinitialization.h index 716af2e81d..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> @@ -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 169cdad618..6ec418634c 100644 --- a/src/tools/uic/customwidgetsinfo.cpp +++ b/src/tools/uic/customwidgetsinfo.cpp @@ -78,19 +78,89 @@ 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 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 ab19f5a2b4..110764ee07 100644 --- a/src/tools/uic/driver.cpp +++ b/src/tools/uic/driver.cpp @@ -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 c4dcec29d5..d46b788419 100644 --- a/src/tools/uic/main.cpp +++ b/src/tools/uic/main.cpp @@ -13,11 +13,42 @@ #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[]) { QHashSeed::setDeterministicGlobalSeed(); @@ -62,6 +93,11 @@ int runUic(int argc, char *argv[]) postfixOption.setValueName(u"postfix"_s); parser.addOption(postfixOption); + 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); @@ -90,6 +126,10 @@ int runUic(int argc, char *argv[]) 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); @@ -100,6 +140,11 @@ int runUic(int argc, char *argv[]) useStarImportsOption.setDescription(u"Python: Use * imports"_s); parser.addOption(useStarImportsOption); + 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); @@ -109,6 +154,7 @@ 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().postfix = parser.value(postfixOption); driver.option().translateFunction = parser.value(translateOption); @@ -130,10 +176,19 @@ int runUic(int argc, char *argv[]) } language::setLanguage(language); if (language == Language::Python) { - driver.option().fromImports = parser.isSet(fromImportsOption); + 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); } if (inputFile.isEmpty()) // reading from stdin diff --git a/src/tools/uic/option.h b/src/tools/uic/option.h index 9b4c98344f..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,11 +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; @@ -34,6 +40,9 @@ struct Option QString postfix; QString translateFunction; QString includeFile; + QString pythonRoot; + + PythonResourceImport pythonResourceImport = PythonResourceImport::Default; Option() : headerProtection(1), @@ -45,11 +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 a268f87bb4..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,23 +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, bool prefix) -{ - const qsizetype lastSlash = resource.lastIndexOf(u'/'); - if (lastSlash != -1) - resource.remove(0, lastSlash + 1); - if (resource.endsWith(".qrc"_L1)) { - resource.chop(4); - if (prefix) - resource.prepend("rc_"_L1); - else - resource.append("_rc"_L1); - } - return resource; -} - // Helpers for WriteImports::ClassesPerModule maps static void insertClass(const QString &module, const QString &className, WriteImports::ClassesPerModule *c) @@ -143,18 +128,57 @@ void WriteImports::acceptUI(DomUI *node) const auto includes = resources->elementInclude(); for (auto include : includes) { if (include->hasAttributeLocation()) - writeImport(pythonResource(include->attributeLocation(), - uic()->option().rcPrefix)); + writeResourceImport(include->attributeLocation()); } output << '\n'; } } -void WriteImports::writeImport(const QString &module) +QString WriteImports::resourceAbsolutePath(QString resource) const +{ + // 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) { - if (uic()->option().fromImports) - uic()->output() << "from . "; - uic()->output() << "import " << module << '\n'; + 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) @@ -205,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/shared/language.cpp b/src/tools/uic/shared/language.cpp index 6567903000..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 { @@ -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 caf5ff4e1f..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; @@ -164,7 +165,7 @@ DomUI *Uic::parseUiFile(QXmlStreamReader &reader) && !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; } |