Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
pythonwriteimports.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
5
6#include <customwidgetsinfo.h>
7#include <option.h>
8#include <uic.h>
9#include <driver.h>
10
11#include <ui4.h>
12
13#include <QtCore/qdir.h>
14#include <QtCore/qfileinfo.h>
15#include <QtCore/qtextstream.h>
16
17#include <algorithm>
18
20
21using namespace Qt::StringLiterals;
22
23// Generate imports for Python. Note some things differ from C++:
24// - qItemView->header()->setFoo() does not require QHeaderView to be imported
25// - qLabel->setFrameShape(QFrame::Box) however requires QFrame to be imported
26// (see acceptProperty())
27
28namespace Python {
29
30// Classes required for properties
32{
33 return {
34 {QStringLiteral("QtCore"),
35 {QStringLiteral("QCoreApplication"), QStringLiteral("QDate"),
36 QStringLiteral("QDateTime"), QStringLiteral("QLocale"),
37 QStringLiteral("QMetaObject"), QStringLiteral("QObject"),
38 QStringLiteral("QPoint"), QStringLiteral("QRect"),
39 QStringLiteral("QSize"), QStringLiteral("QTime"),
40 QStringLiteral("QUrl"), QStringLiteral("Qt")},
41 },
42 {QStringLiteral("QtGui"),
43 {QStringLiteral("QBrush"), QStringLiteral("QColor"),
44 QStringLiteral("QConicalGradient"), QStringLiteral("QCursor"),
45 QStringLiteral("QGradient"), QStringLiteral("QFont"),
46 QStringLiteral("QFontDatabase"), QStringLiteral("QIcon"),
47 QStringLiteral("QImage"), QStringLiteral("QKeySequence"),
48 QStringLiteral("QLinearGradient"), QStringLiteral("QPalette"),
49 QStringLiteral("QPainter"), QStringLiteral("QPixmap"),
50 QStringLiteral("QTransform"), QStringLiteral("QRadialGradient")}
51 },
52 // Add QWidget for QWidget.setTabOrder()
53 {QStringLiteral("QtWidgets"),
54 {QStringLiteral("QSizePolicy"), QStringLiteral("QWidget")}
55 }
56 };
57}
58
59// Helpers for WriteImports::ClassesPerModule maps
60static void insertClass(const QString &module, const QString &className,
62{
63 auto usedIt = c->find(module);
64 if (usedIt == c->end())
65 c->insert(module, {className});
66 else if (!usedIt.value().contains(className))
67 usedIt.value().append(className);
68}
69
70// Format a class list: "from A import (B, C)"
72{
73 std::sort(classList.begin(), classList.end());
74
75 const qsizetype size = classList.size();
76 if (size > 1)
77 str << '(';
78 for (qsizetype i = 0; i < size; ++i) {
79 if (i > 0)
80 str << (i % 4 == 0 ? ",\n " : ", ");
81 str << classList.at(i);
82 }
83 if (size > 1)
84 str << ')';
85}
86
88 bool useStarImports = false,
89 const QByteArray &modulePrefix = {})
90{
91 for (auto it = c.cbegin(), end = c.cend(); it != end; ++it) {
92 str << "from " << modulePrefix << it.key() << " import ";
93 if (useStarImports)
94 str << "* # type: ignore";
95 else
96 formatImportClasses(str, it.value());
97 str << '\n';
98 }
99}
100
102 m_qtClasses(defaultClasses())
103{
104 for (const auto &e : classInfoEntries())
105 m_classToModule.insert(QLatin1StringView(e.klass), QLatin1StringView(e.module));
106}
107
109{
111
112 auto &output = uic()->output();
113 const bool useStarImports = uic()->driver()->option().useStarImports;
114
115 const QByteArray qtPrefix = QByteArrayLiteral("PySide")
116 + QByteArray::number(QT_VERSION_MAJOR) + '.';
117
118 formatClasses(output, m_qtClasses, useStarImports, qtPrefix);
119
120 if (!m_customWidgets.isEmpty() || !m_plainCustomWidgets.isEmpty()) {
121 output << '\n';
122 formatClasses(output, m_customWidgets, useStarImports);
123 for (const auto &w : m_plainCustomWidgets)
124 output << "import " << w << '\n';
125 }
126
127 if (auto resources = node->elementResources()) {
128 const auto includes = resources->elementInclude();
129 for (auto include : includes) {
130 if (include->hasAttributeLocation())
131 writeResourceImport(include->attributeLocation());
132 }
133 output << '\n';
134 }
135}
136
137QString WriteImports::resourceAbsolutePath(QString resource) const
138{
139 // If we know the project root, generate an absolute Python import
140 // to the resource. options. pythonRoot is the Python path component
141 // under which the UI file is.
142 const auto &options = uic()->option();
143 if (!options.inputFile.isEmpty() && !options.pythonRoot.isEmpty()) {
144 resource = QDir::cleanPath(QFileInfo(options.inputFile).canonicalPath() + u'/' + resource);
145 if (resource.size() > options.pythonRoot.size())
146 resource.remove(0, options.pythonRoot.size() + 1);
147 }
148 // If nothing is known, we assume the directory pointed by "../" is the root
149 while (resource.startsWith(u"../"))
150 resource.remove(0, 3);
151 resource.replace(u'/', u'.');
152 return resource;
153}
154
155void WriteImports::writeResourceImport(const QString &module)
156{
157 const auto &options = uic()->option();
158 auto &str = uic()->output();
159
160 QString resource = QDir::cleanPath(module);
161 if (resource.endsWith(u".qrc"))
162 resource.chop(4);
163 const qsizetype basePos = resource.lastIndexOf(u'/') + 1;
164 // Change the name of a qrc file "dir/foo.qrc" file to the Python
165 // module name "foo_rc" according to project conventions.
166 if (options.rcPrefix)
167 resource.insert(basePos, u"rc_");
168 else
169 resource.append(u"_rc");
170
171 switch (options.pythonResourceImport) {
173 str << "import " << QStringView{resource}.sliced(basePos) << '\n';
174 break;
176 str << "from . import " << QStringView{resource}.sliced(basePos) << '\n';
177 break;
179 str << "import " << resourceAbsolutePath(resource) << '\n';
180 break;
181 }
182}
183
185{
186 const CustomWidgetsInfo *cwi = uic()->customWidgetsInfo();
187 if (cwi->extends(className, "QListWidget"))
188 add(QStringLiteral("QListWidgetItem"));
189 else if (cwi->extends(className, "QTreeWidget"))
190 add(QStringLiteral("QTreeWidgetItem"));
191 else if (cwi->extends(className, "QTableWidget"))
192 add(QStringLiteral("QTableWidgetItem"));
193
194 if (dcw != nullptr) {
195 addPythonCustomWidget(className, dcw);
196 return;
197 }
198
199 if (!addQtClass(className))
200 qWarning("WriteImports::add(): Unknown Qt class %s", qPrintable(className));
201}
202
203bool WriteImports::addQtClass(const QString &className)
204{
205 // QVariant is not exposed in PySide
206 if (className == u"QVariant" || className == u"Qt")
207 return true;
208
209 const auto moduleIt = m_classToModule.constFind(className);
210 const bool result = moduleIt != m_classToModule.cend();
211 if (result)
212 insertClass(moduleIt.value(), className, &m_qtClasses);
213 return result;
214}
215
216void WriteImports::addPythonCustomWidget(const QString &className, const DomCustomWidget *node)
217{
218 if (className.contains("::"_L1))
219 return; // Exclude namespaced names (just to make tests pass).
220
221 if (addQtClass(className)) // Qt custom widgets like QQuickWidget, QAxWidget, etc
222 return;
223
224 // When the elementHeader is not set, we know it's the continuation
225 // of a Qt for Python import or a normal import of another module.
226 if (!node->elementHeader() || node->elementHeader()->text().isEmpty()) {
227 m_plainCustomWidgets.append(className);
228 } else { // When we do have elementHeader, we know it's a relative import.
229 QString modulePath = node->elementHeader()->text();
230 // Replace the '/' by '.'
231 modulePath.replace(u'/', u'.');
232 // '.h' is added by default on headers for <customwidget>.
233 if (modulePath.endsWith(".h"_L1, Qt::CaseInsensitive))
234 modulePath.chop(2);
235 else if (modulePath.endsWith(".hh"_L1))
236 modulePath.chop(3);
237 else if (modulePath.endsWith(".hpp"_L1))
238 modulePath.chop(4);
239 insertClass(modulePath, className, &m_customWidgets);
240 }
241}
242
244{
245 switch (node->kind()) {
247 addEnumBaseClass(node->elementEnum());
248 break;
249 case DomProperty::Set:
250 addEnumBaseClass(node->elementSet());
251 break;
252 default:
253 break;
254 }
255
257}
258
259void WriteImports::addEnumBaseClass(const QString &v)
260{
261 // Add base classes like QFrame for QLabel::frameShape()
262 const auto colonPos = v.indexOf(u"::");
263 if (colonPos > 0) {
264 const QString base = v.left(colonPos);
265 if (base.startsWith(u'Q') && base != u"Qt")
266 addQtClass(base);
267 }
268}
269
270} // namespace Python
271
DomHeader * elementHeader() const
Definition ui4.h:674
QString text() const
Definition ui4.h:637
QString elementEnum() const
Definition ui4.h:2490
QString elementSet() const
Definition ui4.h:2517
Kind kind() const
Definition ui4.h:2472
Definition ui4.h:116
DomResources * elementResources() const
Definition ui4.h:223
Option & option()
Definition driver.h:39
void acceptUI(DomUI *node) override
void acceptProperty(DomProperty *node) override
void doAdd(const QString &className, const DomCustomWidget *dcw=nullptr) override
\inmodule QtCore
Definition qbytearray.h:57
static QByteArray number(int, int base=10)
Returns a byte-array representing the whole number n as text.
static QString cleanPath(const QString &path)
Returns path with directory separators normalized (that is, platform-native separators converted to "...
Definition qdir.cpp:2398
QString canonicalPath() const
Returns the file system entry's canonical path (excluding the entry's name), i.e.
const_iterator constFind(const Key &key) const noexcept
Definition qhash.h:1299
const_iterator cend() const noexcept
Definition qhash.h:1218
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1303
bool isEmpty() const
Definition qmap.h:269
const_iterator cbegin() const noexcept
Definition qset.h:138
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:78
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.h:296
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5455
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3824
QString sliced(qsizetype pos) const &
Definition qstring.h:394
void chop(qsizetype n)
Removes n characters from the end of the string.
Definition qstring.cpp:6340
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition qstring.cpp:5506
QString & insert(qsizetype i, QChar c)
Definition qstring.cpp:3132
QString & append(QChar c)
Definition qstring.cpp:3252
QString & remove(qsizetype i, qsizetype len)
Removes n characters from the string, starting at the given position index, and returns a reference t...
Definition qstring.cpp:3466
\inmodule QtCore
Definition uic.h:30
QTextStream & output()
Definition uic.h:41
const CustomWidgetsInfo * customWidgetsInfo() const
Definition uic.h:56
const Option & option() const
Definition uic.h:44
Driver * driver() const
Definition uic.h:38
void add(const QString &className, const DomCustomWidget *dcw=nullptr)
const Uic * uic() const
void acceptUI(DomUI *node) override
void acceptProperty(DomProperty *node) override
QString str
[2]
QSet< QString >::iterator it
static void formatImportClasses(QTextStream &str, QStringList classList)
static void insertClass(const QString &module, const QString &className, WriteImports::ClassesPerModule *c)
static void formatClasses(QTextStream &str, const WriteImports::ClassesPerModule &c, bool useStarImports=false, const QByteArray &modulePrefix={})
static WriteImports::ClassesPerModule defaultClasses()
Combined button and popup list for selecting options.
@ CaseInsensitive
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
#define qWarning
Definition qlogging.h:166
GLsizei const GLfloat * v
[13]
GLfloat GLfloat GLfloat w
[0]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLuint end
const GLubyte * c
GLuint64EXT * result
[6]
#define qPrintable(string)
Definition qstring.h:1531
#define QStringLiteral(str)
ptrdiff_t qsizetype
Definition qtypes.h:165
static const uint base
Definition qurlidna.cpp:20
QT_BEGIN_NAMESPACE typedef uchar * output
const char className[16]
[1]
Definition qwizard.cpp:100
unsigned int useStarImports
Definition option.h:31
ClassInfoEntries classInfoEntries()