uic: Add python

- Add command line option
- Add import (include) handling
- Add language helpers like streamable classes for Function definition,
  object instantiation
- Implement header comment formatting

Task-number: PYSIDE-797
Change-Id: I15041ab16504ea159f6665781a829cd548585af1
Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
This commit is contained in:
Friedemann Kleint 2018-11-20 08:38:16 +01:00
parent 89120c4a76
commit bc8633036c
13 changed files with 630 additions and 48 deletions

View File

@ -40,6 +40,7 @@
QT_BEGIN_NAMESPACE
class QTextStream;
class CustomWidgetsInfo;
class Driver;
class Uic;
@ -74,6 +75,9 @@ struct WriteIncludes : public TreeWalker
void acceptIncludes(DomIncludes *node) override;
void acceptInclude(DomInclude *node) override;
protected:
QTextStream &output() const { return m_output; }
private:
void add(const QString &className, bool determineHeader = true, const QString &header = QString(), bool global = false);

View File

@ -71,7 +71,7 @@ namespace {
// Write a statement to create a spacer item.
void writeSpacerItem(const DomSpacer *node, QTextStream &output) {
const QHash<QString, DomProperty *> properties = propertyMap(node->elementProperty());
output << "new QSpacerItem(";
output << language::operatorNew << "QSpacerItem(";
int w = 0;
int h = 0;
@ -495,8 +495,9 @@ void WriteInitialization::acceptUI(DomUI *node)
const QString widgetClassName = node->elementWidget()->attributeClass();
m_output << m_option.indent << "void " << "setupUi(" << widgetClassName << " *" << varName << ")\n"
<< m_option.indent << "{\n";
const QString parameterType = widgetClassName + QLatin1String(" *");
m_output << m_option.indent
<< language::startFunctionDefinition1("setupUi", parameterType, varName, m_option.indent);
const QStringList connections = m_uic->databaseInfo()->connections();
for (int i=0; i<connections.size(); ++i) {
@ -550,7 +551,7 @@ void WriteInitialization::acceptUI(DomUI *node)
if (m_option.autoConnection)
m_output << "\n" << m_indent << "QMetaObject::connectSlotsByName(" << varName << ");\n";
m_output << m_option.indent << "} // setupUi\n\n";
m_output << m_option.indent << language::endFunctionDefinition("setupUi");
if (!m_mainFormUsedInRetranslateUi) {
m_refreshInitialization += m_indent;
@ -559,10 +560,10 @@ void WriteInitialization::acceptUI(DomUI *node)
m_refreshInitialization += QLatin1String(");\n");
}
m_output << m_option.indent << "void " << "retranslateUi(" << widgetClassName << " *" << varName << ")\n"
<< m_option.indent << "{\n"
m_output << m_option.indent
<< language::startFunctionDefinition1("retranslateUi", parameterType, varName, m_option.indent)
<< m_refreshInitialization
<< m_option.indent << "} // retranslateUi\n\n";
<< m_option.indent << language::endFunctionDefinition("retranslateUi");
m_layoutChain.pop();
m_widgetChain.pop();
@ -612,8 +613,9 @@ void WriteInitialization::acceptWidget(DomWidget *node)
const auto *cwi = m_uic->customWidgetsInfo();
if (m_widgetChain.size() != 1) {
m_output << m_indent << varName << " = new " << cwi->realClassName(className)
<< '(' << parentWidget << ");\n";
m_output << m_indent << varName << " = " << language::operatorNew
<< language::fixClassName(cwi->realClassName(className))
<< '(' << parentWidget << ')' << language::eol;
}
parentWidget = savedParentWidget;
@ -846,7 +848,8 @@ void WriteInitialization::addButtonGroup(const DomWidget *buttonNode, const QStr
m_output << m_indent;
if (createGroupOnTheFly)
m_output << className << " *";
m_output << groupName << " = new " << className << '(' << m_mainFormVarName << ");\n";
m_output << groupName << " = " << language::operatorNew
<< className << '(' << m_mainFormVarName << ')' << language::eol;
m_buttonGroups.insert(groupName);
writeProperties(groupName, className, group->elementProperty());
}
@ -863,7 +866,7 @@ void WriteInitialization::acceptLayout(DomLayout *node)
bool isGroupBox = false;
m_output << m_indent << varName << " = new " << className << '(';
m_output << m_indent << varName << " = " << language::operatorNew << className << '(';
if (!m_layoutChain.top() && !isGroupBox)
m_output << m_driver->findOrInsertWidget(m_widgetChain.top());
@ -1037,7 +1040,8 @@ void WriteInitialization::acceptActionGroup(DomActionGroup *node)
if (m_actionGroupChain.top())
varName = m_driver->findOrInsertActionGroup(m_actionGroupChain.top());
m_output << m_indent << actionName << " = new QActionGroup(" << varName << ");\n";
m_output << m_indent << actionName << " = " << language::operatorNew
<< "QActionGroup(" << varName << ");\n";
writeProperties(actionName, QLatin1String("QActionGroup"), node->elementProperty());
m_actionGroupChain.push(node);
@ -1057,7 +1061,8 @@ void WriteInitialization::acceptAction(DomAction *node)
if (m_actionGroupChain.top())
varName = m_driver->findOrInsertActionGroup(m_actionGroupChain.top());
m_output << m_indent << actionName << " = new QAction(" << varName << ");\n";
m_output << m_indent << actionName << " = " << language::operatorNew
<< "QAction(" << varName << ')' << language::eol;
writeProperties(actionName, QLatin1String("QAction"), node->elementProperty());
}
@ -1322,8 +1327,8 @@ void WriteInitialization::writeProperties(const QString &varName,
case DomProperty::Palette: {
const DomPalette *pal = p->elementPalette();
const QString paletteName = m_driver->unique(QLatin1String("palette"));
m_output << m_indent << "QPalette " << paletteName << ";\n";
m_output << m_indent << language::stackVariable("QPalette", paletteName)
<< language::eol;
writeColorGroup(pal->elementActive(), QLatin1String("QPalette::Active"), paletteName);
writeColorGroup(pal->elementInactive(), QLatin1String("QPalette::Inactive"), paletteName);
writeColorGroup(pal->elementDisabled(), QLatin1String("QPalette::Disabled"), paletteName);
@ -1512,20 +1517,15 @@ QString WriteInitialization::writeSizePolicy(const DomSizePolicy *sp)
const QString spName = m_driver->unique(QLatin1String("sizePolicy"));
m_sizePolicyNameMap.insert(sizePolicyHandle, spName);
m_output << m_indent << "QSizePolicy " << spName;
do {
if (sp->hasElementHSizeType() && sp->hasElementVSizeType()) {
m_output << "(QSizePolicy::" << language::sizePolicy(sp->elementHSizeType())
<< ", QSizePolicy::" << language::sizePolicy(sp->elementVSizeType()) << ");\n";
break;
}
if (sp->hasAttributeHSizeType() && sp->hasAttributeVSizeType()) {
m_output << "(QSizePolicy::" << sp->attributeHSizeType() << ", QSizePolicy::"
<< sp->attributeVSizeType() << ");\n";
break;
}
m_output << ";\n";
} while (false);
m_output << m_indent << language::stackVariableWithInitParameters("QSizePolicy", spName);
if (sp->hasElementHSizeType() && sp->hasElementVSizeType()) {
m_output << "QSizePolicy" << language::qualifier << language::sizePolicy(sp->elementHSizeType())
<< ", QSizePolicy" << language::qualifier << language::sizePolicy(sp->elementVSizeType());
} else if (sp->hasAttributeHSizeType() && sp->hasAttributeVSizeType()) {
m_output << "QSizePolicy::" << sp->attributeHSizeType() << ", QSizePolicy::"
<< sp->attributeVSizeType();
}
m_output << ')' << language::eol;
m_output << m_indent << spName << ".setHorizontalStretch("
<< sp->elementHorStretch() << ");\n";
@ -1549,7 +1549,8 @@ QString WriteInitialization::writeFontProperties(const DomFont *f)
const QString fontName = m_driver->unique(QLatin1String("font"));
m_fontPropertiesNameMap.insert(FontHandle(f), fontName);
m_output << m_indent << "QFont " << fontName << ";\n";
m_output << m_indent << language::stackVariable("QFont", fontName)
<< language::eol;
if (f->hasElementFamily() && !f->elementFamily().isEmpty()) {
m_output << m_indent << fontName << ".setFamily("
<< language::qstring(f->elementFamily(), m_dindent) << ");\n";
@ -2512,7 +2513,8 @@ QString WriteInitialization::Item::writeSetupUi(const QString &parent, Item::Emp
bool generateMultiDirective = false;
if (emptyItemPolicy == Item::ConstructItemOnly && m_children.isEmpty()) {
if (m_setupUiData.policy == ItemData::DontGenerate) {
m_setupUiStream << m_indent << "new " << m_itemClassName << '(' << parent << ");\n";
m_setupUiStream << m_indent << language::operatorNew << m_itemClassName
<< '(' << parent << ')' << language::eol;
return QString();
}
if (m_setupUiData.policy == ItemData::GenerateWithMultiDirective)
@ -2523,11 +2525,17 @@ QString WriteInitialization::Item::writeSetupUi(const QString &parent, Item::Emp
generateMultiDirectiveBegin(m_setupUiStream, m_setupUiData.directives);
const QString uniqueName = m_driver->unique(QLatin1String("__") + m_itemClassName.toLower());
m_setupUiStream << m_indent << m_itemClassName << " *" << uniqueName << " = new " << m_itemClassName << '(' << parent << ");\n";
m_setupUiStream << m_indent;
if (language::language() == Language::Cpp)
m_setupUiStream << m_itemClassName << " *";
m_setupUiStream << uniqueName
<< " = " << language::operatorNew << m_itemClassName << '(' << parent
<< ')' << language::eol;
if (generateMultiDirective) {
m_setupUiStream << "#else\n";
m_setupUiStream << m_indent << "new " << m_itemClassName << '(' << parent << ");\n";
m_setupUiStream << m_indent << language::operatorNew << m_itemClassName
<< '(' << parent << ')' << language::eol;
generateMultiDirectiveEnd(m_setupUiStream, m_setupUiData.directives);
}

View File

@ -29,6 +29,7 @@
#include "uic.h"
#include "option.h"
#include "driver.h"
#include <language.h>
#include <qfile.h>
#include <qdir.h>
@ -96,7 +97,7 @@ int runUic(int argc, char *argv[])
QCommandLineOption generatorOption(QStringList() << QStringLiteral("g") << QStringLiteral("generator"));
generatorOption.setDescription(QStringLiteral("Select generator."));
generatorOption.setValueName(QStringLiteral("java|cpp"));
generatorOption.setValueName(QStringLiteral("python|cpp"));
parser.addOption(generatorOption);
QCommandLineOption idBasedOption(QStringLiteral("idbased"));
@ -116,6 +117,13 @@ int runUic(int argc, char *argv[])
driver.option().translateFunction = parser.value(translateOption);
driver.option().includeFile = parser.value(includeOption);
Language language = Language::Cpp;
if (parser.isSet(generatorOption)) {
if (parser.value(generatorOption).compare(QLatin1String("python")) == 0)
language = Language::Python;
}
language::setLanguage(language);
if (parser.isSet(noStringLiteralOption))
fprintf(stderr, "The -s, --no-stringliteral option is deprecated and it won't take any effect.\n");

View File

@ -0,0 +1,8 @@
INCLUDEPATH += $$PWD
# Input
HEADERS += $$PWD/pythonwritedeclaration.h \
$$PWD/pythonwriteimports.h
SOURCES += $$PWD/pythonwritedeclaration.cpp \
$$PWD/pythonwriteimports.cpp

View File

@ -0,0 +1,73 @@
/****************************************************************************
**
** 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$
**
****************************************************************************/
#include "pythonwritedeclaration.h"
#include <cppwriteinitialization.h>
#include <language.h>
#include <driver.h>
#include <ui4.h>
#include <uic.h>
#include <QtCore/qtextstream.h>
#include <QtCore/qdebug.h>
QT_BEGIN_NAMESPACE
namespace Python {
WriteDeclaration::WriteDeclaration(Uic *uic) :
m_uic(uic),
m_driver(uic->driver()),
m_output(uic->output()),
m_option(uic->option())
{
}
void WriteDeclaration::acceptUI(DomUI *node)
{
// remove any left-over C++ namespaces
const QString qualifiedClassName = QLatin1String("Ui_") + node->elementClass()
+ m_option.postfix;
m_output << "class " << language::fixClassName(qualifiedClassName) << "(object):\n";
TreeWalker::acceptWidget(node->elementWidget());
if (const DomButtonGroups *domButtonGroups = node->elementButtonGroups())
acceptButtonGroups(domButtonGroups);
CPP::WriteInitialization(m_uic).acceptUI(node);
}
// Register button groups to prevent the on-the-fly creation legacy
// feature from triggering
void WriteDeclaration::acceptButtonGroup(const DomButtonGroup *buttonGroup)
{
m_driver->findOrInsertButtonGroup(buttonGroup);
}
} // namespace Python
QT_END_NAMESPACE

View File

@ -0,0 +1,62 @@
/****************************************************************************
**
** 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$
**
****************************************************************************/
#ifndef PYTHONWRITEDECLARATION_H
#define PYTHONWRITEDECLARATION_H
#include <treewalker.h>
QT_BEGIN_NAMESPACE
class QTextStream;
class Driver;
class Uic;
struct Option;
namespace Python {
struct WriteDeclaration : public TreeWalker
{
WriteDeclaration(Uic *uic);
void acceptUI(DomUI *node) override;
void acceptButtonGroup(const DomButtonGroup *buttonGroup) override;
private:
Uic *m_uic;
Driver *m_driver;
QTextStream &m_output;
const Option &m_option;
};
} // namespace Python
QT_END_NAMESPACE
#endif // PYTHONWRITEDECLARATION_H

View File

@ -0,0 +1,92 @@
/****************************************************************************
**
** 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$
**
****************************************************************************/
#include "pythonwriteimports.h"
#include <customwidgetsinfo.h>
#include <uic.h>
#include <ui4.h>
#include <QtCore/qtextstream.h>
QT_BEGIN_NAMESPACE
static const char *standardImports =
R"I(from PySide2.QtCore import (QCoreApplication, QMetaObject, QObject, QPoint,
QRect, QSize, QUrl, Qt)
from PySide2.QtGui import (QColor, QFont, QIcon, QPixmap)
from PySide2.QtWidgets import *
)I";
namespace Python {
WriteImports::WriteImports(Uic *uic) : m_uic(uic)
{
}
void WriteImports::acceptUI(DomUI *node)
{
auto &output = m_uic->output();
output << standardImports << '\n';
if (auto customWidgets = node->elementCustomWidgets()) {
TreeWalker::acceptCustomWidgets(customWidgets);
output << '\n';
}
}
QString WriteImports::qtModuleOf(const DomCustomWidget *node) const
{
if (m_uic->customWidgetsInfo()->extends(node->elementClass(), QLatin1String("QAxWidget")))
return QStringLiteral("QtAxContainer");
if (const auto headerElement = node->elementHeader()) {
const auto &header = headerElement->text();
if (header.startsWith(QLatin1String("Qt"))) {
const int slash = header.indexOf(QLatin1Char('/'));
if (slash != -1)
return header.left(slash);
}
}
return QString();
}
void WriteImports::acceptCustomWidget(DomCustomWidget *node)
{
const auto &className = node->elementClass();
if (className.contains(QLatin1String("::")))
return; // Exclude namespaced names (just to make tests pass).
const QString &qtModule = qtModuleOf(node);
auto &output = m_uic->output();
if (!qtModule.isEmpty())
output << "from PySide2." << qtModule << ' ';
output << "import " << className << '\n';
}
} // namespace Python
QT_END_NAMESPACE

View File

@ -0,0 +1,58 @@
/****************************************************************************
**
** Copyright (C) 2018 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$
**
****************************************************************************/
#ifndef PYTHONWRITEIMPORTS_H
#define PYTHONWRITEIMPORTS_H
#include <treewalker.h>
QT_BEGIN_NAMESPACE
class Uic;
namespace Python {
struct WriteImports : public TreeWalker
{
public:
explicit WriteImports(Uic *uic);
void acceptUI(DomUI *node) override;
void acceptCustomWidget(DomCustomWidget *node) override;
private:
QString qtModuleOf(const DomCustomWidget *node) const;
Uic *const m_uic;
};
} // namespace Python
QT_END_NAMESPACE
#endif // PYTHONWRITEIMPORTS_H

View File

@ -33,6 +33,48 @@
namespace language {
static Encoding encoding = Encoding::Utf8;
static Language _language = Language::Cpp;
Language language() { return _language; }
void setLanguage(Language l)
{
_language = l;
switch (_language) {
case Language::Cpp:
derefPointer = QLatin1String("->");
nullPtr = QLatin1String("nullptr");
operatorNew = QLatin1String("new ");
qtQualifier = QLatin1String("Qt::");
qualifier = QLatin1String("::");
self = QLatin1String(""); // for testing: change to "this->";
eol = QLatin1String(";\n");
encoding = Encoding::Utf8;
break;
case Language::Python:
derefPointer = QLatin1String(".");
nullPtr = QLatin1String("None");
operatorNew = QLatin1String("");
qtQualifier = QLatin1String("Qt.");
qualifier = QLatin1String(".");
self = QLatin1String("self.");
eol = QLatin1String("\n");
encoding = Encoding::Unicode;
break;
}
}
QString derefPointer;
QString nullPtr;
QString operatorNew;
QString qtQualifier;
QString qualifier;
QString self;
QString eol;
QString cppQualifier = QLatin1String("::");
QString cppTrue = QLatin1String("true");
QString cppFalse = QLatin1String("false");
QTextStream &operator<<(QTextStream &str, const qtConfig &c)
{
@ -71,6 +113,13 @@ const char *lookupEnum(const EnumLookup(&array)[N], int value, int defaultIndex
return defaultValue;
}
QString fixClassName(QString className)
{
if (language() == Language::Python)
className.replace(cppQualifier, QLatin1String("_"));
return className;
}
const char *toolbarArea(int v)
{
static const EnumLookup toolBarAreas[] =
@ -250,12 +299,12 @@ void _formatString(QTextStream &str, const QString &value, const QString &indent
switch (encoding) {
// Special characters as 3 digit octal escapes (u8"\303\234mlaut")
case Encoding::Utf8: {
if (qString)
if (qString && _language == Language::Cpp)
str << "QString::fromUtf8(";
const QByteArray utf8 = value.toUtf8();
formatStringSequence<Encoding::Utf8>(str, utf8.cbegin(), utf8.cend(), indent,
8, 3);
if (qString)
if (qString && _language == Language::Cpp)
str << ')';
}
break;
@ -268,4 +317,71 @@ void _formatString(QTextStream &str, const QString &value, const QString &indent
}
}
QTextStream &operator<<(QTextStream &str, const repeat &r)
{
for (int i = 0; i < r.m_count; ++i)
str << r.m_char;
return str;
}
startFunctionDefinition1::startFunctionDefinition1(const char *name, const QString &parameterType,
const QString &parameterName,
const QString &indent,
const char *returnType) :
m_name(name), m_parameterType(parameterType), m_parameterName(parameterName),
m_indent(indent), m_return(returnType)
{
}
QTextStream &operator<<(QTextStream &str, const startFunctionDefinition1 &f)
{
switch (language()) {
case Language::Cpp:
str << (f.m_return ? f.m_return : "void") << ' ' << f.m_name << '('
<< f.m_parameterType;
if (f.m_parameterType.cend()->isLetter())
str << ' ';
str << f.m_parameterName << ')' << '\n' << f.m_indent << "{\n";
break;
case Language::Python:
str << "def " << f.m_name << "(self, " << f.m_parameterName << "):\n";
break;
}
return str;
}
endFunctionDefinition::endFunctionDefinition(const char *name) : m_name(name)
{
}
QTextStream &operator<<(QTextStream &str, const endFunctionDefinition &f)
{
switch (language()) {
case Language::Cpp:
str << "} // " << f.m_name << "\n\n";
break;
case Language::Python:
str << "# " << f.m_name << "\n\n";
break;
}
return str;
}
void _formatStackVariable(QTextStream &str, const char *className, QStringView varName,
bool withInitParameters)
{
switch (language()) {
case Language::Cpp:
str << className << ' ' << varName;
if (withInitParameters)
str << '(';
break;
case Language::Python:
str << varName << " = " << className << '(';
if (!withInitParameters)
str << ')';
break;
}
}
} // namespace language

View File

@ -34,8 +34,25 @@
QT_FORWARD_DECLARE_CLASS(QTextStream)
enum class Language { Cpp, Python };
namespace language {
Language language();
void setLanguage(Language);
extern QString derefPointer;
extern QString nullPtr;
extern QString operatorNew;
extern QString qtQualifier;
extern QString qualifier;
extern QString self;
extern QString eol;
extern QString cppQualifier;
extern QString cppTrue;
extern QString cppFalse;
// Base class for streamable objects with one QStringView parameter
class StringViewStreamable
{
@ -72,6 +89,8 @@ public:
QTextStream &operator<<(QTextStream &, const closeQtConfig &c);
QString fixClassName(QString className);
const char *toolbarArea(int v);
const char *sizePolicy(int v);
const char *dockWidgetArea(int v);
@ -107,6 +126,69 @@ inline QTextStream &operator<<(QTextStream &str, const language::_string<AsQStri
using charliteral = _string<false>;
using qstring = _string<true>;
class repeat {
public:
explicit repeat(int count, char c) : m_count(count), m_char(c) {}
friend QTextStream &operator<<(QTextStream &str, const repeat &r);
private:
const int m_count;
const char m_char;
};
class startFunctionDefinition1 {
public:
explicit startFunctionDefinition1(const char *name, const QString &parameterType,
const QString &parameterName,
const QString &indent,
const char *returnType = nullptr);
friend QTextStream &operator<<(QTextStream &str, const startFunctionDefinition1 &f);
private:
const char *m_name;
const QString &m_parameterType;
const QString &m_parameterName;
const QString &m_indent;
const char *m_return;
};
class endFunctionDefinition {
public:
explicit endFunctionDefinition(const char *name);
friend QTextStream &operator<<(QTextStream &str, const endFunctionDefinition &f);
private:
const char *m_name;
};
void _formatStackVariable(QTextStream &str, const char *className, QStringView varName, bool withInitParameters);
template <bool withInitParameters>
class _stackVariable {
public:
explicit _stackVariable(const char *className, QStringView varName) :
m_className(className), m_varName(varName) {}
void format(QTextStream &str) const
{ _formatStackVariable(str, m_className, m_varName, withInitParameters); }
private:
const char *m_className;
QStringView m_varName;
QStringView m_parameters;
};
template <bool withInitParameters>
inline QTextStream &operator<<(QTextStream &str, const _stackVariable<withInitParameters> &s)
{
s.format(str);
return str;
}
using stackVariable = _stackVariable<false>;
using stackVariableWithInitParameters = _stackVariable<true>;
} // namespace language
#endif // LANGUAGE_H

View File

@ -35,6 +35,10 @@
#include "cppwriteincludes.h"
#include "cppwritedeclaration.h"
#include <pythonwritedeclaration.h>
#include <pythonwriteimports.h>
#include <language.h>
#include <qxmlstream.h>
#include <qfileinfo.h>
@ -103,7 +107,7 @@ bool Uic::printDependencies()
return true;
}
void Uic::writeCopyrightHeader(DomUI *ui)
void Uic::writeCopyrightHeaderCpp(const DomUI *ui) const
{
QString comment = ui->elementComment();
if (!comment.isEmpty())
@ -118,6 +122,48 @@ void Uic::writeCopyrightHeader(DomUI *ui)
out << "********************************************************************************/\n\n";
}
// Format existing UI file comments for Python with some smartness : Replace all
// leading C++ comment characters by '#' or prepend '#' if needed.
static inline bool isCppCommentChar(QChar c)
{
return c == QLatin1Char('/') || c == QLatin1Char('*');
}
static int leadingCppCommentCharCount(const QStringRef &s)
{
int i = 0;
for (const int size = s.size(); i < size && isCppCommentChar(s.at(i)); ++i) {
}
return i;
}
void Uic::writeCopyrightHeaderPython(const DomUI *ui) const
{
QString comment = ui->elementComment();
if (!comment.isEmpty()) {
const auto lines = comment.splitRef(QLatin1Char('\n'));
for (const auto &line : lines) {
if (const int leadingCommentChars = leadingCppCommentCharCount(line)) {
out << language::repeat(leadingCommentChars, '#')
<< line.right(line.size() - leadingCommentChars);
} else {
if (!line.startsWith(QLatin1Char('#')))
out << "# ";
out << line;
}
out << '\n';
}
out << '\n';
}
out << language::repeat(80, '#') << "\n## Form generated from reading UI file '"
<< QFileInfo(opt.inputFile).fileName()
<< "'\n##\n## Created by: Qt User Interface Compiler version " << QT_VERSION_STR
<< "\n##\n## WARNING! All changes made in this file will be lost when recompiling UI file!\n"
<< language::repeat(80, '#') << "\n\n";
}
// Check the version with a stream reader at the <ui> element.
static double versionFromUiAttribute(QXmlStreamReader &reader)
@ -195,15 +241,26 @@ bool Uic::write(QIODevice *in)
bool Uic::write(DomUI *ui)
{
using namespace CPP;
if (!ui || !ui->elementWidget())
return false;
if (opt.copyrightHeader)
writeCopyrightHeader(ui);
const auto lang = language::language();
if (opt.headerProtection) {
if (lang == Language::Python)
out << "# -*- coding: utf-8 -*-\n\n";
if (opt.copyrightHeader) {
switch (language::language()) {
case Language::Cpp:
writeCopyrightHeaderCpp(ui);
break;
case Language::Python:
writeCopyrightHeaderPython(ui);
break;
}
}
if (opt.headerProtection && lang == Language::Cpp) {
writeHeaderProtectionStart();
out << "\n";
}
@ -218,13 +275,25 @@ bool Uic::write(DomUI *ui)
info.acceptUI(ui);
cWidgetsInfo.acceptUI(ui);
WriteIncludes writeIncludes(this);
writeIncludes.acceptUI(ui);
Validator(this).acceptUI(ui);
WriteDeclaration(this).acceptUI(ui);
switch (language::language()) {
case Language::Cpp: {
CPP::WriteIncludes writeIncludes(this);
writeIncludes.acceptUI(ui);
Validator(this).acceptUI(ui);
CPP::WriteDeclaration(this).acceptUI(ui);
}
break;
case Language::Python: {
Python::WriteImports writeImports(this);
writeImports.acceptUI(ui);
Validator(this).acceptUI(ui);
Python::WriteDeclaration(this).acceptUI(ui);
}
break;
}
if (opt.headerProtection)
if (opt.headerProtection && lang == Language::Cpp)
writeHeaderProtectionEnd();
return true;

View File

@ -91,7 +91,8 @@ public:
private:
// copyright header
void writeCopyrightHeader(DomUI *ui);
void writeCopyrightHeaderCpp(const DomUI *ui) const;
void writeCopyrightHeaderPython(const DomUI *ui) const;
DomUI *parseUiFile(QXmlStreamReader &reader);
// header protection

View File

@ -7,6 +7,7 @@ DEFINES += QT_UIC QT_NO_CAST_FROM_ASCII QT_NO_FOREACH
include(uic.pri)
include(shared/shared.pri)
include(cpp/cpp.pri)
include(python/python.pri)
HEADERS += uic.h