diff options
author | Liang Qi <liang.qi@qt.io> | 2019-01-04 12:11:11 +0100 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2019-01-04 13:03:26 +0100 |
commit | 7b23692538f55d499bf094a750311e1e4cd13ec6 (patch) | |
tree | 7e85cdabe0e069ee8fcbc3da3764327b4f8e2ba2 | |
parent | aa316d1d463777612db4b144d945bbaf67481494 (diff) | |
parent | 32897fd0b98966d22ecbd475a0e6a77ca8b1108d (diff) | |
download | qttools-7b23692538f55d499bf094a750311e1e4cd13ec6.tar.gz |
Merge remote-tracking branch 'origin/5.12' into dev
Conflicts:
src/qdoc/htmlgenerator.cpp
src/qtattributionsscanner/qdocgenerator.cpp
Done-With: Martin Smith <martin.smith@qt.io>
Change-Id: I56a23175579a1a699939179da2f35bbcd6c73367
46 files changed, 572 insertions, 263 deletions
diff --git a/dist/changes-5.11.3 b/dist/changes-5.11.3 new file mode 100644 index 000000000..4e0a0b187 --- /dev/null +++ b/dist/changes-5.11.3 @@ -0,0 +1,32 @@ +Qt 5.11.3 is a bug-fix release. It maintains both forward and backward +compatibility (source and binary) with Qt 5.11.0 through 5.11.2. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +http://doc.qt.io/qt-5/index.html + +The Qt version 5.11 series is binary compatible with the 5.10.x series. +Applications compiled for 5.10 will continue to run with 5.11. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* macdeployqt * +**************************************************************************** + + - [QTBUG-68823] Now deploys plugins when Qt is configured with + -no-framework + +**************************************************************************** +* Assistant * +**************************************************************************** + + - [QTBUG-71399] Fix a crash when removing multiple documentation files + inside preferences dialog diff --git a/dist/changes-5.12.0 b/dist/changes-5.12.0 new file mode 100644 index 000000000..7cbcf1d62 --- /dev/null +++ b/dist/changes-5.12.0 @@ -0,0 +1,60 @@ +Qt 5.12 introduces many new features and improvements as well as bugfixes +over the 5.11.x series. For more details, refer to the online documentation +included in this distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.12 series is binary compatible with the 5.11.x series. +Applications compiled for 5.11 will continue to run with 5.12. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* macdeployqt * +**************************************************************************** + + - [QTBUG-68823] Now deploys plugins when Qt is configured with + -no-framework + +**************************************************************************** +* winrtrunner * +**************************************************************************** + + - Loopback exemption for UWP applications: + * Added ability to enable loopback exemption for clients. This basically + enables UWP applications to connect to a local server for debugging + purposes. + * Added ability to enable loopback exemption for servers. This basically + enables UWP applications to react on socket connections that are made + from the same machine for debugging purposes. + +**************************************************************************** +* Qt Help * +**************************************************************************** + + - [QTCREATORBUG-18242] Fixed the issue with too many open files, when + many documentation files were registered. + - [QTBUG-59363] Fixed jumping to the proper documentation version + when activating the link that refers to another qch file. + - [QTBUG-21357] Items are now sorted alphabetically in Contents view. + - Removed qhelpconverter tool. + - Merged qcollectiongenerator tool into the qhelpgenerator tool. + +**************************************************************************** +* Qt Linguist * +**************************************************************************** + + - Added "Go to" action to context menu in "Phrases and guesses" pane. + +lupdate +------- + + - [QTBUG-63364] Add support for C++17 nested namespaces. + - [QTBUG-62478] Fixed premature termination on qmake .prf execution errors. + - Updated qmake project handling to newer functionality in qmake. diff --git a/qttools.pro b/qttools.pro index b87dcea59..e7ae1f2b2 100644 --- a/qttools.pro +++ b/qttools.pro @@ -1,2 +1,2 @@ -load(qt_find_clang) +!wasm:load(qt_find_clang) load(qt_parts) diff --git a/src/assistant/assistant/doc/src/assistant-manual.qdoc b/src/assistant/assistant/doc/src/assistant-manual.qdoc index 9badfc260..c86a19cac 100644 --- a/src/assistant/assistant/doc/src/assistant-manual.qdoc +++ b/src/assistant/assistant/doc/src/assistant-manual.qdoc @@ -251,7 +251,7 @@ file in the \c{file} tags. It is possible to specify a different file or any language. The icon defined by the \c{icon} tags is applied to any language. \row - \li \c{<cacheDirectory base="collection > default">} + \li \c{<cacheDirectory>, <cacheDirectory base="collection">} \li Specifies the cache directory that is used to store index files needed for the full text search and a copy of the collection file. The copy is needed because \QA stores all its settings in the diff --git a/src/assistant/assistant/main.cpp b/src/assistant/assistant/main.cpp index 04f0fc968..ac20872bd 100644 --- a/src/assistant/assistant/main.cpp +++ b/src/assistant/assistant/main.cpp @@ -268,6 +268,7 @@ void setupTranslations() int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QCoreApplication::setAttribute(Qt::AA_DisableWindowContextHelpButton); TRACE_OBJ QScopedPointer<QCoreApplication> a(createApplication(argc, argv)); #if QT_CONFIG(library) diff --git a/src/assistant/help/qhelpcollectionhandler.cpp b/src/assistant/help/qhelpcollectionhandler.cpp index 0cb6264dd..789e490ed 100644 --- a/src/assistant/help/qhelpcollectionhandler.cpp +++ b/src/assistant/help/qhelpcollectionhandler.cpp @@ -210,8 +210,10 @@ bool QHelpCollectionHandler::openCollectionFile() const FileInfoList &docList = registeredDocumentations(); if (indexAndNamespaceFilterTablesMissing) { for (const QHelpCollectionHandler::FileInfo &info : docList) { - if (!registerIndexAndNamespaceFilterTables(info.namespaceName)) + if (!registerIndexAndNamespaceFilterTables(info.namespaceName)) { + emit error(tr("Cannot register index tables in file %1.").arg(collectionFile())); return false; + } } return true; } @@ -239,8 +241,10 @@ bool QHelpCollectionHandler::openCollectionFile() // In this case we remove all records from tables. Transaction transaction(m_connectionName); for (const TimeStamp &timeStamp : toRemove) { - if (!unregisterIndexTable(timeStamp.namespaceId, timeStamp.folderId)) + if (!unregisterIndexTable(timeStamp.namespaceId, timeStamp.folderId)) { + emit error(tr("Cannot unregister index tables in file %1.").arg(collectionFile())); return false; + } } transaction.commit(); diff --git a/src/designer/src/components/formeditor/images/win/filesave.png b/src/designer/src/components/formeditor/images/win/filesave.png Binary files differindex 8feec99be..e65a29d5f 100644 --- a/src/designer/src/components/formeditor/images/win/filesave.png +++ b/src/designer/src/components/formeditor/images/win/filesave.png diff --git a/src/designer/src/components/propertyeditor/propertyeditor.cpp b/src/designer/src/components/propertyeditor/propertyeditor.cpp index 1fee704d2..d393caee5 100644 --- a/src/designer/src/components/propertyeditor/propertyeditor.cpp +++ b/src/designer/src/components/propertyeditor/propertyeditor.cpp @@ -913,8 +913,15 @@ void PropertyEditor::setObject(QObject *object) m_object = object; m_propertyManager->setObject(object); QDesignerFormWindowInterface *formWindow = QDesignerFormWindowInterface::findFormWindow(m_object); - if (Q_UNLIKELY(formWindow == nullptr)) // QTBUG-68507, can happen in Morph Undo macros with buddies - return; + // QTBUG-68507: Form window can be null for objects in Morph Undo macros with buddies + if (object != nullptr && formWindow == nullptr) { + formWindow = m_core->formWindowManager()->activeFormWindow(); + if (formWindow == nullptr) { + qWarning("PropertyEditor::setObject(): Unable to find form window for \"%s\".", + qPrintable(object->objectName())); + return; + } + } FormWindowBase *fwb = qobject_cast<FormWindowBase *>(formWindow); const bool idIdBasedTranslation = fwb && fwb->useIdBasedTranslations(); const bool idIdBasedTranslationUnchanged = (idIdBasedTranslation == DesignerPropertyManager::useIdBasedTranslations()); diff --git a/src/designer/src/components/taskmenu/itemlisteditor.cpp b/src/designer/src/components/taskmenu/itemlisteditor.cpp index d0a1a8308..a5ec15e48 100644 --- a/src/designer/src/components/taskmenu/itemlisteditor.cpp +++ b/src/designer/src/components/taskmenu/itemlisteditor.cpp @@ -168,7 +168,7 @@ void AbstractItemEditor::propertyChanged(QtProperty *property) // Subproperty return; - if ((role == ItemFlagsShadowRole && prop->value().toInt() == int(QListWidgetItem().flags())) + if ((role == ItemFlagsShadowRole && prop->value().toInt() == defaultItemFlags()) || (role == Qt::DecorationPropertyRole && !qvariant_cast<PropertySheetIconValue>(prop->value()).mask()) || (role == Qt::FontRole && !qvariant_cast<QFont>(prop->value()).resolve())) { prop->setModified(false); @@ -214,7 +214,7 @@ void AbstractItemEditor::resetProperty(QtProperty *property) QtVariantProperty *prop = m_propertyManager->variantProperty(property); int role = m_propertyToRole.value(prop); if (role == ItemFlagsShadowRole) - prop->setValue(QVariant::fromValue(int(QListWidgetItem().flags()))); + prop->setValue(QVariant::fromValue(defaultItemFlags())); else prop->setValue(QVariant(prop->valueType(), nullptr)); prop->setModified(false); @@ -246,7 +246,7 @@ void AbstractItemEditor::updateBrowser() QVariant val = getItemData(role); if (!val.isValid()) { if (role == ItemFlagsShadowRole) - val = QVariant::fromValue(int(QListWidgetItem().flags())); + val = QVariant::fromValue(defaultItemFlags()); else val = QVariant(int(prop->value().userType()), nullptr); prop->setModified(false); @@ -430,6 +430,12 @@ QVariant ItemListEditor::getItemData(int role) const return ui.listWidget->currentItem()->data(role); } +int ItemListEditor::defaultItemFlags() const +{ + static const int flags = QListWidgetItem().flags(); + return flags; +} + void ItemListEditor::cacheReloaded() { reloadIconResources(iconCache(), ui.listWidget); diff --git a/src/designer/src/components/taskmenu/itemlisteditor.h b/src/designer/src/components/taskmenu/itemlisteditor.h index ea0634eed..e9b292446 100644 --- a/src/designer/src/components/taskmenu/itemlisteditor.h +++ b/src/designer/src/components/taskmenu/itemlisteditor.h @@ -85,6 +85,7 @@ private slots: void resetProperty(QtProperty *property); protected: + virtual int defaultItemFlags() const = 0; void setupProperties(PropertyDefinition *propDefs); void setupObject(QWidget *object); void setupEditor(QWidget *object, PropertyDefinition *propDefs); @@ -138,6 +139,7 @@ private slots: protected: void setItemData(int role, const QVariant &v) override; QVariant getItemData(int role) const override; + int defaultItemFlags() const override; private: void setPropertyBrowserVisible(bool v); diff --git a/src/designer/src/components/taskmenu/tablewidgeteditor.cpp b/src/designer/src/components/taskmenu/tablewidgeteditor.cpp index 4a28a2f44..b1a7adf12 100644 --- a/src/designer/src/components/taskmenu/tablewidgeteditor.cpp +++ b/src/designer/src/components/taskmenu/tablewidgeteditor.cpp @@ -184,6 +184,12 @@ QVariant TableWidgetEditor::getItemData(int role) const return item->data(role); } +int TableWidgetEditor::defaultItemFlags() const +{ + static const int flags = QTableWidgetItem().flags(); + return flags; +} + void TableWidgetEditor::on_tableWidget_currentCellChanged(int currentRow, int currentCol, int, int /* XXX remove me */) { m_rowEditor->setCurrentIndex(currentRow); diff --git a/src/designer/src/components/taskmenu/tablewidgeteditor.h b/src/designer/src/components/taskmenu/tablewidgeteditor.h index 26ad05b49..72dbb58da 100644 --- a/src/designer/src/components/taskmenu/tablewidgeteditor.h +++ b/src/designer/src/components/taskmenu/tablewidgeteditor.h @@ -82,6 +82,7 @@ private slots: protected: void setItemData(int role, const QVariant &v) override; QVariant getItemData(int role) const override; + int defaultItemFlags() const override; private: void setPropertyBrowserVisible(bool v); diff --git a/src/designer/src/components/taskmenu/treewidgeteditor.cpp b/src/designer/src/components/taskmenu/treewidgeteditor.cpp index 2ec0109a4..20c7bd0a5 100644 --- a/src/designer/src/components/taskmenu/treewidgeteditor.cpp +++ b/src/designer/src/components/taskmenu/treewidgeteditor.cpp @@ -196,6 +196,12 @@ QVariant TreeWidgetEditor::getItemData(int role) const return ui.treeWidget->currentItem()->data(col, role); } +int TreeWidgetEditor::defaultItemFlags() const +{ + static const int flags = QTreeWidgetItem().flags(); + return flags; +} + void TreeWidgetEditor::on_newItemButton_clicked() { QTreeWidgetItem *curItem = ui.treeWidget->currentItem(); diff --git a/src/designer/src/components/taskmenu/treewidgeteditor.h b/src/designer/src/components/taskmenu/treewidgeteditor.h index a0187678d..9b1a607e4 100644 --- a/src/designer/src/components/taskmenu/treewidgeteditor.h +++ b/src/designer/src/components/taskmenu/treewidgeteditor.h @@ -80,6 +80,7 @@ private slots: protected: void setItemData(int role, const QVariant &v) override; QVariant getItemData(int role) const override; + int defaultItemFlags() const override; private: void setPropertyBrowserVisible(bool v); diff --git a/src/designer/src/designer/doc/src/designer-manual.qdoc b/src/designer/src/designer/doc/src/designer-manual.qdoc index dd060af3a..99f45ecdd 100644 --- a/src/designer/src/designer/doc/src/designer-manual.qdoc +++ b/src/designer/src/designer/doc/src/designer-manual.qdoc @@ -58,6 +58,7 @@ \section1 Table of Contents \list + \li \l{A Quick Start to Qt Designer} \li \l{Qt Designer's Editing Modes} \list \li \l{Qt Designer's Widget Editing Mode}{Widget Editing Mode} @@ -507,7 +508,7 @@ each corner and the midpoint of each side, indicating that it can be resized. - To select additional objects, hold down the \key Shift key and click on + To select additional objects, hold down the \key Control key and click on them. If more than one object is selected, the current object will be displayed with resize handles of a different color. @@ -696,43 +697,24 @@ form is previewed or used in an application. Placing objects in a layout also ensures that they will be resized correctly when the form is resized. - - \tableofcontents - - \section1 Applying and Breaking Layouts - - The simplest way to manage objects is to apply a layout to a group of - existing objects. This is achieved by selecting the objects that you need - to manage and applying one of the standard layouts using the main toolbar, - the \gui Form menu, or the form's context menu. - Once widgets have been inserted into a layout, it is not possible to move and resize them individually because the layout itself controls the geometry of each widget within it, taking account of the hints provided by - spacers. Instead, you must either break the layout and adjust each object's - geometry manually, or you can influence the widget's geometry by resizing - the layout. - - To break the layout, press \key{Ctrl+0} or choose \gui{Break Layout} from - the form's context menu, the \gui Form menu or the main toolbar. You can - also add and remove spacers from the layout to influence the geometries of + spacers. Spacers can be added to the layout to influence the geometries of the widgets. + Layouts can be nested to form a hierarchy. For example, to achieve a + typical dialog layout with a horizontal row of buttons, the dialog + elements can be laid out using a vertical box layout with a horizontal + box layout containing the buttons at the bottom. For an introduction to + the Qt layout system, refer to \l{Layout Management}. - \target InsertingObjectsIntoALayout - \table - \row - \li \inlineimage designer-layout-inserting.png - \li \b{Inserting Objects into a Layout} - - Objects can be inserted into an existing layout by dragging them from - their current positions and dropping them at the required location. A - blue cursor is displayed in the layout as an object is dragged over - it to indicate where the object will be added. - \endtable + To break a layout, press \key{Ctrl+0} or choose \gui{Break Layout} from + the form's context menu, the \gui Form menu or the main toolbar. + \tableofcontents - \section2 Setting A Top Level Layout + \section1 Setting A Top Level Layout The form's top level layout can be set by clearing the selection (click the left mouse button on the form itself) and applying a layout. A top level @@ -749,10 +731,52 @@ toolbar shown on the left, or from the context menu shown below. \endtable + Similary, top level layouts are set on container widgets (QGroupBox) + or on pages of page-based container widgets (QTabWidget, QToolBox + and QStackedWidget), respectively. The container widget needs to be + selected for this to succeed. + + Top level layouts are not visible as separate objects in the Object + Inspector. Their properties appear below the widget properties of the + main form, container widget, or page of a container widget in the + Property Editor. + \image designer-set-layout2.png - \section2 Horizontal and Vertical Layouts + \section1 Layout Objects + + Layout objects are created by applying a layout to a group of + existing objects. This is achieved by selecting the objects that you need + to manage and applying one of the standard layouts using the main toolbar, + the \gui Form menu, or the form's context menu. + + The layout object is indicated by a red frame on the form and appears as + an object in the Object Inspector. Its properties (margins and constraints) + are shown in the Property Editor. + + The layout object can be selected and placed within another layout along + with other widgets and layout objects to build a layout hierarchy. + + When a child layout object is selected, its parent layout object can be + selected by pressing down the \key Shift key while clicking on it. This + makes it possible to select a specific layout in a hierarchy, which is + otherwise difficult due to the small frame. + + + \section1 Inserting Objects Into a Layout + \target InsertingObjectsIntoALayout + + Objects can be inserted into an existing layout by dragging them from + their current positions and dropping them at the required location. A + blue cursor is displayed in the layout as an object is dragged over + it to indicate where the object will be added. + + \image designer-layout-inserting.png + \caption Inserting Objects into a Layout + + \section1 Layout Types + \section2 Horizontal and Vertical (Box) Layouts The simplest way to arrange objects on a form is to place them in a horizontal or vertical layout. Horizontal layouts ensure that the widgets @@ -764,7 +788,7 @@ using the grid layout. - \section3 The Grid Layout + \section2 The Grid Layout Complex form layouts can be created by placing objects in a grid layout. This kind of layout gives the form designer much more freedom to arrange @@ -773,7 +797,7 @@ suitable than a nested arrangement of horizontal and vertical layouts. - \section3 The Form Layout + \section2 The Form Layout The QFormLayout class manages widgets in a two-column form; the left column holds labels @@ -797,7 +821,7 @@ \endtable -\section3 Splitter Layouts + \section2 Splitter Layouts Another common way to manage the layout of objects on a form is to place them in a splitter. These splitters arrange the objects horizontally or @@ -814,7 +838,7 @@ keyboard shortcut, or \gui{Lay out} context menu entry. - \section2 Shortcut Keys + \section1 Shortcut Keys In addition to the standard toolbar and context menu entries, there is also a set of keyboard shortcuts to apply layouts on widgets. diff --git a/src/designer/src/lib/uilib/uilib.pri b/src/designer/src/lib/uilib/uilib.pri index b757f4ee9..386414b67 100644 --- a/src/designer/src/lib/uilib/uilib.pri +++ b/src/designer/src/lib/uilib/uilib.pri @@ -24,3 +24,5 @@ SOURCES += \ $$PWD/formbuilderextra.cpp \ $$PWD/resourcebuilder.cpp \ $$PWD/textbuilder.cpp + +OTHER_FILES += $$PWD/widgets.table diff --git a/src/distancefieldgenerator/main.cpp b/src/distancefieldgenerator/main.cpp index c7b5cab13..53ada87ac 100644 --- a/src/distancefieldgenerator/main.cpp +++ b/src/distancefieldgenerator/main.cpp @@ -30,9 +30,6 @@ #include <QApplication> #include <QCommandLineParser> -#include <QFile> -#include <QFileInfo> -#include <QRawFont> QT_USE_NAMESPACE @@ -44,9 +41,21 @@ int main(int argc, char **argv) app.setApplicationName(QStringLiteral("Qt Distance Field Generator")); app.setApplicationVersion(QStringLiteral(QT_VERSION_STR)); + QCommandLineParser parser; + parser.setApplicationDescription( + QCoreApplication::translate("main", + "Allows to prepare a font cache for Qt applications.")); + parser.addHelpOption(); + parser.addVersionOption(); + parser.addPositionalArgument(QLatin1String("file"), + QCoreApplication::translate("main", + "Font file (*.ttf, *.otf)")); + parser.process(app); + MainWindow mainWindow; - mainWindow.showMaximized(); + if (!parser.positionalArguments().isEmpty()) + mainWindow.open(parser.positionalArguments().constFirst()); + mainWindow.show(); return app.exec(); } - diff --git a/src/distancefieldgenerator/mainwindow.cpp b/src/distancefieldgenerator/mainwindow.cpp index 7108e387c..eef116ded 100644 --- a/src/distancefieldgenerator/mainwindow.cpp +++ b/src/distancefieldgenerator/mainwindow.cpp @@ -35,6 +35,7 @@ #include <QtCore/qmath.h> #include <QtCore/qendian.h> #include <QtCore/qbuffer.h> +#include <QtGui/qdesktopservices.h> #include <QtGui/qrawfont.h> #include <QtWidgets/qmessagebox.h> #include <QtWidgets/qlabel.h> @@ -49,15 +50,23 @@ QT_BEGIN_NAMESPACE +static void openHelp() +{ + QDesktopServices::openUrl(QUrl(QLatin1String("http://doc.qt.io/qt-5/qtdistancefieldgenerator-index.html"))); +} + MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) , m_settings(qApp->organizationName(), qApp->applicationName()) - , m_model(nullptr) + , m_model(new DistanceFieldModel(this)) , m_statusBarLabel(nullptr) , m_statusBarProgressBar(nullptr) { ui->setupUi(this); + ui->lvGlyphs->setModel(m_model); + + ui->actionHelp->setShortcut(QKeySequence::HelpContents); m_statusBarLabel = new QLabel(this); m_statusBarLabel->setText(tr("Ready")); @@ -75,6 +84,8 @@ MainWindow::MainWindow(QWidget *parent) qRegisterMetaType<glyph_t>("glyph_t"); qRegisterMetaType<QPainterPath>("QPainterPath"); + restoreGeometry(m_settings.value(QStringLiteral("geometry")).toByteArray()); + setupConnections(); } @@ -83,6 +94,27 @@ MainWindow::~MainWindow() delete ui; } +void MainWindow::open(const QString &path) +{ + m_fileName.clear(); + m_fontFile = path; + m_fontDir = QFileInfo(path).absolutePath(); + m_settings.setValue(QStringLiteral("fontDirectory"), m_fontDir); + + ui->lwUnicodeRanges->clear(); + ui->lwUnicodeRanges->setDisabled(true); + ui->action_Save->setDisabled(true); + ui->action_Save_as->setDisabled(true); + ui->tbSave->setDisabled(true); + ui->action_Open->setDisabled(true); + m_model->setFont(path); +} + +void MainWindow::closeEvent(QCloseEvent * /*event*/) +{ + m_settings.setValue(QStringLiteral("geometry"), saveGeometry()); +} + void MainWindow::setupConnections() { connect(ui->action_Open, &QAction::triggered, this, &MainWindow::openFont); @@ -93,7 +125,22 @@ void MainWindow::setupConnections() connect(ui->tbSelectAll, &QToolButton::clicked, this, &MainWindow::selectAll); connect(ui->actionSelect_all, &QAction::triggered, this, &MainWindow::selectAll); connect(ui->actionSelect_string, &QAction::triggered, this, &MainWindow::selectString); + connect(ui->actionHelp, &QAction::triggered, this, openHelp); + connect(ui->actionAbout_App, &QAction::triggered, this, &MainWindow::about); + connect(ui->actionAbout_Qt, &QAction::triggered, this, [this]() { + QMessageBox::aboutQt(this); + }); connect(ui->lwUnicodeRanges, &QListWidget::itemSelectionChanged, this, &MainWindow::updateUnicodeRanges); + + connect(ui->lvGlyphs->selectionModel(), + &QItemSelectionModel::selectionChanged, + this, + &MainWindow::updateSelection); + connect(m_model, &DistanceFieldModel::startGeneration, this, &MainWindow::startProgressBar); + connect(m_model, &DistanceFieldModel::stopGeneration, this, &MainWindow::stopProgressBar); + connect(m_model, &DistanceFieldModel::distanceFieldGenerated, this, &MainWindow::updateProgressBar); + connect(m_model, &DistanceFieldModel::stopGeneration, this, &MainWindow::populateUnicodeRanges); + connect(m_model, &DistanceFieldModel::error, this, &MainWindow::displayError); } void MainWindow::saveAs() @@ -552,36 +599,8 @@ void MainWindow::openFont() tr("Open font file"), m_fontDir, tr("Fonts (*.ttf *.otf);;All files (*)")); - if (!fileName.isEmpty()) { - m_fileName.clear(); - m_fontFile = fileName; - m_fontDir = QFileInfo(fileName).absolutePath(); - m_settings.setValue(QStringLiteral("fontDirectory"), m_fontDir); - - if (m_model == nullptr) { - m_model = new DistanceFieldModel(this); - connect(m_model, &DistanceFieldModel::startGeneration, this, &MainWindow::startProgressBar); - connect(m_model, &DistanceFieldModel::stopGeneration, this, &MainWindow::stopProgressBar); - connect(m_model, &DistanceFieldModel::distanceFieldGenerated, this, &MainWindow::updateProgressBar); - connect(m_model, &DistanceFieldModel::stopGeneration, this, &MainWindow::populateUnicodeRanges); - connect(m_model, &DistanceFieldModel::error, this, &MainWindow::displayError); - - ui->lvGlyphs->setModel(m_model); - - connect(ui->lvGlyphs->selectionModel(), - &QItemSelectionModel::selectionChanged, - this, - &MainWindow::updateSelection); - } - - ui->lwUnicodeRanges->clear(); - ui->lwUnicodeRanges->setDisabled(true); - ui->action_Save->setDisabled(true); - ui->action_Save_as->setDisabled(true); - ui->tbSave->setDisabled(true); - ui->action_Open->setDisabled(true); - m_model->setFont(fileName); - } + if (!fileName.isEmpty()) + open(fileName); } void MainWindow::updateProgressBar() @@ -620,9 +639,9 @@ void MainWindow::updateSelection() QModelIndexList list = ui->lvGlyphs->selectionModel()->selectedIndexes(); QString label; if (list.size() == ui->lvGlyphs->model()->rowCount()) - label = tr("Deselect &all"); + label = tr("Deselect &All"); else - label = tr("Select &all"); + label = tr("Select &All"); ui->tbSelectAll->setText(label); ui->actionSelect_all->setText(label); @@ -726,4 +745,19 @@ void MainWindow::selectString() } } +void MainWindow::about() +{ + QMessageBox *msgBox = new QMessageBox(this); + msgBox->setAttribute(Qt::WA_DeleteOnClose); + msgBox->setWindowTitle(tr("About Qt Distance Field Generator")); + msgBox->setText(tr("<h3>Qt Distance Field Generator</h3>" + "<p>Version %1.<br/>" + "The Qt Distance Field Generator tool allows " + "to prepare a font cache for Qt applications.</p>" + "<p>Copyright (C) %2 The Qt Company Ltd.</p>") + .arg(QLatin1String(QT_VERSION_STR)) + .arg(QLatin1String("2018"))); + msgBox->show(); +} + QT_END_NAMESPACE diff --git a/src/distancefieldgenerator/mainwindow.h b/src/distancefieldgenerator/mainwindow.h index dc209d558..89a83db52 100644 --- a/src/distancefieldgenerator/mainwindow.h +++ b/src/distancefieldgenerator/mainwindow.h @@ -49,6 +49,11 @@ public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); + void open(const QString &path); + +protected: + void closeEvent(QCloseEvent *event) override; + private slots: void openFont(); void startProgressBar(quint16 glyphCount); @@ -62,6 +67,7 @@ private slots: void saveAs(); void displayError(const QString &errorString); void selectString(); + void about(); private: void setupConnections(); diff --git a/src/distancefieldgenerator/mainwindow.ui b/src/distancefieldgenerator/mainwindow.ui index d1f58e537..e7fe0d788 100644 --- a/src/distancefieldgenerator/mainwindow.ui +++ b/src/distancefieldgenerator/mainwindow.ui @@ -121,7 +121,7 @@ <x>0</x> <y>0</y> <width>800</width> - <height>19</height> + <height>23</height> </rect> </property> <widget class="QMenu" name="menu_File"> @@ -141,13 +141,22 @@ <addaction name="actionSelect_all"/> <addaction name="actionSelect_string"/> </widget> + <widget class="QMenu" name="menu_Help"> + <property name="title"> + <string>&Help</string> + </property> + <addaction name="actionHelp"/> + <addaction name="actionAbout_App"/> + <addaction name="actionAbout_Qt"/> + </widget> <addaction name="menu_File"/> <addaction name="menu_Select"/> + <addaction name="menu_Help"/> </widget> <widget class="QStatusBar" name="statusbar"/> <action name="action_Open"> <property name="text"> - <string>&Open font</string> + <string>&Open Font...</string> </property> <property name="shortcut"> <string>Ctrl+O</string> @@ -155,7 +164,7 @@ </action> <action name="action_Save_as"> <property name="text"> - <string>Save &as...</string> + <string>Save &As...</string> </property> </action> <action name="action_Save"> @@ -176,7 +185,7 @@ </action> <action name="actionSelect_all"> <property name="text"> - <string>Select &all</string> + <string>Select &All</string> </property> <property name="shortcut"> <string>Ctrl+A</string> @@ -184,7 +193,22 @@ </action> <action name="actionSelect_string"> <property name="text"> - <string>Select &string</string> + <string>Select &String</string> + </property> + </action> + <action name="actionAbout_App"> + <property name="text"> + <string>About Qt Distance Field Generator</string> + </property> + </action> + <action name="actionAbout_Qt"> + <property name="text"> + <string>About Qt</string> + </property> + </action> + <action name="actionHelp"> + <property name="text"> + <string>Help</string> </property> </action> </widget> diff --git a/src/linguist/linguist/doc/snippets/doc_src_linguist-manual.pro b/src/linguist/linguist/doc/snippets/doc_src_linguist-manual.pro index 511bd942b..ccb27f421 100644 --- a/src/linguist/linguist/doc/snippets/doc_src_linguist-manual.pro +++ b/src/linguist/linguist/doc/snippets/doc_src_linguist-manual.pro @@ -60,8 +60,3 @@ TRANSLATIONS = superapp_dk.ts \ superapp_no.ts \ superapp_se.ts #! [0] - - -#! [2] -CODECFORSRC = UTF-8 -#! [2] diff --git a/src/linguist/linguist/doc/src/linguist-manual.qdoc b/src/linguist/linguist/doc/src/linguist-manual.qdoc index c93515e9d..403e4652c 100644 --- a/src/linguist/linguist/doc/src/linguist-manual.qdoc +++ b/src/linguist/linguist/doc/src/linguist-manual.qdoc @@ -869,18 +869,15 @@ \snippet doc_src_linguist-manual.pro 0 - If your compiler uses a different encoding for its runtime - system than for its source code and you want to use non-ASCII - characters in string literals, you will need to set the \c - CODECFORSRC. For example: - - \snippet doc_src_linguist-manual.pro 2 - - Microsoft Visual Studio 2005 .NET appears to be the only compiler - for which this is necessary. However, if you want to write - portable code, we recommend that you avoid non-ASCII characters - in your source files. You can still specify non-ASCII characters - portably using escape sequences, for example: + \c lupdate expects all source code to be encoded in UTF-8 by default. + Files that feature a BOM (Byte Order Mark) can also be encoded in + UTF-16 or UTF-32. Set the qmake variable \c CODECFORSRC to + \c UTF-16 to parse files without a BOM as UTF-16. + + Some editors, such as Visual Studio, however use a different + encoding by default. One way to avoid encoding issues is to limit any + source code to ASCII, and use escape sequences for translatable strings + with other characters, for example: \snippet doc_src_linguist-manual.cpp 3 diff --git a/src/linguist/linguist/images/mac/filesave.png b/src/linguist/linguist/images/mac/filesave.png Binary files differindex b41ecf531..e65a29d5f 100644 --- a/src/linguist/linguist/images/mac/filesave.png +++ b/src/linguist/linguist/images/mac/filesave.png diff --git a/src/linguist/linguist/images/win/filesave.png b/src/linguist/linguist/images/win/filesave.png Binary files differindex 8feec99be..e65a29d5f 100644 --- a/src/linguist/linguist/images/win/filesave.png +++ b/src/linguist/linguist/images/win/filesave.png diff --git a/src/linguist/lupdate/cpp.cpp b/src/linguist/lupdate/cpp.cpp index cd02de34f..3836bfcfd 100644 --- a/src/linguist/lupdate/cpp.cpp +++ b/src/linguist/lupdate/cpp.cpp @@ -2325,11 +2325,14 @@ void loadCPP(Translator &translator, const QStringList &filenames, ConversionDat parser.recordResults(isHeader(filename)); } - foreach (const QString &filename, filenames) - if (!CppFiles::isBlacklisted(filename)) - if (const Translator *tor = CppFiles::getTranslator(filename)) + foreach (const QString &filename, filenames) { + if (!CppFiles::isBlacklisted(filename)) { + if (const Translator *tor = CppFiles::getTranslator(filename)) { foreach (const TranslatorMessage &msg, tor->messages()) translator.extend(msg, cd); + } + } + } } QT_END_NAMESPACE diff --git a/src/linguist/shared/translator.cpp b/src/linguist/shared/translator.cpp index 5b0538d4e..af669e235 100644 --- a/src/linguist/shared/translator.cpp +++ b/src/linguist/shared/translator.cpp @@ -384,11 +384,14 @@ int Translator::find(const QString &context, { if (!refs.isEmpty()) { for (TMM::ConstIterator it = m_messages.constBegin(); it != m_messages.constEnd(); ++it) { - if (it->context() == context && it->comment() == comment) - foreach (const TranslatorMessage::Reference &itref, it->allReferences()) - foreach (const TranslatorMessage::Reference &ref, refs) + if (it->context() == context && it->comment() == comment) { + foreach (const TranslatorMessage::Reference &itref, it->allReferences()) { + foreach (const TranslatorMessage::Reference &ref, refs) { if (itref == ref) return it - m_messages.constBegin(); + } + } + } } } return -1; diff --git a/src/linguist/shared/translatormessage.cpp b/src/linguist/shared/translatormessage.cpp index f9048de70..0cc17f1de 100644 --- a/src/linguist/shared/translatormessage.cpp +++ b/src/linguist/shared/translatormessage.cpp @@ -73,10 +73,12 @@ void TranslatorMessage::addReferenceUniq(const QString &fileName, int lineNumber } else { if (fileName == m_fileName && lineNumber == m_lineNumber) return; - if (!m_extraRefs.isEmpty()) // Rather common case, so special-case it - foreach (const Reference &ref, m_extraRefs) + if (!m_extraRefs.isEmpty()) { // Rather common case, so special-case it + foreach (const Reference &ref, m_extraRefs) { if (fileName == ref.fileName() && lineNumber == ref.lineNumber()) return; + } + } m_extraRefs.append(Reference(fileName, lineNumber)); } } diff --git a/src/qdoc/doc/qdoc-manual-markupcmds.qdoc b/src/qdoc/doc/qdoc-manual-markupcmds.qdoc index 8ba6efa05..1b6648f90 100644 --- a/src/qdoc/doc/qdoc-manual-markupcmds.qdoc +++ b/src/qdoc/doc/qdoc-manual-markupcmds.qdoc @@ -1470,6 +1470,9 @@ {positioning} and \l {substring} {argument} as the \l {printline-command} {\\printline} command. + If \\printuntil is used without an argument, it expands to all the + lines from the current position to the end of the quoted file. + The lines from the source file are rendered in a separate paragraph, using a monospace font and the standard indentation. The code is shown verbatim. diff --git a/src/qdoc/htmlgenerator.cpp b/src/qdoc/htmlgenerator.cpp index d7f9ae676..032490639 100644 --- a/src/qdoc/htmlgenerator.cpp +++ b/src/qdoc/htmlgenerator.cpp @@ -1431,7 +1431,6 @@ void HtmlGenerator::generateCppReferencePage(Node* node, CodeMarker* marker) } else { if (!s->members().isEmpty()) { - // out() << "<hr />\n"; QString ref = registerRef(s->title().toLower()); out() << "<a name=\"" << ref << "\"></a>" << divNavTop << "\n"; out() << "<h2 id=\"" << ref << "\">" << protectEnc(s->title()) << "</h2>\n"; @@ -1440,7 +1439,6 @@ void HtmlGenerator::generateCppReferencePage(Node* node, CodeMarker* marker) if (!s->reimplementedMembers().isEmpty()) { QString name = QString("Reimplemented ") + s->title(); QString ref = registerRef(name.toLower()); - // out() << "<hr />\n"; out() << "<a name=\"" << ref << "\"></a>" << divNavTop << "\n"; out() << "<h2 id=\"" << ref << "\">" << protectEnc(name) << "</h2>\n"; generateSection(s->reimplementedMembers(), aggregate, marker); @@ -1473,7 +1471,6 @@ void HtmlGenerator::generateCppReferencePage(Node* node, CodeMarker* marker) if (!aggregate->doc().isEmpty()) { generateExtractionMark(aggregate, DetailedDescriptionMark); - //out() << "<hr />\n" out() << "<div class=\"descr\">\n" // QTBUG-9504 << "<h2 id=\"" << detailsRef << "\">" << "Detailed Description" << "</h2>\n"; generateBody(aggregate, marker); @@ -1485,6 +1482,7 @@ void HtmlGenerator::generateCppReferencePage(Node* node, CodeMarker* marker) s = detailsSections->constBegin(); while (s != detailsSections->constEnd()) { + bool headerGenerated = false; if (s->isEmpty()) { ++s; continue; @@ -1496,50 +1494,56 @@ void HtmlGenerator::generateCppReferencePage(Node* node, CodeMarker* marker) NodeVector::ConstIterator m = s->members().constBegin(); while (m != s->members().constEnd()) { - if ((*m)->access() != Node::Private) { // ### check necessary? - if ((*m)->nodeType() != Node::Class) - generateDetailedMember(*m, aggregate, marker); - else { - out() << "<h3> class "; - generateFullName(*m, aggregate); - out() << "</h3>"; - generateBrief(*m, marker, aggregate); - } + if ((*m)->access() == Node::Private) { // ### check necessary? + ++m; + continue; + } + if (!headerGenerated) { + if (!s->divClass().isEmpty()) + out() << "<div class=\"" << s->divClass() << "\">\n"; // QTBUG-9504 + out() << "<h2>" << protectEnc(s->title()) << "</h2>\n"; + headerGenerated = true; + } + if ((*m)->nodeType() != Node::Class) + generateDetailedMember(*m, aggregate, marker); + else { + out() << "<h3> class "; + generateFullName(*m, aggregate); + out() << "</h3>"; + generateBrief(*m, marker, aggregate); + } - QStringList names; - names << (*m)->name(); - if ((*m)->nodeType() == Node::Function) { - const FunctionNode *func = reinterpret_cast<const FunctionNode *>(*m); - if (func->isSomeCtor() || func->isDtor() || func->overloadNumber() != 0) - names.clear(); - } - else if ((*m)->nodeType() == Node::Property) { - const PropertyNode *prop = reinterpret_cast<const PropertyNode *>(*m); - if (!prop->getters().isEmpty() && - !names.contains(prop->getters().first()->name())) - names << prop->getters().first()->name(); - if (!prop->setters().isEmpty()) - names << prop->setters().first()->name(); - if (!prop->resetters().isEmpty()) - names << prop->resetters().first()->name(); - if (!prop->notifiers().isEmpty()) - names << prop->notifiers().first()->name(); - } - else if ((*m)->nodeType() == Node::Enum) { - const EnumNode *enume = reinterpret_cast<const EnumNode*>(*m); - if (enume->flagsType()) - names << enume->flagsType()->name(); - - foreach (const QString &enumName, - enume->doc().enumItemNames().toSet() - - enume->doc().omitEnumItemNames().toSet()) - names << plainCode(marker->markedUpEnumValue(enumName, - enume)); - } + QStringList names; + names << (*m)->name(); + if ((*m)->nodeType() == Node::Function) { + const FunctionNode *func = reinterpret_cast<const FunctionNode *>(*m); + if (func->isSomeCtor() || func->isDtor() || func->overloadNumber() != 0) + names.clear(); + } else if ((*m)->nodeType() == Node::Property) { + const PropertyNode *prop = reinterpret_cast<const PropertyNode *>(*m); + if (!prop->getters().isEmpty() && + !names.contains(prop->getters().first()->name())) + names << prop->getters().first()->name(); + if (!prop->setters().isEmpty()) + names << prop->setters().first()->name(); + if (!prop->resetters().isEmpty()) + names << prop->resetters().first()->name(); + if (!prop->notifiers().isEmpty()) + names << prop->notifiers().first()->name(); + } else if ((*m)->nodeType() == Node::Enum) { + const EnumNode *enume = reinterpret_cast<const EnumNode*>(*m); + if (enume->flagsType()) + names << enume->flagsType()->name(); + + foreach (const QString &enumName, + enume->doc().enumItemNames().toSet() - + enume->doc().omitEnumItemNames().toSet()) + names << plainCode(marker->markedUpEnumValue(enumName, + enume)); } ++m; } - if (!s->divClass().isEmpty()) + if (headerGenerated && !s->divClass().isEmpty()) out() << "</div>\n"; // QTBUG-9504 ++s; } diff --git a/src/qdoc/node.cpp b/src/qdoc/node.cpp index 6e6202f76..976ee5689 100644 --- a/src/qdoc/node.cpp +++ b/src/qdoc/node.cpp @@ -948,7 +948,7 @@ Node *Aggregate::findChildNode(const QString& name, Node::Genus genus, int findF } else { NodeList nodes = childMap_.values(name); if (!nodes.isEmpty()) { - for (int i=0; i<nodes.size(); ++i) { + for (int i = 0; i < nodes.size(); ++i) { Node* node = nodes.at(i); if (genus == node->genus()) { if (findFlags & TypesOnly) { @@ -960,7 +960,8 @@ Node *Aggregate::findChildNode(const QString& name, Node::Genus genus, int findF && !node->isJsBasicType() && !node->isEnumType()) continue; - } + } else if (findFlags & IgnoreModules && node->isModule()) + continue; return node; } } diff --git a/src/qdoc/qdocdatabase.h b/src/qdoc/qdocdatabase.h index 9e53dde53..deb554abe 100644 --- a/src/qdoc/qdocdatabase.h +++ b/src/qdoc/qdocdatabase.h @@ -51,7 +51,8 @@ class QDocDatabase; enum FindFlag { SearchBaseClasses = 0x1, SearchEnumValues = 0x2, - TypesOnly = 0x4 + TypesOnly = 0x4, + IgnoreModules = 0x8 }; class QDocForest diff --git a/src/qdoc/tree.cpp b/src/qdoc/tree.cpp index ea3950a9e..4a7b15b09 100644 --- a/src/qdoc/tree.cpp +++ b/src/qdoc/tree.cpp @@ -885,7 +885,11 @@ const Node* Tree::findNode(const QStringList& path, if (node == 0 || !node->isAggregate()) break; - const Node* next = static_cast<const Aggregate*>(node)->findChildNode(path.at(i), genus, findFlags); + // Clear the TypesOnly flag until the last path segment, as e.g. namespaces are not types. + // We also ignore module nodes as they are not aggregates and thus have no children. + int tmpFlags = (i < path.size() - 1) ? (findFlags & ~TypesOnly) | IgnoreModules : findFlags; + + const Node* next = static_cast<const Aggregate*>(node)->findChildNode(path.at(i), genus, tmpFlags); if (!next && (findFlags & SearchEnumValues) && i == path.size()-1) { next = static_cast<const Aggregate*>(node)->findEnumNodeForValue(path.at(i)); } @@ -893,7 +897,7 @@ const Node* Tree::findNode(const QStringList& path, node->isClass() && (findFlags & SearchBaseClasses)) { NodeList baseClasses = allBaseClasses(static_cast<const ClassNode*>(node)); foreach (const Node* baseClass, baseClasses) { - next = static_cast<const Aggregate*>(baseClass)->findChildNode(path.at(i), genus, findFlags); + next = static_cast<const Aggregate*>(baseClass)->findChildNode(path.at(i), genus, tmpFlags); if (!next && (findFlags & SearchEnumValues) && i == path.size() - 1) next = static_cast<const Aggregate*>(baseClass)->findEnumNodeForValue(path.at(i)); if (next) { diff --git a/src/qtattributionsscanner/qdocgenerator.cpp b/src/qtattributionsscanner/qdocgenerator.cpp index 6cab72e6e..882875ff5 100644 --- a/src/qtattributionsscanner/qdocgenerator.cpp +++ b/src/qtattributionsscanner/qdocgenerator.cpp @@ -143,7 +143,7 @@ static void generate(QTextStream &out, const Package &package, const QDir &baseD tr("Path %1 : cannot open license file %2.") .arg(QDir::toNativeSeparators(package.path)) .arg(QDir::toNativeSeparators(package.licenseFile)) - ) << "\n"; + ) << "*/\n"; return; } out << "\\badcode\n"; diff --git a/src/shared/winutils/qmlutils.cpp b/src/shared/winutils/qmlutils.cpp index 414446499..6e8d5192b 100644 --- a/src/shared/winutils/qmlutils.cpp +++ b/src/shared/winutils/qmlutils.cpp @@ -51,7 +51,7 @@ QString QmlImportScanResult::Module::installPath(const QString &root) const const int lastSlashPos = relativePath.lastIndexOf(QLatin1Char('/')); if (lastSlashPos != -1) { result += QLatin1Char('/'); - result += relativePath.left(lastSlashPos); + result += relativePath.leftRef(lastSlashPos); } return result; } @@ -116,7 +116,7 @@ QmlImportScanResult runQmlImportScanner(const QString &directory, const QStringL + QStringLiteral(": ") + QString::fromLocal8Bit(stdErr); return result; } - QJsonParseError jsonParseError; + QJsonParseError jsonParseError{}; const QJsonDocument data = QJsonDocument::fromJson(stdOut, &jsonParseError); if (data.isNull() ) { *errorMessage = binary + QStringLiteral(" returned invalid JSON output: ") diff --git a/src/shared/winutils/qmlutils.h b/src/shared/winutils/qmlutils.h index a05007103..87e6ca132 100644 --- a/src/shared/winutils/qmlutils.h +++ b/src/shared/winutils/qmlutils.h @@ -47,10 +47,9 @@ struct QmlImportScanResult { QString relativePath; }; - QmlImportScanResult() : ok(false) {} void append(const QmlImportScanResult &other); - bool ok; + bool ok = false; QList<Module> modules; QStringList plugins; }; diff --git a/src/shared/winutils/utils.cpp b/src/shared/winutils/utils.cpp index cdf017715..00a205438 100644 --- a/src/shared/winutils/utils.cpp +++ b/src/shared/winutils/utils.cpp @@ -493,8 +493,6 @@ QString findInPath(const QString &file) const char *qmakeInfixKey = "QT_INFIX"; -QMap<QString, QString> queryQMakeAll(QString *errorMessage); - QMap<QString, QString> queryQMakeAll(QString *errorMessage) { QByteArray stdOut; @@ -819,12 +817,12 @@ inline void determineDebugAndDependentLibs(const ImageNtHeader *nth, const void { const bool hasDebugEntry = nth->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size; QStringList dependentLibraries; - if (dependentLibrariesIn || (isDebugIn && hasDebugEntry && !isMinGW)) + if (dependentLibrariesIn || (isDebugIn != nullptr && hasDebugEntry && !isMinGW)) dependentLibraries = readImportSections(nth, fileMemory, errorMessage); if (dependentLibrariesIn) *dependentLibrariesIn = dependentLibraries; - if (isDebugIn) { + if (isDebugIn != nullptr) { if (isMinGW) { // Use logic that's used e.g. in objdump / pfd library *isDebugIn = !(nth->FileHeader.Characteristics & IMAGE_FILE_DEBUG_STRIPPED); @@ -840,7 +838,7 @@ inline void determineDebugAndDependentLibs(const ImageNtHeader *nth, const void // and debug flags. bool readPeExecutable(const QString &peExecutableFileName, QString *errorMessage, QStringList *dependentLibrariesIn, unsigned *wordSizeIn, - bool *isDebugIn, bool isMinGW) + bool *isDebugIn, bool isMinGW, unsigned short *machineArchIn) { bool result = false; HANDLE hFile = NULL; @@ -890,6 +888,9 @@ bool readPeExecutable(const QString &peExecutableFileName, QString *errorMessage fileMemory, isMinGW, dependentLibrariesIn, isDebugIn, errorMessage); } + if (machineArchIn) + *machineArchIn = ntHeaders->FileHeader.Machine; + result = true; if (optVerboseLevel > 1) { std::wcout << __FUNCTION__ << ": " << QDir::toNativeSeparators(peExecutableFileName) @@ -970,7 +971,7 @@ QString findD3dCompiler(Platform platform, const QString &qtBinDir, unsigned wor #else // Q_OS_WIN bool readPeExecutable(const QString &, QString *errorMessage, - QStringList *, unsigned *, bool *, bool) + QStringList *, unsigned *, bool *, bool, unsigned short *) { *errorMessage = QStringLiteral("Not implemented."); return false; @@ -1032,4 +1033,23 @@ bool patchQtCore(const QString &path, QString *errorMessage) return true; } +#ifdef Q_OS_WIN +QString getArchString(unsigned short machineArch) +{ + switch (machineArch) { + case IMAGE_FILE_MACHINE_I386: + return QStringLiteral("x86"); + case IMAGE_FILE_MACHINE_ARM: + return QStringLiteral("arm"); + case IMAGE_FILE_MACHINE_AMD64: + return QStringLiteral("x64"); + case IMAGE_FILE_MACHINE_ARM64: + return QStringLiteral("arm64"); + default: + break; + } + return QString(); +} +#endif // Q_OS_WIN + QT_END_NAMESPACE diff --git a/src/shared/winutils/utils.h b/src/shared/winutils/utils.h index a5e6f01f7..5552a3665 100644 --- a/src/shared/winutils/utils.h +++ b/src/shared/winutils/utils.h @@ -82,8 +82,8 @@ inline std::wostream &operator<<(std::wostream &str, const QString &s) // Container class for JSON output class JsonOutput { - typedef QPair<QString, QString> SourceTargetMapping; - typedef QList<SourceTargetMapping> SourceTargetMappings; + using SourceTargetMapping = QPair<QString, QString>; + using SourceTargetMappings = QList<SourceTargetMapping>; public: void addFile(const QString &source, const QString &target) @@ -185,21 +185,28 @@ bool runElevatedBackgroundProcess(const QString &binary, const QStringList &args bool readPeExecutable(const QString &peExecutableFileName, QString *errorMessage, QStringList *dependentLibraries = 0, unsigned *wordSize = 0, - bool *isDebug = 0, bool isMinGW = false); + bool *isDebug = 0, bool isMinGW = false, unsigned short *machineArch = nullptr); bool readElfExecutable(const QString &elfExecutableFileName, QString *errorMessage, QStringList *dependentLibraries = 0, unsigned *wordSize = 0, bool *isDebug = 0); inline bool readExecutable(const QString &executableFileName, Platform platform, QString *errorMessage, QStringList *dependentLibraries = 0, - unsigned *wordSize = 0, bool *isDebug = 0) + unsigned *wordSize = 0, bool *isDebug = 0, unsigned short *machineArch = nullptr) { return platform == Unix ? readElfExecutable(executableFileName, errorMessage, dependentLibraries, wordSize, isDebug) : readPeExecutable(executableFileName, errorMessage, dependentLibraries, wordSize, isDebug, - (platform == WindowsDesktopMinGW)); + (platform == WindowsDesktopMinGW), machineArch); } +#ifdef Q_OS_WIN +# if !defined(IMAGE_FILE_MACHINE_ARM64) +# define IMAGE_FILE_MACHINE_ARM64 0xAA64 +# endif +QString getArchString (unsigned short machineArch); +#endif // Q_OS_WIN + // Return dependent modules of executable files. inline QStringList findDependentLibraries(const QString &executableFileName, Platform platform, QString *errorMessage) diff --git a/src/windeployqt/main.cpp b/src/windeployqt/main.cpp index 738887c0f..247749aaa 100644 --- a/src/windeployqt/main.cpp +++ b/src/windeployqt/main.cpp @@ -40,6 +40,7 @@ #include <QtCore/QOperatingSystemVersion> #include <QtCore/QSharedPointer> #include <QtCore/QVector> +#include <QtCore/qt_windows.h> #include <algorithm> #include <iostream> @@ -180,12 +181,11 @@ static inline QString webProcessBinary(const char *binaryName, Platform p) static QByteArray formatQtModules(quint64 mask, bool option = false) { QByteArray result; - const size_t qtModulesCount = sizeof(qtModuleEntries)/sizeof(QtModuleEntry); - for (size_t i = 0; i < qtModulesCount; ++i) { - if (mask & qtModuleEntries[i].module) { + for (const auto &qtModule : qtModuleEntries) { + if (mask & qtModule.module) { if (!result.isEmpty()) result.append(' '); - result.append(option ? qtModuleEntries[i].option : qtModuleEntries[i].libraryName); + result.append(option ? qtModule.option : qtModule.libraryName); } } return result; @@ -311,9 +311,8 @@ enum CommandLineParseFlag { static inline int parseArguments(const QStringList &arguments, QCommandLineParser *parser, Options *options, QString *errorMessage) { - typedef QSharedPointer<QCommandLineOption> CommandLineOptionPtr; - typedef QPair<CommandLineOptionPtr, quint64> OptionMaskPair; - typedef QVector<OptionMaskPair> OptionMaskVector; + using CommandLineOptionPtr = QSharedPointer<QCommandLineOption>; + using OptionPtrVector = QVector<CommandLineOptionPtr>; parser->setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); parser->setApplicationDescription(QStringLiteral("Qt Deploy Tool ") + QLatin1String(QT_VERSION_STR) @@ -450,21 +449,22 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse parser->addPositionalArgument(QStringLiteral("[files]"), QStringLiteral("Binaries or directory containing the binary.")); - OptionMaskVector enabledModules; - OptionMaskVector disabledModules; - const size_t qtModulesCount = sizeof(qtModuleEntries)/sizeof(QtModuleEntry); - for (size_t i = 0; i < qtModulesCount; ++i) { + OptionPtrVector enabledModuleOptions; + OptionPtrVector disabledModuleOptions; + const int qtModulesCount = int(sizeof(qtModuleEntries) / sizeof(QtModuleEntry)); + enabledModuleOptions.reserve(qtModulesCount); + disabledModuleOptions.reserve(qtModulesCount); + for (int i = 0; i < qtModulesCount; ++i) { const QString option = QLatin1String(qtModuleEntries[i].option); const QString name = QLatin1String(qtModuleEntries[i].libraryName); const QString enabledDescription = QStringLiteral("Add ") + name + QStringLiteral(" module."); CommandLineOptionPtr enabledOption(new QCommandLineOption(option, enabledDescription)); parser->addOption(*enabledOption.data()); - enabledModules.push_back(OptionMaskPair(enabledOption, qtModuleEntries[i].module)); - + enabledModuleOptions.append(enabledOption); const QString disabledDescription = QStringLiteral("Remove ") + name + QStringLiteral(" module."); CommandLineOptionPtr disabledOption(new QCommandLineOption(QStringLiteral("no-") + option, disabledDescription)); - disabledModules.push_back(OptionMaskPair(disabledOption, qtModuleEntries[i].module)); + disabledModuleOptions.append(disabledOption); parser->addOption(*disabledOption.data()); } @@ -540,11 +540,11 @@ static inline int parseArguments(const QStringList &arguments, QCommandLineParse options->patchQt = !parser->isSet(noPatchQtOption); - for (size_t i = 0; i < qtModulesCount; ++i) { - if (parser->isSet(*enabledModules.at(int(i)).first.data())) - options->additionalLibraries |= enabledModules.at(int(i)).second; - if (parser->isSet(*disabledModules.at(int(i)).first.data())) - options->disabledLibraries |= disabledModules.at(int(i)).second; + for (int i = 0; i < qtModulesCount; ++i) { + if (parser->isSet(*enabledModuleOptions.at(i))) + options->additionalLibraries |= qtModuleEntries[i].module; + if (parser->isSet(*disabledModuleOptions.at(i))) + options->disabledLibraries |= qtModuleEntries[i].module; } // Add some dependencies @@ -689,13 +689,13 @@ static inline bool isQtModule(const QString &libName) // Helper for recursively finding all dependent Qt libraries. static bool findDependentQtLibraries(const QString &qtBinDir, const QString &binary, Platform platform, QString *errorMessage, QStringList *result, - unsigned *wordSize = 0, bool *isDebug = 0, + unsigned *wordSize = 0, bool *isDebug = 0, unsigned short *machineArch = 0, int *directDependencyCount = 0, int recursionDepth = 0) { QStringList dependentLibs; if (directDependencyCount) *directDependencyCount = 0; - if (!readExecutable(binary, platform, errorMessage, &dependentLibs, wordSize, isDebug)) { + if (!readExecutable(binary, platform, errorMessage, &dependentLibs, wordSize, isDebug, machineArch)) { errorMessage->prepend(QLatin1String("Unable to find dependent libraries of ") + QDir::toNativeSeparators(binary) + QLatin1String(" :")); return false; @@ -715,7 +715,7 @@ static bool findDependentQtLibraries(const QString &qtBinDir, const QString &bin *directDependencyCount = end - start; // Recurse for (int i = start; i < end; ++i) - if (!findDependentQtLibraries(qtBinDir, result->at(i), platform, errorMessage, result, 0, 0, 0, recursionDepth + 1)) + if (!findDependentQtLibraries(qtBinDir, result->at(i), platform, errorMessage, result, 0, 0, 0, 0, recursionDepth + 1)) return false; return true; } @@ -838,10 +838,9 @@ static const PluginModuleMapping pluginModuleMappings[] = static inline quint64 qtModuleForPlugin(const QString &subDirName) { - const PluginModuleMapping *end = pluginModuleMappings - + sizeof(pluginModuleMappings) / sizeof(pluginModuleMappings[0]); - const PluginModuleMapping *result = - std::find_if(pluginModuleMappings, end, + const auto end = std::end(pluginModuleMappings); + const auto result = + std::find_if(std::begin(pluginModuleMappings), end, [&subDirName] (const PluginModuleMapping &m) { return subDirName == QLatin1String(m.directoryName); }); return result != end ? result->module : 0; // "designer" } @@ -860,12 +859,11 @@ static quint64 qtModule(QString module, const QString &infix) if (endPos > 0) module.truncate(endPos); // That should leave us with 'Qt5Core<d>'. - const size_t qtModulesCount = sizeof(qtModuleEntries)/sizeof(QtModuleEntry); - for (size_t i = 0; i < qtModulesCount; ++i) { - const QLatin1String libraryName(qtModuleEntries[i].libraryName); + for (const auto &qtModule : qtModuleEntries) { + const QLatin1String libraryName(qtModule.libraryName); if (module == libraryName || (module.size() == libraryName.size() + 1 && module.startsWith(libraryName))) { - return qtModuleEntries[i].module; + return qtModule.module; } } return 0; @@ -954,10 +952,9 @@ QStringList findQtPlugins(quint64 *usedQtModules, quint64 disabledQtModules, static QStringList translationNameFilters(quint64 modules, const QString &prefix) { QStringList result; - const size_t qtModulesCount = sizeof(qtModuleEntries)/sizeof(QtModuleEntry); - for (size_t i = 0; i < qtModulesCount; ++i) { - if ((qtModuleEntries[i].module & modules) && qtModuleEntries[i].translation) { - const QString name = QLatin1String(qtModuleEntries[i].translation) + + for (const auto &qtModule : qtModuleEntries) { + if ((qtModule.module & modules) && qtModule.translation) { + const QString name = QLatin1String(qtModule.translation) + QLatin1Char('_') + prefix + QStringLiteral(".qm"); if (!result.contains(name)) result.push_back(name); @@ -1048,6 +1045,7 @@ static QString libraryPath(const QString &libraryLocation, const char *name, } static QString vcDebugRedistDir() { return QStringLiteral("Debug_NonRedist"); } +static QString onecoreRedistDir() { return QStringLiteral("onecore"); } static QString vcRedistDir() { @@ -1089,7 +1087,7 @@ static QString vcRedistDir() return QString(); } -static QStringList compilerRunTimeLibs(Platform platform, bool isDebug, unsigned wordSize) +static QStringList compilerRunTimeLibs(Platform platform, bool isDebug, unsigned short machineArch) { QStringList result; switch (platform) { @@ -1103,9 +1101,8 @@ static QStringList compilerRunTimeLibs(Platform platform, bool isDebug, unsigned const QString binPath = QFileInfo(gcc).absolutePath(); QStringList filters; const QString suffix = QLatin1Char('*') + sharedLibrarySuffix(platform); - const size_t count = sizeof(minGwRuntimes) / sizeof(minGwRuntimes[0]); - for (size_t i = 0; i < count; ++i) - filters.append(QLatin1String(minGwRuntimes[i]) + suffix); + for (auto minGwRuntime : minGwRuntimes) + filters.append(QLatin1String(minGwRuntime) + suffix); const QFileInfoList &dlls = QDir(binPath).entryInfoList(filters, QDir::Files); for (const QFileInfo &dllFi : dlls) result.append(dllFi.absoluteFilePath()); @@ -1117,10 +1114,10 @@ static QStringList compilerRunTimeLibs(Platform platform, bool isDebug, unsigned break; QStringList redistFiles; QDir vcRedistDir(vcRedistDirName); - const QString wordSizeString(QLatin1String(wordSize > 32 ? "x64" : "x86")); + const QString machineArchString = getArchString(machineArch); if (isDebug) { // Append DLLs from Debug_NonRedist\x??\Microsoft.VC<version>.DebugCRT. - if (vcRedistDir.cd(vcDebugRedistDir()) && vcRedistDir.cd(wordSizeString)) { + if (vcRedistDir.cd(vcDebugRedistDir()) && vcRedistDir.cd(machineArchString)) { const QStringList names = vcRedistDir.entryList(QStringList(QStringLiteral("Microsoft.VC*.DebugCRT")), QDir::Dirs); if (!names.isEmpty() && vcRedistDir.cd(names.first())) { const QFileInfoList &dlls = vcRedistDir.entryInfoList(QStringList(QLatin1String("*.dll"))); @@ -1134,10 +1131,10 @@ static QStringList compilerRunTimeLibs(Platform platform, bool isDebug, unsigned if (!countryCodes.isEmpty()) // Pre MSVC2017 releaseRedistDir += QLatin1Char('/') + countryCodes.constFirst(); QFileInfo fi(releaseRedistDir + QLatin1Char('/') + QStringLiteral("vc_redist.") - + wordSizeString + QStringLiteral(".exe")); + + machineArchString + QStringLiteral(".exe")); if (!fi.isFile()) { // Pre MSVC2017/15.5 fi.setFile(releaseRedistDir + QLatin1Char('/') + QStringLiteral("vcredist_") - + wordSizeString + QStringLiteral(".exe")); + + machineArchString + QStringLiteral(".exe")); } if (fi.isFile()) redistFiles.append(fi.absoluteFilePath()); @@ -1190,24 +1187,6 @@ static bool updateLibrary(const QString &sourceFileName, const QString &targetDi return true; } -// Check for a Qt Quick Controls import path and return the version. -// 'QtQuick/Controls' ==> 1, or 'QtQuick/Controls.2' ==> 2. -static inline int quickControlsImportPath(const QString &ip) -{ - if (ip.contains(QLatin1String("Qt/labs/calendar")) - || ip.contains(QLatin1String("Qt/labs/folderlistmodel")) - || ip.contains(QLatin1String("Qt/labs/settings")) - || ip.contains(QLatin1String("QtQuick/Templates.2")) - || ip.contains(QLatin1String("QtQuick/Controls.2"))) { - return 2; - } - if (ip.endsWith(QLatin1String("QtQuick/Dialogs")) || ip.contains(QLatin1String("QtQuick/Dialogs/")) - || ip.contains(QLatin1String("QtQuick/Controls"))) { - return 1; // Dialogs only in v1, so far; no version number on directory: v1. - } - return 0; // Non-controls import -} - static DeployResult deploy(const Options &options, const QMap<QString, QString> &qmakeVariables, QString *errorMessage) @@ -1228,9 +1207,10 @@ static DeployResult deploy(const Options &options, QStringList dependentQtLibs; bool detectedDebug; unsigned wordSize; + unsigned short machineArch; int directDependencyCount = 0; if (!findDependentQtLibraries(libraryLocation, options.binaries.first(), options.platform, errorMessage, &dependentQtLibs, &wordSize, - &detectedDebug, &directDependencyCount)) { + &detectedDebug, &machineArch, &directDependencyCount)) { return result; } for (int b = 1; b < options.binaries.size(); ++b) { @@ -1329,7 +1309,7 @@ static DeployResult deploy(const Options &options, qmlScanResult.append(scanResult); // Additional dependencies of QML plugins. for (const QString &plugin : qAsConst(qmlScanResult.plugins)) { - if (!findDependentQtLibraries(libraryLocation, plugin, options.platform, errorMessage, &dependentQtLibs, &wordSize, &detectedDebug)) + if (!findDependentQtLibraries(libraryLocation, plugin, options.platform, errorMessage, &dependentQtLibs, &wordSize, &detectedDebug, &machineArch)) return result; } if (optVerboseLevel >= 1) { @@ -1369,12 +1349,11 @@ static DeployResult deploy(const Options &options, // Apply options flags and re-add library names. QString qtGuiLibrary; - const size_t qtModulesCount = sizeof(qtModuleEntries)/sizeof(QtModuleEntry); - for (size_t i = 0; i < qtModulesCount; ++i) { - if (result.deployedQtLibraries & qtModuleEntries[i].module) { - const QString library = libraryPath(libraryLocation, qtModuleEntries[i].libraryName, qtLibInfix, options.platform, isDebug); + for (const auto &qtModule : qtModuleEntries) { + if (result.deployedQtLibraries & qtModule.module) { + const QString library = libraryPath(libraryLocation, qtModule.libraryName, qtLibInfix, options.platform, isDebug); deployedQtLibraries.append(library); - if (qtModuleEntries[i].module == QtGuiModule) + if (qtModule.module == QtGuiModule) qtGuiLibrary = library; } } @@ -1411,7 +1390,7 @@ static DeployResult deploy(const Options &options, if (options.angleDetection != Options::AngleDetectionForceOff && (dependsOnAngle || dependsOnCombinedAngle || !dependsOnOpenGl || options.angleDetection == Options::AngleDetectionForceOn)) { const QString combinedAngleFullPath = qtBinDir + slash + libCombinedQtAngleName; - if (QFileInfo(combinedAngleFullPath).exists()) { + if (QFileInfo::exists(combinedAngleFullPath)) { deployedQtLibraries.append(combinedAngleFullPath); } else { const QString libGlesFullPath = qtBinDir + slash + libGlesName; @@ -1423,7 +1402,8 @@ static DeployResult deploy(const Options &options, deployedQtLibraries.append(libEglFullPath); } // Find the system D3d Compiler matching the D3D library. - if (options.systemD3dCompiler && !options.isWinRt()) { + // Any arm64 OS will be new enough to be shipped with the D3DCompiler inbox. + if (options.systemD3dCompiler && !options.isWinRt() && machineArch != IMAGE_FILE_MACHINE_ARM64) { const QString d3dCompiler = findD3dCompiler(options.platform, qtBinDir, wordSize); if (d3dCompiler.isEmpty()) { std::wcerr << "Warning: Cannot find any version of the d3dcompiler DLL.\n"; @@ -1472,7 +1452,7 @@ static DeployResult deploy(const Options &options, options.directory : options.libraryDirectory; QStringList libraries = deployedQtLibraries; if (options.compilerRunTime) - libraries.append(compilerRunTimeLibs(options.platform, isDebug, wordSize)); + libraries.append(compilerRunTimeLibs(options.platform, isDebug, machineArch)); for (const QString &qtLib : qAsConst(libraries)) { if (!updateLibrary(qtLib, targetPath, options, errorMessage)) return result; @@ -1604,8 +1584,8 @@ static bool deployWebEngineCore(const QMap<QString, QString> &qmakeVariables, const QString resourcesTargetDir(options.directory + resourcesSubDir); if (!createDirectory(resourcesTargetDir, errorMessage)) return false; - for (size_t i = 0; i < sizeof(installDataFiles)/sizeof(installDataFiles[0]); ++i) { - if (!updateFile(resourcesSourceDir + QLatin1String(installDataFiles[i]), + for (auto installDataFile : installDataFiles) { + if (!updateFile(resourcesSourceDir + QLatin1String(installDataFile), resourcesTargetDir, options.updateFileFlags, options.json, errorMessage)) { return false; } @@ -1622,21 +1602,20 @@ static bool deployWebEngineCore(const QMap<QString, QString> &qmakeVariables, return createDirectory(options.translationsDirectory, errorMessage) && updateFile(translations.absoluteFilePath(), options.translationsDirectory, options.updateFileFlags, options.json, errorMessage); - } else { - // Translations have been turned off, but QtWebEngine needs at least one. - const QFileInfo enUSpak(translations.filePath() + QStringLiteral("/en-US.pak")); - if (!enUSpak.exists()) { - std::wcerr << "Warning: Cannot find " - << QDir::toNativeSeparators(enUSpak.absoluteFilePath()) << ".\n"; - return true; - } - const QString webEngineTranslationsDir = options.translationsDirectory + QLatin1Char('/') - + translations.fileName(); - if (!createDirectory(webEngineTranslationsDir, errorMessage)) - return false; - return updateFile(enUSpak.absoluteFilePath(), webEngineTranslationsDir, - options.updateFileFlags, options.json, errorMessage); } + // Translations have been turned off, but QtWebEngine needs at least one. + const QFileInfo enUSpak(translations.filePath() + QStringLiteral("/en-US.pak")); + if (!enUSpak.exists()) { + std::wcerr << "Warning: Cannot find " + << QDir::toNativeSeparators(enUSpak.absoluteFilePath()) << ".\n"; + return true; + } + const QString webEngineTranslationsDir = options.translationsDirectory + QLatin1Char('/') + + translations.fileName(); + if (!createDirectory(webEngineTranslationsDir, errorMessage)) + return false; + return updateFile(enUSpak.absoluteFilePath(), webEngineTranslationsDir, + options.updateFileFlags, options.json, errorMessage); } int main(int argc, char **argv) diff --git a/src/winrtrunner/appxlocalengine.cpp b/src/winrtrunner/appxlocalengine.cpp index e255f0a98..69bc39919 100644 --- a/src/winrtrunner/appxlocalengine.cpp +++ b/src/winrtrunner/appxlocalengine.cpp @@ -690,6 +690,31 @@ bool AppxLocalEngine::setLoopbackExemptServerEnabled(bool enabled) return true; } +bool AppxLocalEngine::setLoggingRules(const QByteArray &rules) +{ + qCDebug(lcWinRtRunner) << __FUNCTION__; + + QDir loggingIniDir(devicePath(QLatin1String("QtProject"))); + if (!loggingIniDir.exists() && !loggingIniDir.mkpath(QStringLiteral("."))) { + qCWarning(lcWinRtRunner) << "Could not create" << loggingIniDir; + return false; + } + QFile loggingIniFile(loggingIniDir.absolutePath().append(QLatin1String("/qtlogging.ini"))); + if (loggingIniFile.exists() && !loggingIniFile.remove()) { + qCWarning(lcWinRtRunner) << loggingIniFile << "already exists."; + return false; + } + if (!loggingIniFile.open(QIODevice::WriteOnly | QIODevice::Text)) { + qCWarning(lcWinRtRunner) << "Could not open" << loggingIniFile << "for writing."; + return false; + } + + QTextStream stream(&loggingIniFile); + stream << "[Rules]\n" << rules; + + return true; +} + bool AppxLocalEngine::suspend() { diff --git a/src/winrtrunner/appxlocalengine.h b/src/winrtrunner/appxlocalengine.h index 291149bd3..0049b6ba4 100644 --- a/src/winrtrunner/appxlocalengine.h +++ b/src/winrtrunner/appxlocalengine.h @@ -64,6 +64,7 @@ public: bool disableDebugging() override; bool setLoopbackExemptClientEnabled(bool enabled) override; bool setLoopbackExemptServerEnabled(bool enabled) override; + bool setLoggingRules(const QByteArray &rules) override; bool suspend() override; bool waitForFinished(int secs) override; bool stop() override; diff --git a/src/winrtrunner/appxphoneengine.cpp b/src/winrtrunner/appxphoneengine.cpp index e45d007e4..39c3b2712 100644 --- a/src/winrtrunner/appxphoneengine.cpp +++ b/src/winrtrunner/appxphoneengine.cpp @@ -471,6 +471,12 @@ bool AppxPhoneEngine::setLoopbackExemptServerEnabled(bool) return false; } +bool AppxPhoneEngine::setLoggingRules(const QByteArray &) +{ + qCDebug(lcWinRtRunner) << __FUNCTION__; + return false; +} + bool AppxPhoneEngine::suspend() { qCDebug(lcWinRtRunner) << __FUNCTION__; diff --git a/src/winrtrunner/appxphoneengine.h b/src/winrtrunner/appxphoneengine.h index 641bf4653..b462e797f 100644 --- a/src/winrtrunner/appxphoneengine.h +++ b/src/winrtrunner/appxphoneengine.h @@ -64,6 +64,7 @@ public: bool disableDebugging() override; bool setLoopbackExemptClientEnabled(bool enabled) override; bool setLoopbackExemptServerEnabled(bool enabled) override; + bool setLoggingRules(const QByteArray &rules) override; bool suspend() override; bool waitForFinished(int secs) override; bool stop() override; diff --git a/src/winrtrunner/main.cpp b/src/winrtrunner/main.cpp index db22b4461..bf4e8fabf 100644 --- a/src/winrtrunner/main.cpp +++ b/src/winrtrunner/main.cpp @@ -40,6 +40,7 @@ #include <QtCore/QCommandLineParser> #include <QtCore/QCoreApplication> #include <QtCore/QDir> +#include <QtCore/QRegExp> #include <QtCore/QStringList> #include <QtCore/QMap> #include <QtCore/QLoggingCategory> @@ -52,6 +53,23 @@ QT_USE_NAMESPACE int main(int argc, char *argv[]) { + // If logging rules are set via env variable, we pass these to the application we are running. + // winrtrunner behaves different from other applications in the regard that its logging rules + // have to be enabled explicitly. Setting "*=true" will not enable extended logging. Reason is + // CI setting "*=true" if an auto test fails and additional winrtrunner output might just + // confuse users. + const QByteArray loggingRules = qgetenv("QT_LOGGING_RULES"); + const QList<QByteArray> rules = loggingRules.split(';'); + QRegExp runnerExp(QLatin1String("^qt\\.winrtrunner.*\\s*=\\s*true\\s*$")); + bool runnerRuleFound = false; + for (const QByteArray &rule : rules) { + if (runnerExp.indexIn(QLatin1String(rule)) != -1) { + runnerRuleFound = true; + break; + } + } + if (!runnerRuleFound) + qunsetenv("QT_LOGGING_RULES"); QCoreApplication a(argc, argv); QCommandLineParser parser; parser.setApplicationDescription(QLatin1String("winrtrunner installs, runs, and collects test " @@ -118,7 +136,7 @@ int main(int argc, char *argv[]) QCommandLineOption deviceOption(QStringLiteral("device"), QLatin1String("Specifies the device to target as a device name " - " or index. Use --list-devices to find available " + "or index. Use --list-devices to find available " "devices. The default device is the first device " "found for the active run profile."), QStringLiteral("name|index")); @@ -282,6 +300,11 @@ int main(int argc, char *argv[]) return ignoreErrors ? 0 : 3; } + if (!loggingRules.isNull() && !runner.setLoggingRules(loggingRules)) { + qCDebug(lcWinRtRunner) << "Could not set logging rules, exiting with code 3."; + return ignoreErrors ? 0 : 3; + } + if (parser.isSet(debugOption)) { const QString &debuggerExecutable = parser.value(debugOption); const QString &debuggerArguments = parser.value(debuggerArgumentsOption); diff --git a/src/winrtrunner/runner.cpp b/src/winrtrunner/runner.cpp index 9794fd605..e816d9baa 100644 --- a/src/winrtrunner/runner.cpp +++ b/src/winrtrunner/runner.cpp @@ -233,6 +233,14 @@ bool Runner::setLoopbackExemptServerEnabled(bool enabled) return d->engine->setLoopbackExemptServerEnabled(enabled); } +bool Runner::setLoggingRules(const QByteArray &rules) +{ + Q_D(Runner); + Q_ASSERT(d->engine); + + return d->engine->setLoggingRules(rules); +} + bool Runner::suspend() { Q_D(Runner); diff --git a/src/winrtrunner/runner.h b/src/winrtrunner/runner.h index 743156154..00b251be8 100644 --- a/src/winrtrunner/runner.h +++ b/src/winrtrunner/runner.h @@ -70,6 +70,7 @@ public: bool disableDebugging(); bool setLoopbackExemptClientEnabled(bool enabled); bool setLoopbackExemptServerEnabled(bool enabled); + bool setLoggingRules(const QByteArray &rules); bool suspend(); bool stop(); bool wait(int maxWaitTime = 0); diff --git a/src/winrtrunner/runnerengine.h b/src/winrtrunner/runnerengine.h index 4cdd8f36f..44565c46c 100644 --- a/src/winrtrunner/runnerengine.h +++ b/src/winrtrunner/runnerengine.h @@ -55,6 +55,7 @@ public: virtual bool disableDebugging() = 0; virtual bool setLoopbackExemptClientEnabled(bool enabled) = 0; virtual bool setLoopbackExemptServerEnabled(bool enabled) = 0; + virtual bool setLoggingRules(const QByteArray &rules) = 0; virtual bool suspend() = 0; virtual bool waitForFinished(int secs) = 0; virtual bool stop() = 0; |