/**************************************************************************** ** ** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the tools applications of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "language.h" #include namespace language { static Encoding encoding = Encoding::Utf8; static Language _language = Language::Cpp; Language language() { return _language; } void setLanguage(Language l) { _language = l; switch (_language) { case Language::Cpp: derefPointer = QLatin1String("->"); listStart = '{'; listEnd = '}'; nullPtr = QLatin1String("nullptr"); operatorNew = QLatin1String("new "); qtQualifier = QLatin1String("Qt::"); qualifier = QLatin1String("::"); self = QLatin1String(""); // for testing: change to "this->"; eol = QLatin1String(";\n"); emptyString = QLatin1String("QString()"); encoding = Encoding::Utf8; break; case Language::Python: derefPointer = QLatin1String("."); listStart = '['; listEnd = ']'; nullPtr = QLatin1String("None"); operatorNew = QLatin1String(""); qtQualifier = QLatin1String("Qt."); qualifier = QLatin1String("."); self = QLatin1String("self."); eol = QLatin1String("\n"); emptyString = QLatin1String("\"\""); encoding = Encoding::Unicode; break; } } QString derefPointer; char listStart; char listEnd; QString nullPtr; QString operatorNew; QString qtQualifier; QString qualifier; QString self; QString eol; QString emptyString; QString cppQualifier = QLatin1String("::"); QString cppTrue = QLatin1String("true"); QString cppFalse = QLatin1String("false"); QTextStream &operator<<(QTextStream &str, const qtConfig &c) { str << "QT_CONFIG(" << c.parameter() << ')'; return str; } QTextStream &operator<<(QTextStream &str, const openQtConfig &c) { str << "#if " << qtConfig(c.parameter()) << '\n'; return str; } QTextStream &operator<<(QTextStream &str, const closeQtConfig &c) { str << "#endif // " << qtConfig(c.parameter()) << '\n'; return str; } struct EnumLookup { int value; const char *valueString; }; template const char *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; qWarning("uic: Warning: Invalid enumeration value %d, defaulting to %s", value, defaultValue); return defaultValue; } QString fixClassName(QString className) { if (language() == Language::Python) className.replace(cppQualifier, QLatin1String("_")); return className; } const char *toolbarArea(int v) { static const EnumLookup toolBarAreas[] = { {0, "NoToolBarArea"}, {0x1, "LeftToolBarArea"}, {0x2, "RightToolBarArea"}, {0x4, "TopToolBarArea"}, {0x8, "BottomToolBarArea"}, {0xf, "AllToolBarAreas"} }; return lookupEnum(toolBarAreas, v); } const char *sizePolicy(int v) { static const EnumLookup sizePolicies[] = { {0, "Fixed"}, {0x1, "Minimum"}, {0x4, "Maximum"}, {0x5, "Preferred"}, {0x3, "MinimumExpanding"}, {0x7, "Expanding"}, {0xD, "Ignored"} }; return lookupEnum(sizePolicies, v, 3); } const char *dockWidgetArea(int v) { static const EnumLookup dockWidgetAreas[] = { {0, "NoDockWidgetArea"}, {0x1, "LeftDockWidgetArea"}, {0x2, "RightDockWidgetArea"}, {0x4, "TopDockWidgetArea"}, {0x8, "BottomDockWidgetArea"}, {0xf, "AllDockWidgetAreas"} }; return lookupEnum(dockWidgetAreas, v); } const char *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"}, }; return lookupEnum(colorRoles, v); } // Helpers for formatting a character sequences // Format a special character like '\x0a' static int formatEscapedNumber(QTextStream &str, ushort value, int base, int width, char prefix = 0) { int length = 1 + width; str << '\\'; if (prefix) { str << prefix; ++length; } const auto oldPadChar = str.padChar(); const auto oldFieldWidth = str.fieldWidth(); const auto oldFieldAlignment = str.fieldAlignment(); const auto oldIntegerBase = str.integerBase(); str.setPadChar(QLatin1Char('0')); str.setFieldWidth(width); str.setFieldAlignment(QTextStream::AlignRight); str.setIntegerBase(base); str << value; str.setIntegerBase(oldIntegerBase); str.setFieldAlignment(oldFieldAlignment); str.setFieldWidth(oldFieldWidth); str.setPadChar(oldPadChar); return length; } static int formatSpecialCharacter(QTextStream &str, ushort value) { int length = 0; switch (value) { case '\\': str << "\\\\"; length += 2; break; case '\"': str << "\\\""; length += 2; break; case '\n': str << "\\n\"\n\""; length += 5; break; default: break; } return length; } // Format a sequence of characters for C++ with special characters numerically // escaped (non-raw string literals), wrappped at maxSegmentSize. FormattingTraits // are used to transform characters into (unsigned) codes, which can be used // for either normal escapes or Unicode code points as used in Unicode literals. enum : int { maxSegmentSize = 1024 }; template struct FormattingTraits { }; template <> struct FormattingTraits { static ushort code(char c) { return uchar(c); } }; template <> struct FormattingTraits { static ushort code(QChar c) { return c.unicode(); } }; template static void formatStringSequence(QTextStream &str, Iterator it, Iterator end, const QString &indent, int escapeIntegerBase, int escapeWidth, char escapePrefix = 0) { str << '"'; int length = 0; while (it != end) { const auto code = FormattingTraits::code(*it); if (code >= 0x80) { length += formatEscapedNumber(str, code, escapeIntegerBase, escapeWidth, escapePrefix); } else if (const int l = formatSpecialCharacter(str, code)) { length += l; } else if (code != '\r') { str << *it; ++length; } ++it; if (it != end && length > maxSegmentSize) { str << "\"\n" << indent << indent << '"'; length = 0; } } str << '"'; } void _formatString(QTextStream &str, const QString &value, const QString &indent, bool qString) { switch (encoding) { // Special characters as 3 digit octal escapes (u8"\303\234mlaut") case Encoding::Utf8: { if (qString && _language == Language::Cpp) str << "QString::fromUtf8("; const QByteArray utf8 = value.toUtf8(); formatStringSequence(str, utf8.cbegin(), utf8.cend(), indent, 8, 3); if (qString && _language == Language::Cpp) str << ')'; } break; // Special characters as 4 digit hex Unicode points (u8"\u00dcmlaut") case Encoding::Unicode: str << 'u'; // Python Unicode literal (would be UTF-16 in C++) formatStringSequence(str, value.cbegin(), value.cend(), indent, 16, 4, 'u'); break; } } QTextStream &operator<<(QTextStream &str, const repeat &r) { for (int i = 0; i < r.m_count; ++i) str << r.m_char; return str; } startFunctionDefinition1::startFunctionDefinition1(const char *name, const QString ¶meterType, const QString ¶meterName, const QString &indent, const char *returnType) : m_name(name), m_parameterType(parameterType), m_parameterName(parameterName), m_indent(indent), m_return(returnType) { } QTextStream &operator<<(QTextStream &str, const startFunctionDefinition1 &f) { switch (language()) { case Language::Cpp: str << (f.m_return ? f.m_return : "void") << ' ' << f.m_name << '(' << f.m_parameterType; if (f.m_parameterType.cend()->isLetter()) str << ' '; str << f.m_parameterName << ')' << '\n' << f.m_indent << "{\n"; break; case Language::Python: str << "def " << f.m_name << "(self, " << f.m_parameterName << "):\n"; break; } return str; } endFunctionDefinition::endFunctionDefinition(const char *name) : m_name(name) { } QTextStream &operator<<(QTextStream &str, const endFunctionDefinition &f) { switch (language()) { case Language::Cpp: str << "} // " << f.m_name << "\n\n"; break; case Language::Python: str << "# " << f.m_name << "\n\n"; break; } return str; } void _formatStackVariable(QTextStream &str, const char *className, QStringView varName, bool withInitParameters) { switch (language()) { case Language::Cpp: str << className << ' ' << varName; if (withInitParameters) str << '('; break; case Language::Python: str << varName << " = " << className << '('; if (!withInitParameters) str << ')'; break; } } 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 }; // Format a member function for a signal slot connection static void formatMemberFnPtr(QTextStream &str, const SignalSlot &s, OverloadUse useQOverload = DontUseOverload) { const int parenPos = s.signature.indexOf(QLatin1Char('(')); Q_ASSERT(parenPos >= 0); const auto functionName = QStringView{s.signature}.left(parenPos); const auto parameters = QStringView{s.signature}.mid(parenPos + 1, s.signature.size() - parenPos - 2); const bool withOverload = useQOverload == UseOverload || (useQOverload == UseOverloadWhenNoArguments && parameters.isEmpty()); if (withOverload) str << "qOverload<" << parameters << ">("; str << '&' << s.className << "::" << functionName; if (withOverload) str << ')'; } static void formatMemberFnPtrConnection(QTextStream &str, const SignalSlot &sender, const SignalSlot &receiver) { str << "QObject::connect(" << sender.name << ", "; formatMemberFnPtr(str, sender); str << ", " << receiver.name << ", "; formatMemberFnPtr(str, receiver, UseOverloadWhenNoArguments); str << ')'; } static void formatStringBasedConnection(QTextStream &str, const SignalSlot &sender, const SignalSlot &receiver) { str << "QObject::connect(" << sender.name << ", SIGNAL("<< sender.signature << "), " << receiver.name << ", SLOT(" << receiver.signature << "))"; } void formatConnection(QTextStream &str, const SignalSlot &sender, const SignalSlot &receiver, ConnectionSyntax connectionSyntax) { switch (language()) { case Language::Cpp: switch (connectionSyntax) { case ConnectionSyntax::MemberFunctionPtr: formatMemberFnPtrConnection(str, sender, receiver); break; case ConnectionSyntax::StringBased: formatStringBasedConnection(str, sender, receiver); break; } break; case Language::Python: str << sender.name << '.' << QStringView{sender.signature}.left(sender.signature.indexOf(QLatin1Char('('))) << ".connect(" << receiver.name << '.' << QStringView{receiver.signature}.left(receiver.signature.indexOf(QLatin1Char('('))) << ')'; break; } } QString boolValue(bool v) { switch (language()) { case Language::Cpp: return v ? cppTrue : cppFalse; case Language::Python: return v ? QStringLiteral("True") : QStringLiteral("False"); } Q_UNREACHABLE(); } static inline QString dot() { return QStringLiteral("."); } QString enumValue(const QString &value) { if (language() == Language::Cpp || !value.contains(cppQualifier)) return value; QString fixed = value; fixed.replace(cppQualifier, dot()); return fixed; } } // namespace language