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
driver.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 "driver.h"
6#include "uic.h"
7#include "ui4.h"
8
9#include <language.h>
10
11#include <qfileinfo.h>
12#include <qdebug.h>
13
14#include <algorithm>
15
17
18using namespace Qt::StringLiterals;
19
20Driver::Driver()
21 : m_stdout(stdout, QFile::WriteOnly | QFile::Text),
22 m_output(&m_stdout)
23{
24}
25
26Driver::~Driver() = default;
27
28static inline QString spacerItemClass() { return QStringLiteral("QSpacerItem"); }
29static inline QString actionGroupClass() { return QStringLiteral("QActionGroup"); }
30static inline QString actionClass() { return QStringLiteral("QAction"); }
31static inline QString buttonGroupClass() { return QStringLiteral("QButtonGroup"); }
32
33template <class DomClass>
34Driver::DomObjectHashConstIt<DomClass>
35 Driver::findByAttributeNameIt(const DomObjectHash<DomClass> &domHash,
36 const QString &name) const
37{
38 const auto end = domHash.cend();
39 for (auto it = domHash.cbegin(); it != end; ++it) {
40 if (it.key()->attributeName() == name)
41 return it;
42 }
43 return end;
44}
45
46template <class DomClass>
47const DomClass *Driver::findByAttributeName(const DomObjectHash<DomClass> &domHash,
48 const QString &name) const
49{
50 auto it = findByAttributeNameIt(domHash, name);
51 return it != domHash.cend() ? it.key() : nullptr;
52}
53
54template <class DomClass>
55QString Driver::findOrInsert(DomObjectHash<DomClass> *domHash, const DomClass *dom,
56 const QString &className, bool isMember)
57{
58 auto it = domHash->find(dom);
59 if (it == domHash->end()) {
60 const QString name = this->unique(dom->attributeName(), className);
61 it = domHash->insert(dom, isMember ? language::self + name : name);
62 }
63 return it.value();
64}
65
66QString Driver::findOrInsertWidget(const DomWidget *ui_widget)
67{
68 // Top level is passed into setupUI(), everything else is a member variable
69 const bool isMember = !m_widgets.isEmpty();
70 return findOrInsert(&m_widgets, ui_widget, ui_widget->attributeClass(), isMember);
71}
72
73QString Driver::findOrInsertSpacer(const DomSpacer *ui_spacer)
74{
75 return findOrInsert(&m_spacers, ui_spacer, spacerItemClass());
76}
77
78QString Driver::findOrInsertLayout(const DomLayout *ui_layout)
79{
80 return findOrInsert(&m_layouts, ui_layout, ui_layout->attributeClass());
81}
82
83QString Driver::findOrInsertLayoutItem(const DomLayoutItem *ui_layoutItem)
84{
85 switch (ui_layoutItem->kind()) {
86 case DomLayoutItem::Widget:
87 return findOrInsertWidget(ui_layoutItem->elementWidget());
88 case DomLayoutItem::Spacer:
89 return findOrInsertSpacer(ui_layoutItem->elementSpacer());
90 case DomLayoutItem::Layout:
91 return findOrInsertLayout(ui_layoutItem->elementLayout());
92 case DomLayoutItem::Unknown:
93 break;
94 }
95
96 Q_ASSERT( 0 );
97
98 return {};
99}
100
101QString Driver::findOrInsertActionGroup(const DomActionGroup *ui_group)
102{
103 return findOrInsert(&m_actionGroups, ui_group, actionGroupClass());
104}
105
106QString Driver::findOrInsertAction(const DomAction *ui_action)
107{
108 return findOrInsert(&m_actions, ui_action, actionClass());
109}
110
111QString Driver::findOrInsertButtonGroup(const DomButtonGroup *ui_group)
112{
113 return findOrInsert(&m_buttonGroups, ui_group, buttonGroupClass());
114}
115
116// Find a group by its non-uniqified name
117const DomButtonGroup *Driver::findButtonGroup(const QString &attributeName) const
118{
119 return findByAttributeName(m_buttonGroups, attributeName);
120}
121
122
123QString Driver::findOrInsertName(const QString &name)
124{
125 return unique(name);
126}
127
128QString Driver::normalizedName(const QString &name)
129{
130 QString result = name;
131 std::replace_if(result.begin(), result.end(),
132 [] (QChar c) { return !c.isLetterOrNumber(); },
133 u'_');
134 return result;
135}
136
137QString Driver::unique(const QString &instanceName, const QString &className)
138{
139 QString name;
140 bool alreadyUsed = false;
141
142 if (!instanceName.isEmpty()) {
143 name = normalizedName(instanceName);
144 QString base = name;
145
146 for (int id = 1; m_nameRepository.contains(name); ++id) {
147 alreadyUsed = true;
148 name = base + QString::number(id);
149 }
150 } else if (!className.isEmpty()) {
151 name = unique(qtify(className));
152 } else {
153 name = unique("var"_L1);
154 }
155
156 if (alreadyUsed && !className.isEmpty()) {
157 fprintf(stderr, "%s: Warning: The name '%s' (%s) is already in use, defaulting to '%s'.\n",
158 qPrintable(m_option.messagePrefix()),
159 qPrintable(instanceName), qPrintable(className),
160 qPrintable(name));
161 }
162
163 m_nameRepository.insert(name, true);
164 return name;
165}
166
167QString Driver::qtify(const QString &name)
168{
169 QString qname = name;
170
171 if (qname.at(0) == u'Q' || qname.at(0) == u'K')
172 qname.remove(0, 1);
173
174 for (qsizetype i = 0, size = qname.size(); i < size && qname.at(i).isUpper(); ++i)
175 qname[i] = qname.at(i).toLower();
176
177 return qname;
178}
179
180static bool isAnsiCCharacter(QChar c)
181{
182 return (c.toUpper() >= u'A' && c.toUpper() <= u'Z') || c.isDigit() || c == u'_';
183}
184
185QString Driver::headerFileName() const
186{
187 QString name = m_option.outputFile;
188
189 if (name.isEmpty()) {
190 name = "ui_"_L1; // ### use ui_ as prefix.
191 name.append(m_option.inputFile);
192 }
193
194 return headerFileName(name);
195}
196
197QString Driver::headerFileName(const QString &fileName)
198{
199 if (fileName.isEmpty())
200 return headerFileName(u"noname"_s);
201
202 QFileInfo info(fileName);
203 QString baseName = info.baseName();
204 // Transform into a valid C++ identifier
205 if (!baseName.isEmpty() && baseName.at(0).isDigit())
206 baseName.prepend(u'_');
207 for (qsizetype i = 0; i < baseName.size(); ++i) {
208 QChar c = baseName.at(i);
209 if (!isAnsiCCharacter(c)) {
210 // Replace character by its unicode value
211 QString hex = QString::number(c.unicode(), 16);
212 baseName.replace(i, 1, u'_' + hex + u'_');
213 i += hex.size() + 1;
214 }
215 }
216 return baseName.toUpper() + "_H"_L1;
217}
218
219bool Driver::printDependencies(const QString &fileName)
220{
221 Q_ASSERT(m_option.dependencies == true);
222
223 m_option.inputFile = fileName;
224
225 Uic tool(this);
226 return tool.printDependencies();
227}
228
229bool Driver::uic(const QString &fileName, DomUI *ui, QTextStream *out)
230{
231 m_option.inputFile = fileName;
232 setUseIdBasedTranslations(ui->attributeIdbasedtr());
233
234 QTextStream *oldOutput = m_output;
235
236 m_output = out != nullptr ? out : &m_stdout;
237
238 Uic tool(this);
239 const bool result = tool.write(ui);
240
241 m_output = oldOutput;
242
243 return result;
244}
245
246bool Driver::uic(const QString &fileName, QTextStream *out)
247{
248 QFile f;
249 if (fileName.isEmpty()) {
250 if (!f.open(stdin, QIODevice::ReadOnly))
251 return false;
252 } else {
253 f.setFileName(fileName);
254 if (!f.open(QIODevice::ReadOnly))
255 return false;
256 }
257
258 m_option.inputFile = fileName;
259
260 QTextStream *oldOutput = m_output;
261 bool deleteOutput = false;
262
263 if (out) {
264 m_output = out;
265 } else {
266#ifdef Q_OS_WIN
267 // As one might also redirect the output to a file on win,
268 // we should not create the textstream with QFile::Text flag.
269 // The redirected file is opened in TextMode and this will
270 // result in broken line endings as writing will replace \n again.
271 m_output = new QTextStream(stdout, QIODevice::WriteOnly);
272#else
273 m_output = new QTextStream(stdout, QIODevice::WriteOnly | QFile::Text);
274#endif
275 deleteOutput = true;
276 }
277
278 Uic tool(this);
279 bool rtn = tool.write(&f);
280 f.close();
281
282 if (deleteOutput)
283 delete m_output;
284
285 m_output = oldOutput;
286
287 return rtn;
288}
289
290const DomWidget *Driver::widgetByName(const QString &attributeName) const
291{
292 return findByAttributeName(m_widgets, attributeName);
293}
294
295QString Driver::widgetVariableName(const QString &attributeName) const
296{
297 auto it = findByAttributeNameIt(m_widgets, attributeName);
298 return it != m_widgets.cend() ? it.value() : QString();
299}
300
301const DomActionGroup *Driver::actionGroupByName(const QString &attributeName) const
302{
303 return findByAttributeName(m_actionGroups, attributeName);
304}
305
306const DomAction *Driver::actionByName(const QString &attributeName) const
307{
308 return findByAttributeName(m_actions, attributeName);
309}
310
311QT_END_NAMESPACE
bool uic(const QString &fileName, QTextStream *output=nullptr)
Definition driver.cpp:246
void setUseIdBasedTranslations(bool u)
Definition driver.h:69
const DomAction * actionByName(const QString &attributeName) const
Definition driver.cpp:306
QString widgetVariableName(const QString &attributeName) const
Definition driver.cpp:295
static QString qtify(const QString &name)
Definition driver.cpp:167
const DomActionGroup * actionGroupByName(const QString &attributeName) const
Definition driver.cpp:301
QString unique(const QString &instanceName=QString(), const QString &className=QString())
Definition driver.cpp:137
QString findOrInsertButtonGroup(const DomButtonGroup *ui_group)
Definition driver.cpp:111
static QString normalizedName(const QString &name)
Definition driver.cpp:128
QString findOrInsertWidget(const DomWidget *ui_widget)
Definition driver.cpp:66
const DomWidget * widgetByName(const QString &attributeName) const
Definition driver.cpp:290
QString findOrInsertActionGroup(const DomActionGroup *ui_group)
Definition driver.cpp:101
bool uic(const QString &fileName, DomUI *ui, QTextStream *output=nullptr)
Definition driver.cpp:229
static QString headerFileName(const QString &fileName)
Definition driver.cpp:197
QString findOrInsertLayoutItem(const DomLayoutItem *ui_layoutItem)
Definition driver.cpp:83
virtual ~Driver()
const DomButtonGroup * findButtonGroup(const QString &attributeName) const
Definition driver.cpp:117
QString headerFileName() const
Definition driver.cpp:185
QString findOrInsertAction(const DomAction *ui_action)
Definition driver.cpp:106
QString findOrInsertLayout(const DomLayout *ui_layout)
Definition driver.cpp:78
QString findOrInsertSpacer(const DomSpacer *ui_spacer)
Definition driver.cpp:73
QString findOrInsertName(const QString &name)
Definition driver.cpp:123
bool printDependencies(const QString &fileName)
Definition driver.cpp:219
Definition uic.h:31
bool printDependencies()
Definition uic.cpp:37
bool write(DomUI *ui)
Definition uic.cpp:221
static QString buttonGroupClass()
Definition driver.cpp:31
static bool isAnsiCCharacter(QChar c)
Definition driver.cpp:180
static QString spacerItemClass()
Definition driver.cpp:28
static QString actionGroupClass()
Definition driver.cpp:29
static QString actionClass()
Definition driver.cpp:30
Combined button and popup list for selecting options.
const QString & asString(const QString &s)
Definition qstring.h:1700
QString self
Definition language.cpp:61
#define qPrintable(string)
Definition qstring.h:1705
#define QStringLiteral(str)
Definition qstring.h:1847