Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
uic.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3// Qt-Security score:insignificant reason:build-tool
4
5#include "uic.h"
6#include "ui4.h"
7#include "driver.h"
8#include "option.h"
9#include "treewalker.h"
10#include "validator.h"
11
14#include <pythonwritedeclaration.h>
15#include <pythonwriteimports.h>
16
17#include <language.h>
18
19#include <qxmlstream.h>
20#include <qfileinfo.h>
21#include <qscopedpointer.h>
22#include <qtextstream.h>
23
25
26using namespace Qt::StringLiterals;
27
28Uic::Uic(Driver *d)
29 : drv(d),
30 out(d->output()),
31 opt(d->option())
32{
33}
34
35Uic::~Uic() = default;
36
38{
39 QString fileName = opt.inputFile;
40
41 QFile f;
42 if (fileName.isEmpty()) {
43 if (!f.open(stdin, QIODevice::ReadOnly))
44 return false;
45 } else {
46 f.setFileName(fileName);
47 if (!f.open(QIODevice::ReadOnly))
48 return false;
49 }
50
51 DomUI *ui = nullptr;
52 {
53 QXmlStreamReader reader;
54 reader.setDevice(&f);
55 ui = parseUiFile(reader);
56 if (!ui)
57 return false;
58 }
59
60 if (DomIncludes *includes = ui->elementIncludes()) {
61 const auto incls = includes->elementInclude();
62 for (DomInclude *incl : incls) {
63 QString file = incl->text();
64 if (file.isEmpty())
65 continue;
66
67 fprintf(stdout, "%s\n", file.toLocal8Bit().constData());
68 }
69 }
70
71 if (DomCustomWidgets *customWidgets = ui->elementCustomWidgets()) {
72 const auto elementCustomWidget = customWidgets->elementCustomWidget();
73 for (DomCustomWidget *customWidget : elementCustomWidget) {
74 if (DomHeader *header = customWidget->elementHeader()) {
75 QString file = header->text();
76 if (file.isEmpty())
77 continue;
78
79 fprintf(stdout, "%s\n", file.toLocal8Bit().constData());
80 }
81 }
82 }
83
84 delete ui;
85
86 return true;
87}
88
89void Uic::writeCopyrightHeaderCpp(const DomUI *ui) const
90{
91 QString comment = ui->elementComment();
92 if (!comment.isEmpty())
93 out << "/*\n" << comment << "\n*/\n\n";
94
95 out << "/********************************************************************************\n";
96 out << "** Form generated from reading UI file '" << QFileInfo(opt.inputFile).fileName() << "'\n";
97 out << "**\n";
98 out << "** Created by: Qt User Interface Compiler version " << QT_VERSION_STR << "\n";
99 out << "**\n";
100 out << "** WARNING! All changes made in this file will be lost when recompiling UI file!\n";
101 out << "********************************************************************************/\n\n";
102}
103
104// Format existing UI file comments for Python with some smartness : Replace all
105// leading C++ comment characters by '#' or prepend '#' if needed.
106
107static inline bool isCppCommentChar(QChar c)
108{
109 return c == u'/' || c == u'*';
110}
111
113{
114 qsizetype i = 0;
115 for (const qsizetype size = s.size(); i < size && isCppCommentChar(s.at(i)); ++i) {
116 }
117 return i;
118}
119
120void Uic::writeCopyrightHeaderPython(const DomUI *ui) const
121{
122 QString comment = ui->elementComment();
123 if (!comment.isEmpty()) {
124 const auto lines = QStringView{comment}.split(u'\n');
125 for (const auto &line : lines) {
126 if (const auto leadingCommentChars = leadingCppCommentCharCount(line)) {
127 out << language::repeat(leadingCommentChars, '#')
128 << line.right(line.size() - leadingCommentChars);
129 } else {
130 if (!line.startsWith(u'#'))
131 out << "# ";
132 out << line;
133 }
134 out << '\n';
135 }
136 out << '\n';
137 }
138
139 out << language::repeat(80, '#') << "\n## Form generated from reading UI file '"
140 << QFileInfo(opt.inputFile).fileName()
141 << "'\n##\n## Created by: Qt User Interface Compiler version " << QT_VERSION_STR
142 << "\n##\n## WARNING! All changes made in this file will be lost when recompiling UI file!\n"
143 << language::repeat(80, '#') << "\n\n";
144}
145
146// Check the version with a stream reader at the <ui> element.
147
148static double versionFromUiAttribute(QXmlStreamReader &reader)
149{
150 const QXmlStreamAttributes attributes = reader.attributes();
151 const auto versionAttribute = "version"_L1;
152 if (!attributes.hasAttribute(versionAttribute))
153 return 4.0;
154 const QStringView version = attributes.value(versionAttribute);
155 return version.toDouble();
156}
157
158DomUI *Uic::parseUiFile(QXmlStreamReader &reader)
159{
160 DomUI *ui = nullptr;
161
162 const auto uiElement = "ui"_L1;
163 while (!reader.atEnd()) {
164 if (reader.readNext() == QXmlStreamReader::StartElement) {
165 if (reader.name().compare(uiElement, Qt::CaseInsensitive) == 0
166 && !ui) {
167 const double version = versionFromUiAttribute(reader);
168 if (version < 4.0) {
169 const QString msg = QString::fromLatin1("uic: File generated with too old version of Qt Widgets Designer (%1)").arg(version);
170 fprintf(stderr, "%s\n", qPrintable(msg));
171 return nullptr;
172 }
173
174 ui = new DomUI();
175 ui->read(reader);
176 } else {
177 reader.raiseError("Unexpected element "_L1 + reader.name().toString());
178 }
179 }
180 }
181 if (reader.hasError()) {
182 delete ui;
183 ui = nullptr;
184 fprintf(stderr, "%s\n", qPrintable(QString::fromLatin1("uic: Error in line %1, column %2 : %3")
185 .arg(reader.lineNumber()).arg(reader.columnNumber())
186 .arg(reader.errorString())));
187 }
188
189 return ui;
190}
191
192bool Uic::write(QIODevice *in)
193{
194 QScopedPointer<DomUI> ui;
195 {
196 QXmlStreamReader reader;
197 reader.setDevice(in);
198 ui.reset(parseUiFile(reader));
199 }
200
201 if (ui.isNull())
202 return false;
203
204 double version = ui->attributeVersion().toDouble();
205 if (version < 4.0) {
206 fprintf(stderr, "uic: File generated with too old version of Qt Widgets Designer\n");
207 return false;
208 }
209
210 const QString &language = ui->attributeLanguage();
211 driver()->setUseIdBasedTranslations(ui->attributeIdbasedtr());
212
213 if (!language.isEmpty() && language.compare("c++"_L1, Qt::CaseInsensitive) != 0) {
214 fprintf(stderr, "uic: File is not a \"c++\" ui file, language=%s\n", qPrintable(language));
215 return false;
216 }
217
218 return write(ui.data());
219}
220
221bool Uic::write(DomUI *ui)
222{
223 if (!ui || !ui->elementWidget())
224 return false;
225
226 {
227 Validator validator(this);
228 validator.acceptUI(ui);
229 if (!validator.errors().isEmpty()) {
230 for (const QString &error : validator.errors())
231 fprintf(stderr, "%s: %s\n", qPrintable(opt.messagePrefix()), qPrintable(error));
232 return false;
233 }
234 }
235
236 const auto lang = language::language();
237
238 if (lang == Language::Python)
239 out << "# -*- coding: utf-8 -*-\n\n";
240
241 if (opt.copyrightHeader) {
242 switch (language::language()) {
243 case Language::Cpp:
244 writeCopyrightHeaderCpp(ui);
245 break;
246 case Language::Python:
247 writeCopyrightHeaderPython(ui);
248 break;
249 }
250 }
251
252 if (opt.headerProtection && lang == Language::Cpp) {
253 writeHeaderProtectionStart();
254 out << "\n";
255 }
256
257 pixFunction = ui->elementPixmapFunction();
258 if (pixFunction == "QPixmap::fromMimeSource"_L1 || pixFunction == "qPixmapFromMimeSource"_L1) {
259 fprintf(stderr, "%s: Warning: Obsolete pixmap function '%s' specified in the UI file.\n",
260 qPrintable(opt.messagePrefix()), qPrintable(pixFunction));
261 pixFunction.clear();
262 }
263
264 info.acceptUI(ui);
265 cWidgetsInfo.acceptUI(ui);
266
267 switch (language::language()) {
268 case Language::Cpp: {
269 CPP::WriteIncludes writeIncludes(this);
270 writeIncludes.acceptUI(ui);
272 }
273 break;
274 case Language::Python: {
275 Python::WriteImports writeImports(this);
276 writeImports.acceptUI(ui);
278 }
279 break;
280 }
281
282 if (opt.headerProtection && lang == Language::Cpp)
283 writeHeaderProtectionEnd();
284
285 return true;
286}
287
288void Uic::writeHeaderProtectionStart()
289{
290 QString h = drv->headerFileName();
291 out << "#ifndef " << h << "\n"
292 << "#define " << h << "\n";
293}
294
295void Uic::writeHeaderProtectionEnd()
296{
297 QString h = drv->headerFileName();
298 out << "#endif // " << h << "\n";
299}
300
301bool Uic::isButton(const QString &className) const
302{
303 static const QStringList buttons = {
304 u"QRadioButton"_s, u"QToolButton"_s,
305 u"QCheckBox"_s, u"QPushButton"_s,
306 u"QCommandLinkButton"_s
307 };
308 return customWidgetsInfo()->extendsOneOf(className, buttons);
309}
310
311bool Uic::isContainer(const QString &className) const
312{
313 static const QStringList containers = {
314 u"QStackedWidget"_s, u"QToolBox"_s,
315 u"QTabWidget"_s, u"QScrollArea"_s,
316 u"QMdiArea"_s, u"QWizard"_s,
317 u"QDockWidget"_s
318 };
319
320 return customWidgetsInfo()->extendsOneOf(className, containers);
321}
322
323bool Uic::isMenu(const QString &className) const
324{
325 static const QStringList menus = {
326 u"QMenu"_s, u"QPopupMenu"_s
327 };
328 return customWidgetsInfo()->extendsOneOf(className, menus);
329}
330
331QT_END_NAMESPACE
void acceptUI(DomUI *node) override
QTextStream & output() const
Definition driver.h:39
void setUseIdBasedTranslations(bool u)
Definition driver.h:69
Option & option()
Definition driver.h:40
void acceptUI(DomUI *node) override
Definition uic.h:31
bool printDependencies()
Definition uic.cpp:37
bool isButton(const QString &className) const
Definition uic.cpp:301
~Uic()
bool write(QIODevice *in)
Definition uic.cpp:192
const CustomWidgetsInfo * customWidgetsInfo() const
Definition uic.h:57
bool write(DomUI *ui)
Definition uic.cpp:221
bool isMenu(const QString &className) const
Definition uic.cpp:323
bool isContainer(const QString &className) const
Definition uic.cpp:311
Driver * driver() const
Definition uic.h:39
Language
Definition language.h:13
Combined button and popup list for selecting options.
const QString & asString(const QString &s)
Definition qstring.h:1700
Language language()
Definition language.cpp:19
#define qPrintable(string)
Definition qstring.h:1705
void acceptUI(DomUI *node) override
unsigned int headerProtection
Definition option.h:21
unsigned int copyrightHeader
Definition option.h:22
void acceptUI(DomUI *node) override
void acceptUI(DomUI *node) override
Validator(Uic *uic)
static double versionFromUiAttribute(QXmlStreamReader &reader)
Definition uic.cpp:148
static qsizetype leadingCppCommentCharCount(QStringView s)
Definition uic.cpp:112
static bool isCppCommentChar(QChar c)
Definition uic.cpp:107