1 /****************************************************************************
2 **
3 ** Copyright (C) 2018 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the tools applications of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21 ** included in the packaging of this file. Please review the following
22 ** information to ensure the GNU General Public License requirements will
23 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24 **
25 ** $QT_END_LICENSE$
26 **
27 ****************************************************************************/
28
29 #include "language.h"
30
31 #include <QtCore/qtextstream.h>
32
33 namespace language {
34
35 static Encoding encoding = Encoding::Utf8;
36 static Language _language = Language::Cpp;
37
language()38 Language language() { return _language; }
39
setLanguage(Language l)40 void setLanguage(Language l)
41 {
42 _language = l;
43 switch (_language) {
44 case Language::Cpp:
45 derefPointer = QLatin1String("->");
46 nullPtr = QLatin1String("nullptr");
47 operatorNew = QLatin1String("new ");
48 qtQualifier = QLatin1String("Qt::");
49 qualifier = QLatin1String("::");
50 self = QLatin1String(""); // for testing: change to "this->";
51 eol = QLatin1String(";\n");
52 emptyString = QLatin1String("QString()");
53 encoding = Encoding::Utf8;
54 break;
55 case Language::Python:
56 derefPointer = QLatin1String(".");
57 nullPtr = QLatin1String("None");
58 operatorNew = QLatin1String("");
59 qtQualifier = QLatin1String("Qt.");
60 qualifier = QLatin1String(".");
61 self = QLatin1String("self.");
62 eol = QLatin1String("\n");
63 emptyString = QLatin1String("\"\"");
64 encoding = Encoding::Unicode;
65 break;
66 }
67 }
68
69 QString derefPointer;
70 QString nullPtr;
71 QString operatorNew;
72 QString qtQualifier;
73 QString qualifier;
74 QString self;
75 QString eol;
76 QString emptyString;
77
78 QString cppQualifier = QLatin1String("::");
79 QString cppTrue = QLatin1String("true");
80 QString cppFalse = QLatin1String("false");
81
operator <<(QTextStream & str,const qtConfig & c)82 QTextStream &operator<<(QTextStream &str, const qtConfig &c)
83 {
84 str << "QT_CONFIG(" << c.parameter() << ')';
85 return str;
86 }
87
operator <<(QTextStream & str,const openQtConfig & c)88 QTextStream &operator<<(QTextStream &str, const openQtConfig &c)
89 {
90 str << "#if " << qtConfig(c.parameter()) << '\n';
91 return str;
92 }
93
operator <<(QTextStream & str,const closeQtConfig & c)94 QTextStream &operator<<(QTextStream &str, const closeQtConfig &c)
95 {
96 str << "#endif // " << qtConfig(c.parameter()) << '\n';
97 return str;
98 }
99
100 struct EnumLookup
101 {
102 int value;
103 const char *valueString;
104 };
105
106 template <int N>
lookupEnum(const EnumLookup (& array)[N],int value,int defaultIndex=0)107 const char *lookupEnum(const EnumLookup(&array)[N], int value, int defaultIndex = 0)
108 {
109 for (int i = 0; i < N; ++i) {
110 if (value == array[i].value)
111 return array[i].valueString;
112 }
113 const char *defaultValue = array[defaultIndex].valueString;
114 qWarning("uic: Warning: Invalid enumeration value %d, defaulting to %s",
115 value, defaultValue);
116 return defaultValue;
117 }
118
fixClassName(QString className)119 QString fixClassName(QString className)
120 {
121 if (language() == Language::Python)
122 className.replace(cppQualifier, QLatin1String("_"));
123 return className;
124 }
125
toolbarArea(int v)126 const char *toolbarArea(int v)
127 {
128 static const EnumLookup toolBarAreas[] =
129 {
130 {0, "NoToolBarArea"},
131 {0x1, "LeftToolBarArea"},
132 {0x2, "RightToolBarArea"},
133 {0x4, "TopToolBarArea"},
134 {0x8, "BottomToolBarArea"},
135 {0xf, "AllToolBarAreas"}
136 };
137 return lookupEnum(toolBarAreas, v);
138 }
139
sizePolicy(int v)140 const char *sizePolicy(int v)
141 {
142 static const EnumLookup sizePolicies[] =
143 {
144 {0, "Fixed"},
145 {0x1, "Minimum"},
146 {0x4, "Maximum"},
147 {0x5, "Preferred"},
148 {0x3, "MinimumExpanding"},
149 {0x7, "Expanding"},
150 {0xD, "Ignored"}
151 };
152 return lookupEnum(sizePolicies, v, 3);
153 }
154
dockWidgetArea(int v)155 const char *dockWidgetArea(int v)
156 {
157 static const EnumLookup dockWidgetAreas[] =
158 {
159 {0, "NoDockWidgetArea"},
160 {0x1, "LeftDockWidgetArea"},
161 {0x2, "RightDockWidgetArea"},
162 {0x4, "TopDockWidgetArea"},
163 {0x8, "BottomDockWidgetArea"},
164 {0xf, "AllDockWidgetAreas"}
165 };
166 return lookupEnum(dockWidgetAreas, v);
167 }
168
paletteColorRole(int v)169 const char *paletteColorRole(int v)
170 {
171 static const EnumLookup colorRoles[] =
172 {
173 {0, "WindowText"},
174 {1, "Button"},
175 {2, "Light"},
176 {3, "Midlight"},
177 {4, "Dark"},
178 {5, "Mid"},
179 {6, "Text"},
180 {7, "BrightText"},
181 {8, "ButtonText"},
182 {9, "Base"},
183 {10, "Window"},
184 {11, "Shadow"},
185 {12, "Highlight"},
186 {13, "HighlightedText"},
187 {14, "Link"},
188 {15, "LinkVisited"},
189 {16, "AlternateBase"},
190 {17, "NoRole"},
191 {18, "ToolTipBase"},
192 {19, "ToolTipText"},
193 {20, "PlaceholderText"},
194 };
195 return lookupEnum(colorRoles, v);
196 }
197
198 // Helpers for formatting a character sequences
199
200 // Format a special character like '\x0a'
formatEscapedNumber(QTextStream & str,ushort value,int base,int width,char prefix=0)201 static int formatEscapedNumber(QTextStream &str, ushort value, int base, int width,
202 char prefix = 0)
203 {
204 int length = 1 + width;
205 str << '\\';
206 if (prefix) {
207 str << prefix;
208 ++length;
209 }
210 const auto oldPadChar = str.padChar();
211 const auto oldFieldWidth = str.fieldWidth();
212 const auto oldFieldAlignment = str.fieldAlignment();
213 const auto oldIntegerBase = str.integerBase();
214 str.setPadChar(QLatin1Char('0'));
215 str.setFieldWidth(width);
216 str.setFieldAlignment(QTextStream::AlignRight);
217 str.setIntegerBase(base);
218 str << value;
219 str.setIntegerBase(oldIntegerBase);
220 str.setFieldAlignment(oldFieldAlignment);
221 str.setFieldWidth(oldFieldWidth);
222 str.setPadChar(oldPadChar);
223 return length;
224 }
225
formatSpecialCharacter(QTextStream & str,ushort value)226 static int formatSpecialCharacter(QTextStream &str, ushort value)
227 {
228 int length = 0;
229 switch (value) {
230 case '\\':
231 str << "\\\\";
232 length += 2;
233 break;
234 case '\"':
235 str << "\\\"";
236 length += 2;
237 break;
238 case '\n':
239 str << "\\n\"\n\"";
240 length += 5;
241 break;
242 default:
243 break;
244 }
245 return length;
246 }
247
248 // Format a sequence of characters for C++ with special characters numerically
249 // escaped (non-raw string literals), wrappped at maxSegmentSize. FormattingTraits
250 // are used to transform characters into (unsigned) codes, which can be used
251 // for either normal escapes or Unicode code points as used in Unicode literals.
252
253 enum : int { maxSegmentSize = 1024 };
254
255 template <Encoding e>
256 struct FormattingTraits
257 {
258 };
259
260 template <>
261 struct FormattingTraits<Encoding::Utf8>
262 {
codelanguage::FormattingTraits263 static ushort code(char c) { return uchar(c); }
264 };
265
266 template <>
267 struct FormattingTraits<Encoding::Unicode>
268 {
codelanguage::FormattingTraits269 static ushort code(QChar c) { return c.unicode(); }
270 };
271
272 template <Encoding e, class Iterator>
formatStringSequence(QTextStream & str,Iterator it,Iterator end,const QString & indent,int escapeIntegerBase,int escapeWidth,char escapePrefix=0)273 static void formatStringSequence(QTextStream &str, Iterator it, Iterator end,
274 const QString &indent,
275 int escapeIntegerBase, int escapeWidth,
276 char escapePrefix = 0)
277 {
278 str << '"';
279 int length = 0;
280 while (it != end) {
281 const auto code = FormattingTraits<e>::code(*it);
282 if (code >= 0x80) {
283 length += formatEscapedNumber(str, code, escapeIntegerBase, escapeWidth, escapePrefix);
284 } else if (const int l = formatSpecialCharacter(str, code)) {
285 length += l;
286 } else if (code != '\r') {
287 str << *it;
288 ++length;
289 }
290 ++it;
291 if (it != end && length > maxSegmentSize) {
292 str << "\"\n" << indent << indent << '"';
293 length = 0;
294 }
295 }
296 str << '"';
297 }
298
_formatString(QTextStream & str,const QString & value,const QString & indent,bool qString)299 void _formatString(QTextStream &str, const QString &value, const QString &indent,
300 bool qString)
301 {
302 switch (encoding) {
303 // Special characters as 3 digit octal escapes (u8"\303\234mlaut")
304 case Encoding::Utf8: {
305 if (qString && _language == Language::Cpp)
306 str << "QString::fromUtf8(";
307 const QByteArray utf8 = value.toUtf8();
308 formatStringSequence<Encoding::Utf8>(str, utf8.cbegin(), utf8.cend(), indent,
309 8, 3);
310 if (qString && _language == Language::Cpp)
311 str << ')';
312 }
313 break;
314 // Special characters as 4 digit hex Unicode points (u8"\u00dcmlaut")
315 case Encoding::Unicode:
316 str << 'u'; // Python Unicode literal (would be UTF-16 in C++)
317 formatStringSequence<Encoding::Unicode>(str, value.cbegin(), value.cend(), indent,
318 16, 4, 'u');
319 break;
320 }
321 }
322
operator <<(QTextStream & str,const repeat & r)323 QTextStream &operator<<(QTextStream &str, const repeat &r)
324 {
325 for (int i = 0; i < r.m_count; ++i)
326 str << r.m_char;
327 return str;
328 }
329
startFunctionDefinition1(const char * name,const QString & parameterType,const QString & parameterName,const QString & indent,const char * returnType)330 startFunctionDefinition1::startFunctionDefinition1(const char *name, const QString ¶meterType,
331 const QString ¶meterName,
332 const QString &indent,
333 const char *returnType) :
334 m_name(name), m_parameterType(parameterType), m_parameterName(parameterName),
335 m_indent(indent), m_return(returnType)
336 {
337 }
338
operator <<(QTextStream & str,const startFunctionDefinition1 & f)339 QTextStream &operator<<(QTextStream &str, const startFunctionDefinition1 &f)
340 {
341 switch (language()) {
342 case Language::Cpp:
343 str << (f.m_return ? f.m_return : "void") << ' ' << f.m_name << '('
344 << f.m_parameterType;
345 if (f.m_parameterType.cend()->isLetter())
346 str << ' ';
347 str << f.m_parameterName << ')' << '\n' << f.m_indent << "{\n";
348 break;
349 case Language::Python:
350 str << "def " << f.m_name << "(self, " << f.m_parameterName << "):\n";
351 break;
352 }
353 return str;
354 }
355
endFunctionDefinition(const char * name)356 endFunctionDefinition::endFunctionDefinition(const char *name) : m_name(name)
357 {
358 }
359
operator <<(QTextStream & str,const endFunctionDefinition & f)360 QTextStream &operator<<(QTextStream &str, const endFunctionDefinition &f)
361 {
362 switch (language()) {
363 case Language::Cpp:
364 str << "} // " << f.m_name << "\n\n";
365 break;
366 case Language::Python:
367 str << "# " << f.m_name << "\n\n";
368 break;
369 }
370 return str;
371 }
372
_formatStackVariable(QTextStream & str,const char * className,QStringView varName,bool withInitParameters)373 void _formatStackVariable(QTextStream &str, const char *className, QStringView varName,
374 bool withInitParameters)
375 {
376 switch (language()) {
377 case Language::Cpp:
378 str << className << ' ' << varName;
379 if (withInitParameters)
380 str << '(';
381 break;
382 case Language::Python:
383 str << varName << " = " << className << '(';
384 if (!withInitParameters)
385 str << ')';
386 break;
387 }
388 }
389
formatConnection(QTextStream & str,const SignalSlot & sender,const SignalSlot & receiver)390 void formatConnection(QTextStream &str, const SignalSlot &sender, const SignalSlot &receiver)
391 {
392 switch (language()) {
393 case Language::Cpp:
394 str << "QObject::connect(" << sender.name << ", SIGNAL("<< sender.signature
395 << "), " << receiver.name << ", SLOT("<< receiver.signature << "))";
396 break;
397 case Language::Python:
398 str << sender.name << '.'
399 << sender.signature.leftRef(sender.signature.indexOf(QLatin1Char('(')))
400 << ".connect(" << receiver.name << '.'
401 << receiver.signature.leftRef(receiver.signature.indexOf(QLatin1Char('(')))
402 << ')';
403 break;
404 }
405 }
406
boolValue(bool v)407 QString boolValue(bool v)
408 {
409 switch (language()) {
410 case Language::Cpp:
411 return v ? cppTrue : cppFalse;
412 case Language::Python:
413 return v ? QStringLiteral("True") : QStringLiteral("False");
414 }
415 Q_UNREACHABLE();
416 }
417
dot()418 static inline QString dot() { return QStringLiteral("."); }
419
enumValue(const QString & value)420 QString enumValue(const QString &value)
421 {
422 if (language() == Language::Cpp || !value.contains(cppQualifier))
423 return value;
424 QString fixed = value;
425 fixed.replace(cppQualifier, dot());
426 return fixed;
427 }
428
429 } // namespace language
430