diff options
Diffstat (limited to 'src/tools/uic/python/pythonwriteimports.cpp')
-rw-r--r-- | src/tools/uic/python/pythonwriteimports.cpp | 147 |
1 files changed, 86 insertions, 61 deletions
diff --git a/src/tools/uic/python/pythonwriteimports.cpp b/src/tools/uic/python/pythonwriteimports.cpp index f9dfeb28da..74eeab8387 100644 --- a/src/tools/uic/python/pythonwriteimports.cpp +++ b/src/tools/uic/python/pythonwriteimports.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2019 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$ -** -****************************************************************************/ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "pythonwriteimports.h" @@ -35,12 +10,16 @@ #include <ui4.h> +#include <QtCore/qdir.h> +#include <QtCore/qfileinfo.h> #include <QtCore/qtextstream.h> #include <algorithm> QT_BEGIN_NAMESPACE +using namespace Qt::StringLiterals; + // Generate imports for Python. Note some things differ from C++: // - qItemView->header()->setFoo() does not require QHeaderView to be imported // - qLabel->setFrameShape(QFrame::Box) however requires QFrame to be imported @@ -70,26 +49,13 @@ static WriteImports::ClassesPerModule defaultClasses() QStringLiteral("QPainter"), QStringLiteral("QPixmap"), QStringLiteral("QTransform"), QStringLiteral("QRadialGradient")} }, + // Add QWidget for QWidget.setTabOrder() {QStringLiteral("QtWidgets"), - {QStringLiteral("QSizePolicy")} + {QStringLiteral("QSizePolicy"), QStringLiteral("QWidget")} } }; } -// Change the name of a qrc file "dir/foo.qrc" file to the Python -// module name "foo_rc" according to project conventions. -static QString pythonResource(QString resource) -{ - const int lastSlash = resource.lastIndexOf(QLatin1Char('/')); - if (lastSlash != -1) - resource.remove(0, lastSlash + 1); - if (resource.endsWith(QLatin1String(".qrc"))) { - resource.chop(4); - resource.append(QLatin1String("_rc")); - } - return resource; -} - // Helpers for WriteImports::ClassesPerModule maps static void insertClass(const QString &module, const QString &className, WriteImports::ClassesPerModule *c) @@ -136,7 +102,7 @@ WriteImports::WriteImports(Uic *uic) : WriteIncludesBase(uic), m_qtClasses(defaultClasses()) { for (const auto &e : classInfoEntries()) - m_classToModule.insert(QLatin1String(e.klass), QLatin1String(e.module)); + m_classToModule.insert(QLatin1StringView(e.klass), QLatin1StringView(e.module)); } void WriteImports::acceptUI(DomUI *node) @@ -162,27 +128,67 @@ void WriteImports::acceptUI(DomUI *node) const auto includes = resources->elementInclude(); for (auto include : includes) { if (include->hasAttributeLocation()) - writeImport(pythonResource(include->attributeLocation())); + writeResourceImport(include->attributeLocation()); } output << '\n'; } } -void WriteImports::writeImport(const QString &module) +QString WriteImports::resourceAbsolutePath(QString resource) const +{ + // If we know the project root, generate an absolute Python import + // to the resource. options. pythonRoot is the Python path component + // under which the UI file is. + const auto &options = uic()->option(); + if (!options.inputFile.isEmpty() && !options.pythonRoot.isEmpty()) { + resource = QDir::cleanPath(QFileInfo(options.inputFile).canonicalPath() + u'/' + resource); + if (resource.size() > options.pythonRoot.size()) + resource.remove(0, options.pythonRoot.size() + 1); + } + // If nothing is known, we assume the directory pointed by "../" is the root + while (resource.startsWith(u"../")) + resource.remove(0, 3); + resource.replace(u'/', u'.'); + return resource; +} + +void WriteImports::writeResourceImport(const QString &module) { - if (uic()->option().fromImports) - uic()->output() << "from . "; - uic()->output() << "import " << module << '\n'; + const auto &options = uic()->option(); + auto &str = uic()->output(); + + QString resource = QDir::cleanPath(module); + if (resource.endsWith(u".qrc")) + resource.chop(4); + const qsizetype basePos = resource.lastIndexOf(u'/') + 1; + // Change the name of a qrc file "dir/foo.qrc" file to the Python + // module name "foo_rc" according to project conventions. + if (options.rcPrefix) + resource.insert(basePos, u"rc_"); + else + resource.append(u"_rc"); + + switch (options.pythonResourceImport) { + case Option::PythonResourceImport::Default: + str << "import " << QStringView{resource}.sliced(basePos) << '\n'; + break; + case Option::PythonResourceImport::FromDot: + str << "from . import " << QStringView{resource}.sliced(basePos) << '\n'; + break; + case Option::PythonResourceImport::Absolute: + str << "import " << resourceAbsolutePath(resource) << '\n'; + break; + } } void WriteImports::doAdd(const QString &className, const DomCustomWidget *dcw) { const CustomWidgetsInfo *cwi = uic()->customWidgetsInfo(); - if (cwi->extends(className, QLatin1String("QListWidget"))) + if (cwi->extends(className, "QListWidget")) add(QStringLiteral("QListWidgetItem")); - else if (cwi->extends(className, QLatin1String("QTreeWidget"))) + else if (cwi->extends(className, "QTreeWidget")) add(QStringLiteral("QTreeWidgetItem")); - else if (cwi->extends(className, QLatin1String("QTableWidget"))) + else if (cwi->extends(className, "QTableWidget")) add(QStringLiteral("QTableWidgetItem")); if (dcw != nullptr) { @@ -209,7 +215,7 @@ bool WriteImports::addQtClass(const QString &className) void WriteImports::addPythonCustomWidget(const QString &className, const DomCustomWidget *node) { - if (className.contains(QLatin1String("::"))) + if (className.contains("::"_L1)) return; // Exclude namespaced names (just to make tests pass). if (addQtClass(className)) // Qt custom widgets like QQuickWidget, QAxWidget, etc @@ -222,26 +228,45 @@ void WriteImports::addPythonCustomWidget(const QString &className, const DomCust } else { // When we do have elementHeader, we know it's a relative import. QString modulePath = node->elementHeader()->text(); // Replace the '/' by '.' - modulePath.replace(QLatin1Char('/'), QLatin1Char('.')); - // '.h' is added by default on headers for <customwidget> - if (modulePath.endsWith(QLatin1String(".h"))) + modulePath.replace(u'/', u'.'); + // '.h' is added by default on headers for <customwidget>. + if (modulePath.endsWith(".h"_L1, Qt::CaseInsensitive)) modulePath.chop(2); + else if (modulePath.endsWith(".hh"_L1)) + modulePath.chop(3); + else if (modulePath.endsWith(".hpp"_L1)) + modulePath.chop(4); insertClass(modulePath, className, &m_customWidgets); } } void WriteImports::acceptProperty(DomProperty *node) { - if (node->kind() == DomProperty::Enum) { - // Add base classes like QFrame for QLabel::frameShape() - const QString &enumV = node->elementEnum(); - const auto colonPos = enumV.indexOf(u"::"); - if (colonPos > 0) - addQtClass(enumV.left(colonPos)); + switch (node->kind()) { + case DomProperty::Enum: + addEnumBaseClass(node->elementEnum()); + break; + case DomProperty::Set: + addEnumBaseClass(node->elementSet()); + break; + default: + break; } + WriteIncludesBase::acceptProperty(node); } +void WriteImports::addEnumBaseClass(const QString &v) +{ + // Add base classes like QFrame for QLabel::frameShape() + const auto colonPos = v.indexOf(u"::"); + if (colonPos > 0) { + const QString base = v.left(colonPos); + if (base.startsWith(u'Q') && base != u"Qt") + addQtClass(base); + } +} + } // namespace Python QT_END_NAMESPACE |