diff options
Diffstat (limited to 'src')
123 files changed, 4914 insertions, 395 deletions
diff --git a/src/imports/imports.pro b/src/imports/imports.pro index f7002f9ed5..ff7b6e75af 100644 --- a/src/imports/imports.pro +++ b/src/imports/imports.pro @@ -10,6 +10,7 @@ SUBDIRS += \ qtHaveModule(quick) { SUBDIRS += \ + layouts \ qtquick2 \ particles \ window \ diff --git a/src/imports/layouts/layouts.pro b/src/imports/layouts/layouts.pro new file mode 100644 index 0000000000..26574150de --- /dev/null +++ b/src/imports/layouts/layouts.pro @@ -0,0 +1,22 @@ +CXX_MODULE = qml +TARGET = qquicklayoutsplugin +TARGETPATH = QtQuick/Layouts +IMPORT_VERSION = 1.2 + +QT *= qml-private quick-private gui-private core-private + +SOURCES += plugin.cpp \ + qquicklayout.cpp \ + qquicklinearlayout.cpp \ + qquickstacklayout.cpp \ + qquickgridlayoutengine.cpp \ + qquicklayoutstyleinfo.cpp + +HEADERS += \ + qquicklayout_p.h \ + qquicklinearlayout_p.h \ + qquickstacklayout_p.h \ + qquickgridlayoutengine_p.h \ + qquicklayoutstyleinfo_p.h + +load(qml_plugin) diff --git a/src/imports/layouts/plugin.cpp b/src/imports/layouts/plugin.cpp new file mode 100644 index 0000000000..4552b7219b --- /dev/null +++ b/src/imports/layouts/plugin.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Layouts module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtQml/qqmlextensionplugin.h> + +#include "qquicklinearlayout_p.h" +#include "qquickstacklayout_p.h" + +QT_BEGIN_NAMESPACE + +//![class decl] +class QtQuickLayoutsPlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface/1.0") +public: + virtual void registerTypes(const char *uri) + { + Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.Layouts")); + Q_UNUSED(uri); + + qmlRegisterType<QQuickRowLayout>(uri, 1, 0, "RowLayout"); + qmlRegisterType<QQuickColumnLayout>(uri, 1, 0, "ColumnLayout"); + qmlRegisterType<QQuickGridLayout>(uri, 1, 0, "GridLayout"); + qmlRegisterType<QQuickStackLayout>(uri, 1, 3, "StackLayout"); + qmlRegisterUncreatableType<QQuickLayout>(uri, 1, 0, "Layout", + QStringLiteral("Do not create objects of type Layout")); + qmlRegisterUncreatableType<QQuickLayout>(uri, 1, 2, "Layout", + QStringLiteral("Do not create objects of type Layout")); + qmlRegisterRevision<QQuickGridLayoutBase, 1>(uri, 1, 1); + } +}; +//![class decl] + +QT_END_NAMESPACE + +#include "plugin.moc" diff --git a/src/imports/layouts/plugins.qmltypes b/src/imports/layouts/plugins.qmltypes new file mode 100644 index 0000000000..b130215b62 --- /dev/null +++ b/src/imports/layouts/plugins.qmltypes @@ -0,0 +1,102 @@ +import QtQuick.tooling 1.2 + +// This file describes the plugin-supplied types contained in the library. +// It is used for QML tooling purposes only. +// +// This file was auto-generated by: +// 'qmlplugindump -nonrelocatable QtQuick.Layouts 1.2' + +Module { + dependencies: [] + Component { + name: "QQuickColumnLayout" + defaultProperty: "data" + prototype: "QQuickLinearLayout" + exports: ["QtQuick.Layouts/ColumnLayout 1.0"] + exportMetaObjectRevisions: [0] + } + Component { + name: "QQuickGridLayout" + defaultProperty: "data" + prototype: "QQuickGridLayoutBase" + exports: ["QtQuick.Layouts/GridLayout 1.0"] + exportMetaObjectRevisions: [0] + Enum { + name: "Flow" + values: { + "LeftToRight": 0, + "TopToBottom": 1 + } + } + Property { name: "columnSpacing"; type: "double" } + Property { name: "rowSpacing"; type: "double" } + Property { name: "columns"; type: "int" } + Property { name: "rows"; type: "int" } + Property { name: "flow"; type: "Flow" } + } + Component { + name: "QQuickGridLayoutBase" + defaultProperty: "data" + prototype: "QQuickLayout" + Property { name: "layoutDirection"; revision: 1; type: "Qt::LayoutDirection" } + Signal { name: "layoutDirectionChanged"; revision: 1 } + } + Component { + name: "QQuickLayout" + defaultProperty: "data" + prototype: "QQuickItem" + exports: ["QtQuick.Layouts/Layout 1.0", "QtQuick.Layouts/Layout 1.2"] + isCreatable: false + exportMetaObjectRevisions: [0, 0] + attachedType: "QQuickLayoutAttached" + } + Component { + name: "QQuickLayoutAttached" + prototype: "QObject" + Property { name: "minimumWidth"; type: "double" } + Property { name: "minimumHeight"; type: "double" } + Property { name: "preferredWidth"; type: "double" } + Property { name: "preferredHeight"; type: "double" } + Property { name: "maximumWidth"; type: "double" } + Property { name: "maximumHeight"; type: "double" } + Property { name: "fillHeight"; type: "bool" } + Property { name: "fillWidth"; type: "bool" } + Property { name: "row"; type: "int" } + Property { name: "column"; type: "int" } + Property { name: "rowSpan"; type: "int" } + Property { name: "columnSpan"; type: "int" } + Property { name: "alignment"; type: "Qt::Alignment" } + Property { name: "margins"; type: "double" } + Property { name: "leftMargin"; type: "double" } + Property { name: "topMargin"; type: "double" } + Property { name: "rightMargin"; type: "double" } + Property { name: "bottomMargin"; type: "double" } + } + Component { + name: "QQuickLinearLayout" + defaultProperty: "data" + prototype: "QQuickGridLayoutBase" + Property { name: "spacing"; type: "double" } + } + Component { + name: "QQuickRowLayout" + defaultProperty: "data" + prototype: "QQuickLinearLayout" + exports: ["QtQuick.Layouts/RowLayout 1.0"] + exportMetaObjectRevisions: [0] + } + Component { + name: "QQuickStackLayout" + defaultProperty: "data" + prototype: "QQuickLayout" + exports: ["QtQuick.Layouts/StackLayout 1.3"] + exportMetaObjectRevisions: [0] + Property { name: "count"; type: "int"; isReadonly: true } + Property { name: "currentIndex"; type: "int" } + Method { + name: "itemAt" + type: "QQuickItem*" + Parameter { name: "index"; type: "int" } + } + } +} diff --git a/src/imports/layouts/qmldir b/src/imports/layouts/qmldir new file mode 100644 index 0000000000..00f85f7d64 --- /dev/null +++ b/src/imports/layouts/qmldir @@ -0,0 +1,5 @@ +module QtQuick.Layouts +plugin qquicklayoutsplugin +classname QtQuickLayoutsPlugin +typeinfo plugins.qmltypes +designersupported diff --git a/src/imports/layouts/qquickgridlayoutengine.cpp b/src/imports/layouts/qquickgridlayoutengine.cpp new file mode 100644 index 0000000000..fe716f0694 --- /dev/null +++ b/src/imports/layouts/qquickgridlayoutengine.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Layouts module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickitem.h" +#include "qquickgridlayoutengine_p.h" +#include "qquicklayout_p.h" + +QT_BEGIN_NAMESPACE + +void QQuickGridLayoutEngine::setAlignment(QQuickItem *quickItem, Qt::Alignment alignment) +{ + if (QQuickGridLayoutItem *item = findLayoutItem(quickItem)) { + item->setAlignment(alignment); + invalidate(); + } +} + +Qt::Alignment QQuickGridLayoutEngine::alignment(QQuickItem *quickItem) const +{ + if (QGridLayoutItem *item = findLayoutItem(quickItem)) + return item->alignment(); + return 0; +} + +QT_END_NAMESPACE diff --git a/src/imports/layouts/qquickgridlayoutengine_p.h b/src/imports/layouts/qquickgridlayoutengine_p.h new file mode 100644 index 0000000000..86f56a5af4 --- /dev/null +++ b/src/imports/layouts/qquickgridlayoutengine_p.h @@ -0,0 +1,164 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Layouts module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKGRIDLAYOUTENGINE_P_H +#define QQUICKGRIDLAYOUTENGINE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the graphics view layout classes. This header +// file may change from version to version without notice, or even be removed. +// +// We mean it. +// + +#include <QtGui/private/qgridlayoutengine_p.h> +#include <QtGui/private/qlayoutpolicy_p.h> +#include <QtCore/qmath.h> + +#include "qquickitem.h" +#include "qquicklayout_p.h" +#include "qdebug.h" +QT_BEGIN_NAMESPACE + +class QQuickGridLayoutItem : public QGridLayoutItem { +public: + QQuickGridLayoutItem(QQuickItem *item, int row, int column, + int rowSpan = 1, int columnSpan = 1, Qt::Alignment alignment = 0) + : QGridLayoutItem(row, column, rowSpan, columnSpan, alignment), m_item(item), sizeHintCacheDirty(true), useFallbackToWidthOrHeight(true) {} + + + QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const + { + Q_UNUSED(constraint); // Quick Layouts does not support constraint atm + return effectiveSizeHints()[which]; + } + + QSizeF *effectiveSizeHints() const + { + if (!sizeHintCacheDirty) + return cachedSizeHints; + + QQuickLayout::effectiveSizeHints_helper(m_item, cachedSizeHints, 0, useFallbackToWidthOrHeight); + useFallbackToWidthOrHeight = false; + + sizeHintCacheDirty = false; + return cachedSizeHints; + } + + void setCachedSizeHints(QSizeF *sizeHints) + { + for (int i = 0; i < Qt::NSizeHints; ++i) { + cachedSizeHints[i] = sizeHints[i]; + } + sizeHintCacheDirty = false; + } + + void invalidate() + { + quickLayoutDebug() << "engine::invalidate()"; + sizeHintCacheDirty = true; + } + + QLayoutPolicy::Policy sizePolicy(Qt::Orientation orientation) const + { + return QQuickLayout::effectiveSizePolicy_helper(m_item, orientation, attachedLayoutObject(m_item, false)); + } + + void setGeometry(const QRectF &rect) + { + QQuickLayoutAttached *info = attachedLayoutObject(m_item, false); + const QRectF r = info ? rect.marginsRemoved(info->qMargins()) : rect; + const QSizeF oldSize(m_item->width(), m_item->height()); + const QSizeF newSize = r.size(); + m_item->setPosition(r.topLeft()); + if (newSize == oldSize) { + if (QQuickLayout *lay = qobject_cast<QQuickLayout *>(m_item)) { + if (lay->arrangementIsDirty()) + lay->rearrange(newSize); + } + } else { + m_item->setSize(newSize); + } + } + + QQuickItem *layoutItem() const { return m_item; } + + QQuickItem *m_item; +private: + mutable QSizeF cachedSizeHints[Qt::NSizeHints]; + mutable unsigned sizeHintCacheDirty : 1; + mutable unsigned useFallbackToWidthOrHeight : 1; +}; + +class QQuickGridLayoutEngine : public QGridLayoutEngine { +public: + QQuickGridLayoutEngine() : QGridLayoutEngine(Qt::AlignVCenter, true /*snapToPixelGrid*/) { } + + int indexOf(QQuickItem *item) const { + for (int i = 0; i < q_items.size(); ++i) { + if (item == static_cast<QQuickGridLayoutItem*>(q_items.at(i))->layoutItem()) + return i; + } + return -1; + } + + QQuickGridLayoutItem *findLayoutItem(QQuickItem *layoutItem) const + { + for (int i = q_items.count() - 1; i >= 0; --i) { + QQuickGridLayoutItem *item = static_cast<QQuickGridLayoutItem*>(q_items.at(i)); + if (item->layoutItem() == layoutItem) + return item; + } + return 0; + } + + void setAlignment(QQuickItem *quickItem, Qt::Alignment alignment); + Qt::Alignment alignment(QQuickItem *quickItem) const; + +}; + + + +QT_END_NAMESPACE + +#endif // QQUICKGRIDLAYOUTENGINE_P_H diff --git a/src/imports/layouts/qquicklayout.cpp b/src/imports/layouts/qquicklayout.cpp new file mode 100644 index 0000000000..d4d4e1703d --- /dev/null +++ b/src/imports/layouts/qquicklayout.cpp @@ -0,0 +1,1081 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Layouts module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquicklayout_p.h" +#include <QEvent> +#include <QtCore/qcoreapplication.h> +#include <QtCore/qnumeric.h> +#include <QtCore/qmath.h> +#include <limits> + +/*! + \qmltype Layout + \instantiates QQuickLayoutAttached + \inqmlmodule QtQuick.Layouts + \ingroup layouts + \brief Provides attached properties for items pushed onto a \l GridLayout, + \l RowLayout or \l ColumnLayout. + + An object of type Layout is attached to children of the layout to provide layout specific + information about the item. + The properties of the attached object influence how the layout will arrange the items. + + For instance, you can specify \l minimumWidth, \l preferredWidth, and + \l maximumWidth if the default values are not satisfactory. + + When a layout is resized, items may grow or shrink. Due to this, items have a + \l{Layout::minimumWidth}{minimum size}, \l{Layout::preferredWidth}{preferred size} and a + \l{Layout::maximumWidth}{maximum size}. + + If minimum size has not been explicitly specified on an item, the size is set to \c 0. + If maximum size has not been explicitly specified on an item, the size is set to + \c Number.POSITIVE_INFINITY. + + For layouts, the implicit minimum and maximum sizes depend on the content of the layouts. + + The \l fillWidth and \l fillHeight properties can either be \c true or \c false. If they are \c + false, the item's size will be fixed to its preferred size. Otherwise, it will grow or shrink + between its minimum and maximum size as the layout is resized. + + \note It is not recommended to have bindings to the x, y, width, or height properties of items + in a layout, since this would conflict with the goals of Layout, and can also cause binding + loops. + + + \sa GridLayout + \sa RowLayout + \sa ColumnLayout +*/ + +QT_BEGIN_NAMESPACE + +QQuickLayoutAttached::QQuickLayoutAttached(QObject *parent) + : QObject(parent), + m_minimumWidth(0), + m_minimumHeight(0), + m_preferredWidth(-1), + m_preferredHeight(-1), + m_maximumWidth(std::numeric_limits<qreal>::infinity()), + m_maximumHeight(std::numeric_limits<qreal>::infinity()), + m_defaultMargins(0), + m_row(-1), + m_column(-1), + m_rowSpan(1), + m_columnSpan(1), + m_fillWidth(false), + m_fillHeight(false), + m_isFillWidthSet(false), + m_isFillHeightSet(false), + m_isMinimumWidthSet(false), + m_isMinimumHeightSet(false), + m_isMaximumWidthSet(false), + m_isMaximumHeightSet(false), + m_changesNotificationEnabled(true), + m_isLeftMarginSet(false), + m_isTopMarginSet(false), + m_isRightMarginSet(false), + m_isBottomMarginSet(false), + m_alignment(0) +{ + +} + +/*! + \qmlattachedproperty real Layout::minimumWidth + + This property holds the minimum width of an item in a layout. + The default value is the item's implicit minimum width. + + If the item is a layout, the implicit minimum width will be the minimum width the layout can + have without any of its items shrinking below their minimum width. + The implicit minimum width for any other item is \c 0. + + Setting this value to -1 will reset the width back to its implicit minimum width. + + + \sa preferredWidth + \sa maximumWidth +*/ +void QQuickLayoutAttached::setMinimumWidth(qreal width) +{ + if (qIsNaN(width)) + return; + m_isMinimumWidthSet = width >= 0; + if (m_minimumWidth == width) + return; + + m_minimumWidth = width; + invalidateItem(); + emit minimumWidthChanged(); +} + +/*! + \qmlattachedproperty real Layout::minimumHeight + + This property holds the minimum height of an item in a layout. + The default value is the item's implicit minimum height. + + If the item is a layout, the implicit minimum height will be the minimum height the layout can + have without any of its items shrinking below their minimum height. + The implicit minimum height for any other item is \c 0. + + Setting this value to -1 will reset the height back to its implicit minimum height. + + \sa preferredHeight + \sa maximumHeight +*/ +void QQuickLayoutAttached::setMinimumHeight(qreal height) +{ + if (qIsNaN(height)) + return; + m_isMinimumHeightSet = height >= 0; + if (m_minimumHeight == height) + return; + + m_minimumHeight = height; + invalidateItem(); + emit minimumHeightChanged(); +} + +/*! + \qmlattachedproperty real Layout::preferredWidth + + This property holds the preferred width of an item in a layout. + If the preferred width is \c -1 it will be ignored, and the layout + will use \l{Item::implicitWidth}{implicitWidth} instead. + The default is \c -1. + + \sa minimumWidth + \sa maximumWidth +*/ +void QQuickLayoutAttached::setPreferredWidth(qreal width) +{ + if (qIsNaN(width) || m_preferredWidth == width) + return; + + m_preferredWidth = width; + invalidateItem(); + emit preferredWidthChanged(); +} + +/*! + \qmlattachedproperty real Layout::preferredHeight + + This property holds the preferred height of an item in a layout. + If the preferred height is \c -1 it will be ignored, and the layout + will use \l{Item::implicitHeight}{implicitHeight} instead. + The default is \c -1. + + \sa minimumHeight + \sa maximumHeight +*/ +void QQuickLayoutAttached::setPreferredHeight(qreal height) +{ + if (qIsNaN(height) || m_preferredHeight == height) + return; + + m_preferredHeight = height; + invalidateItem(); + emit preferredHeightChanged(); +} + +/*! + \qmlattachedproperty real Layout::maximumWidth + + This property holds the maximum width of an item in a layout. + The default value is the item's implicit maximum width. + + If the item is a layout, the implicit maximum width will be the maximum width the layout can + have without any of its items growing beyond their maximum width. + The implicit maximum width for any other item is \c Number.POSITIVE_INFINITY. + + Setting this value to \c -1 will reset the width back to its implicit maximum width. + + \sa minimumWidth + \sa preferredWidth +*/ +void QQuickLayoutAttached::setMaximumWidth(qreal width) +{ + if (qIsNaN(width)) + return; + m_isMaximumWidthSet = width >= 0; + if (m_maximumWidth == width) + return; + + m_maximumWidth = width; + invalidateItem(); + emit maximumWidthChanged(); +} + +/*! + \qmlattachedproperty real Layout::maximumHeight + + The default value is the item's implicit maximum height. + + If the item is a layout, the implicit maximum height will be the maximum height the layout can + have without any of its items growing beyond their maximum height. + The implicit maximum height for any other item is \c Number.POSITIVE_INFINITY. + + Setting this value to \c -1 will reset the height back to its implicit maximum height. + + \sa minimumHeight + \sa preferredHeight +*/ +void QQuickLayoutAttached::setMaximumHeight(qreal height) +{ + if (qIsNaN(height)) + return; + m_isMaximumHeightSet = height >= 0; + if (m_maximumHeight == height) + return; + + m_maximumHeight = height; + invalidateItem(); + emit maximumHeightChanged(); +} + +void QQuickLayoutAttached::setMinimumImplicitSize(const QSizeF &sz) +{ + bool emitWidthChanged = false; + bool emitHeightChanged = false; + if (!m_isMinimumWidthSet && m_minimumWidth != sz.width()) { + m_minimumWidth = sz.width(); + emitWidthChanged = true; + } + if (!m_isMinimumHeightSet && m_minimumHeight != sz.height()) { + m_minimumHeight = sz.height(); + emitHeightChanged = true; + } + // Only invalidate the item once, and make sure we emit signal changed after the call to + // invalidateItem() + if (emitWidthChanged || emitHeightChanged) { + invalidateItem(); + if (emitWidthChanged) + emit minimumWidthChanged(); + if (emitHeightChanged) + emit minimumHeightChanged(); + } +} + +void QQuickLayoutAttached::setMaximumImplicitSize(const QSizeF &sz) +{ + bool emitWidthChanged = false; + bool emitHeightChanged = false; + if (!m_isMaximumWidthSet && m_maximumWidth != sz.width()) { + m_maximumWidth = sz.width(); + emitWidthChanged = true; + } + if (!m_isMaximumHeightSet && m_maximumHeight != sz.height()) { + m_maximumHeight = sz.height(); + emitHeightChanged = true; + } + // Only invalidate the item once, and make sure we emit changed signal after the call to + // invalidateItem() + if (emitWidthChanged || emitHeightChanged) { + invalidateItem(); + if (emitWidthChanged) + emit maximumWidthChanged(); + if (emitHeightChanged) + emit maximumHeightChanged(); + } +} + +/*! + \qmlattachedproperty bool Layout::fillWidth + + If this property is \c true, the item will be as wide as possible while respecting + the given constraints. If the property is \c false, the item will have a fixed width + set to the preferred width. + The default is \c false, except for layouts themselves, which default to \c true. + + \sa fillHeight +*/ +void QQuickLayoutAttached::setFillWidth(bool fill) +{ + m_isFillWidthSet = true; + if (m_fillWidth != fill) { + m_fillWidth = fill; + invalidateItem(); + emit fillWidthChanged(); + } +} + +/*! + \qmlattachedproperty bool Layout::fillHeight + + If this property is \c true, the item will be as tall as possible while respecting + the given constraints. If the property is \c false, the item will have a fixed height + set to the preferred height. + The default is \c false, except for layouts themselves, which default to \c true. + + \sa fillWidth +*/ +void QQuickLayoutAttached::setFillHeight(bool fill) +{ + m_isFillHeightSet = true; + if (m_fillHeight != fill) { + m_fillHeight = fill; + invalidateItem(); + emit fillHeightChanged(); + } +} + +/*! + \qmlattachedproperty int Layout::row + + This property allows you to specify the row position of an item in a \l GridLayout. + + If both \l column and this property are not set, it is up to the layout to assign a cell to the item. + + The default value is \c 0. + + \sa column + \sa rowSpan +*/ +void QQuickLayoutAttached::setRow(int row) +{ + if (row >= 0 && row != m_row) { + m_row = row; + repopulateLayout(); + emit rowChanged(); + } +} + +/*! + \qmlattachedproperty int Layout::column + + This property allows you to specify the column position of an item in a \l GridLayout. + + If both \l row and this property are not set, it is up to the layout to assign a cell to the item. + + The default value is \c 0. + + \sa row + \sa columnSpan +*/ +void QQuickLayoutAttached::setColumn(int column) +{ + if (column >= 0 && column != m_column) { + m_column = column; + repopulateLayout(); + emit columnChanged(); + } +} + + +/*! + \qmlattachedproperty Qt.Alignment Layout::alignment + + This property allows you to specify the alignment of an item within the cell(s) it occupies. + + The default value is \c 0, which means it will be \c{Qt.AlignVCenter | Qt.AlignLeft} + + A valid alignment is a combination of the following flags: + \list + \li Qt::AlignLeft + \li Qt::AlignHCenter + \li Qt::AlignRight + \li Qt::AlignTop + \li Qt::AlignVCenter + \li Qt::AlignBottom + \li Qt::AlignBaseline + \endlist + +*/ +void QQuickLayoutAttached::setAlignment(Qt::Alignment align) +{ + if (align != m_alignment) { + m_alignment = align; + if (QQuickLayout *layout = parentLayout()) { + layout->setAlignment(item(), align); + invalidateItem(); + } + emit alignmentChanged(); + } +} + +/*! + \qmlattachedproperty real Layout::margins + + Sets the margins outside of an item to all have the same value. The item + itself does not evaluate its own margins. It is the parent's responsibility + to decide if it wants to evaluate the margins. + + Specifically, margins are only evaluated by ColumnLayout, RowLayout, + GridLayout, and other layout-like containers, such as SplitView, where the + effective cell size of an item will be increased as the margins are + increased. + + Therefore, if an item with margins is a child of another \c Item, its + position, size and implicit size will remain unchanged. + + Combining margins with alignment will align the item \e including its + margins. For instance, a vertically-centered Item with a top margin of \c 1 + and a bottom margin of \c 9 will cause the Items effective alignment within + the cell to be 4 pixels above the center. + + The default value is \c 0. + + \sa leftMargin + \sa topMargin + \sa rightMargin + \sa bottomMargin + + \since QtQuick.Layouts 1.2 +*/ +void QQuickLayoutAttached::setMargins(qreal m) +{ + if (m == m_defaultMargins) + return; + + m_defaultMargins = m; + invalidateItem(); + if (!m_isLeftMarginSet && m_margins.left() != m) + emit leftMarginChanged(); + if (!m_isTopMarginSet && m_margins.top() != m) + emit topMarginChanged(); + if (!m_isRightMarginSet && m_margins.right() != m) + emit rightMarginChanged(); + if (!m_isBottomMarginSet && m_margins.bottom() != m) + emit bottomMarginChanged(); + emit marginsChanged(); +} + +/*! + \qmlattachedproperty real Layout::leftMargin + + Specifies the left margin outside of an item. + If the value is not set, it will use the value from \l margins. + + \sa margins + + \since QtQuick.Layouts 1.2 +*/ +void QQuickLayoutAttached::setLeftMargin(qreal m) +{ + const bool changed = leftMargin() != m; + m_margins.setLeft(m); + m_isLeftMarginSet = true; + if (changed) { + invalidateItem(); + emit leftMarginChanged(); + } +} + +void QQuickLayoutAttached::resetLeftMargin() +{ + const bool changed = m_isLeftMarginSet && (m_defaultMargins != m_margins.left()); + m_isLeftMarginSet = false; + if (changed) { + invalidateItem(); + emit leftMarginChanged(); + } +} + +/*! + \qmlattachedproperty real Layout::topMargin + + Specifies the top margin outside of an item. + If the value is not set, it will use the value from \l margins. + + \sa margins + + \since QtQuick.Layouts 1.2 +*/ +void QQuickLayoutAttached::setTopMargin(qreal m) +{ + const bool changed = topMargin() != m; + m_margins.setTop(m); + m_isTopMarginSet = true; + if (changed) { + invalidateItem(); + emit topMarginChanged(); + } +} + +void QQuickLayoutAttached::resetTopMargin() +{ + const bool changed = m_isTopMarginSet && (m_defaultMargins != m_margins.top()); + m_isTopMarginSet = false; + if (changed) { + invalidateItem(); + emit topMarginChanged(); + } +} + +/*! + \qmlattachedproperty real Layout::rightMargin + + Specifies the right margin outside of an item. + If the value is not set, it will use the value from \l margins. + + \sa margins + + \since QtQuick.Layouts 1.2 +*/ +void QQuickLayoutAttached::setRightMargin(qreal m) +{ + const bool changed = rightMargin() != m; + m_margins.setRight(m); + m_isRightMarginSet = true; + if (changed) { + invalidateItem(); + emit rightMarginChanged(); + } +} + +void QQuickLayoutAttached::resetRightMargin() +{ + const bool changed = m_isRightMarginSet && (m_defaultMargins != m_margins.right()); + m_isRightMarginSet = false; + if (changed) { + invalidateItem(); + emit rightMarginChanged(); + } +} + +/*! + \qmlattachedproperty real Layout::bottomMargin + + Specifies the bottom margin outside of an item. + If the value is not set, it will use the value from \l margins. + + \sa margins + + \since QtQuick.Layouts 1.2 +*/ +void QQuickLayoutAttached::setBottomMargin(qreal m) +{ + const bool changed = bottomMargin() != m; + m_margins.setBottom(m); + m_isBottomMarginSet = true; + if (changed) { + invalidateItem(); + emit bottomMarginChanged(); + } +} + +void QQuickLayoutAttached::resetBottomMargin() +{ + const bool changed = m_isBottomMarginSet && (m_defaultMargins != m_margins.bottom()); + m_isBottomMarginSet = false; + if (changed) { + invalidateItem(); + emit bottomMarginChanged(); + } +} + + +/*! + \qmlattachedproperty int Layout::rowSpan + + This property allows you to specify the row span of an item in a \l GridLayout. + + The default value is \c 1. + + \sa columnSpan + \sa row +*/ +void QQuickLayoutAttached::setRowSpan(int span) +{ + if (span != m_rowSpan) { + m_rowSpan = span; + repopulateLayout(); + emit rowSpanChanged(); + } +} + + +/*! + \qmlattachedproperty int Layout::columnSpan + + This property allows you to specify the column span of an item in a \l GridLayout. + + The default value is \c 1. + + \sa rowSpan + \sa column +*/ +void QQuickLayoutAttached::setColumnSpan(int span) +{ + if (span != m_columnSpan) { + m_columnSpan = span; + repopulateLayout(); + emit columnSpanChanged(); + } +} + + +qreal QQuickLayoutAttached::sizeHint(Qt::SizeHint which, Qt::Orientation orientation) const +{ + qreal result = 0; + if (QQuickLayout *layout = qobject_cast<QQuickLayout *>(item())) { + const QSizeF sz = layout->sizeHint(which); + result = (orientation == Qt::Horizontal ? sz.width() : sz.height()); + } else { + if (which == Qt::MaximumSize) + result = std::numeric_limits<qreal>::infinity(); + } + return result; +} + +void QQuickLayoutAttached::invalidateItem() +{ + if (!m_changesNotificationEnabled) + return; + quickLayoutDebug() << "QQuickLayoutAttached::invalidateItem"; + if (QQuickLayout *layout = parentLayout()) { + layout->invalidate(item()); + } +} + +void QQuickLayoutAttached::repopulateLayout() +{ + if (QQuickLayout *layout = parentLayout()) + layout->updateLayoutItems(); +} + +QQuickLayout *QQuickLayoutAttached::parentLayout() const +{ + QQuickItem *parentItem = item(); + if (parentItem) { + parentItem = parentItem->parentItem(); + return qobject_cast<QQuickLayout *>(parentItem); + } else { + qWarning("Layout must be attached to Item elements"); + } + return 0; +} + +QQuickItem *QQuickLayoutAttached::item() const +{ + return qobject_cast<QQuickItem *>(parent()); +} + + +QQuickLayout::QQuickLayout(QQuickLayoutPrivate &dd, QQuickItem *parent) + : QQuickItem(dd, parent), + m_dirty(false) +{ +} + +QQuickLayout::~QQuickLayout() +{ + d_func()->m_isReady = false; +} + +QQuickLayoutAttached *QQuickLayout::qmlAttachedProperties(QObject *object) +{ + return new QQuickLayoutAttached(object); +} + +void QQuickLayout::updatePolish() +{ + rearrange(QSizeF(width(), height())); +} + +void QQuickLayout::componentComplete() +{ + Q_D(QQuickLayout); + d->m_disableRearrange = true; + QQuickItem::componentComplete(); // will call our geometryChanged(), (where isComponentComplete() == true) + d->m_disableRearrange = false; + d->m_isReady = true; +} + +void QQuickLayout::invalidate(QQuickItem * /*childItem*/) +{ + if (m_dirty) + return; + + m_dirty = true; + + if (!qobject_cast<QQuickLayout *>(parentItem())) { + quickLayoutDebug() << "QQuickLayout::invalidate(), polish()"; + polish(); + } +} + +bool QQuickLayout::shouldIgnoreItem(QQuickItem *child, QQuickLayoutAttached *&info, QSizeF *sizeHints) const +{ + Q_D(const QQuickLayout); + bool ignoreItem = true; + QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child); + if (childPrivate->explicitVisible) { + effectiveSizeHints_helper(child, sizeHints, &info, true); + QSizeF effectiveMaxSize = sizeHints[Qt::MaximumSize]; + if (!effectiveMaxSize.isNull()) { + QSizeF &prefS = sizeHints[Qt::PreferredSize]; + if (effectiveSizePolicy_helper(child, Qt::Horizontal, info) == QLayoutPolicy::Fixed) + effectiveMaxSize.setWidth(prefS.width()); + if (effectiveSizePolicy_helper(child, Qt::Vertical, info) == QLayoutPolicy::Fixed) + effectiveMaxSize.setHeight(prefS.height()); + } + ignoreItem = effectiveMaxSize.isNull(); + } + + if (ignoreItem) + d->m_ignoredItems << child; + return ignoreItem; +} +struct QQuickItemPublic : public QQuickItem { + static bool isCompleted(QQuickItem *item) { + return static_cast<QQuickItemPublic*>(item)->isComponentComplete(); + } +}; + +void QQuickLayout::itemChange(ItemChange change, const ItemChangeData &value) +{ + if (change == ItemChildAddedChange) { + QQuickItem *item = value.item; + QObject::connect(item, SIGNAL(implicitWidthChanged()), this, SLOT(invalidateSenderItem())); + QObject::connect(item, SIGNAL(implicitHeightChanged()), this, SLOT(invalidateSenderItem())); + QObject::connect(item, SIGNAL(baselineOffsetChanged(qreal)), this, SLOT(invalidateSenderItem())); + QQuickItemPrivate::get(item)->addItemChangeListener(this, QQuickItemPrivate::SiblingOrder); + if (isReady()) + updateLayoutItems(); + } else if (change == ItemChildRemovedChange) { + QQuickItem *item = value.item; + QObject::disconnect(item, SIGNAL(implicitWidthChanged()), this, SLOT(invalidateSenderItem())); + QObject::disconnect(item, SIGNAL(implicitHeightChanged()), this, SLOT(invalidateSenderItem())); + QObject::disconnect(item, SIGNAL(baselineOffsetChanged(qreal)), this, SLOT(invalidateSenderItem())); + QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::SiblingOrder); + if (isReady()) + updateLayoutItems(); + } + QQuickItem::itemChange(change, value); +} + +void QQuickLayout::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + Q_D(QQuickLayout); + QQuickItem::geometryChanged(newGeometry, oldGeometry); + if (d->m_disableRearrange || !isReady() || !newGeometry.isValid()) + return; + + quickLayoutDebug() << "QQuickStackLayout::geometryChanged" << newGeometry << oldGeometry; + rearrange(newGeometry.size()); +} + +void QQuickLayout::invalidateSenderItem() +{ + if (!isReady()) + return; + QQuickItem *item = static_cast<QQuickItem *>(sender()); + Q_ASSERT(item); + invalidate(item); +} + +bool QQuickLayout::isReady() const +{ + return d_func()->m_isReady; +} + +void QQuickLayout::itemSiblingOrderChanged(QQuickItem *item) +{ + Q_UNUSED(item); + updateLayoutItems(); +} + +void QQuickLayout::rearrange(const QSizeF &/*size*/) +{ + m_dirty = false; +} + + +/* + The layout engine assumes: + 1. minimum <= preferred <= maximum + 2. descent is within minimum and maximum bounds (### verify) + + This function helps to ensure that by the following rules (in the following order): + 1. If minimum > maximum, set minimum = maximum + 2. Clamp preferred to be between the [minimum,maximum] range. + 3. If descent > minimum, set descent = minimum (### verify if this is correct, it might + need some refinements to multiline texts) + + If any values are "not set" (i.e. negative), they will be left untouched, so that we + know which values needs to be fetched from the implicit hints (not user hints). + */ +static void normalizeHints(qreal &minimum, qreal &preferred, qreal &maximum, qreal &descent) +{ + if (minimum >= 0 && maximum >= 0 && minimum > maximum) + minimum = maximum; + + if (preferred >= 0) { + if (minimum >= 0 && preferred < minimum) { + preferred = minimum; + } else if (maximum >= 0 && preferred > maximum) { + preferred = maximum; + } + } + + if (minimum >= 0 && descent > minimum) + descent = minimum; +} + +static void boundSize(QSizeF &result, const QSizeF &size) +{ + if (size.width() >= 0 && size.width() < result.width()) + result.setWidth(size.width()); + if (size.height() >= 0 && size.height() < result.height()) + result.setHeight(size.height()); +} + +static void expandSize(QSizeF &result, const QSizeF &size) +{ + if (size.width() >= 0 && size.width() > result.width()) + result.setWidth(size.width()); + if (size.height() >= 0 && size.height() > result.height()) + result.setHeight(size.height()); +} + +static inline void combineHints(qreal ¤t, qreal fallbackHint) +{ + if (current < 0) + current = fallbackHint; +} + +static inline void combineSize(QSizeF &result, const QSizeF &fallbackSize) +{ + combineHints(result.rwidth(), fallbackSize.width()); + combineHints(result.rheight(), fallbackSize.height()); +} + +static inline void combineImplicitHints(QQuickLayoutAttached *info, Qt::SizeHint which, QSizeF *size) +{ + if (!info) return; + + Q_ASSERT(which == Qt::MinimumSize || which == Qt::MaximumSize); + + const QSizeF constraint(which == Qt::MinimumSize + ? QSizeF(info->minimumWidth(), info->minimumHeight()) + : QSizeF(info->maximumWidth(), info->maximumHeight())); + + if (!info->isExtentExplicitlySet(Qt::Horizontal, which)) + combineHints(size->rwidth(), constraint.width()); + if (!info->isExtentExplicitlySet(Qt::Vertical, which)) + combineHints(size->rheight(), constraint.height()); +} + +typedef qreal (QQuickLayoutAttached::*SizeGetter)() const; + +/*! + \internal + Note: Can potentially return the attached QQuickLayoutAttached object through \a attachedInfo. + + It is like this is because it enables it to be reused. + + The goal of this function is to return the effective minimum, preferred and maximum size hints + that the layout will use for this item. + This function takes care of gathering all explicitly set size hints, normalizes them so + that min < pref < max. + Further, the hints _not_explicitly_ set will then be initialized with the implicit size hints, + which is usually derived from the content of the layouts (or items). + + The following table illustrates the preference of the properties used for measuring layout + items. If present, the USER properties will be preferred. If USER properties are not present, + the HINT properties will be preferred. Finally, the FALLBACK properties will be used as an + ultimate fallback. + + Note that one can query if the value of Layout.minimumWidth or Layout.maximumWidth has been + explicitly or implicitly set with QQuickLayoutAttached::isExtentExplicitlySet(). This + determines if it should be used as a USER or as a HINT value. + + Fractional size hints will be ceiled to the closest integer. This is in order to give some + slack when the items are snapped to the pixel grid. + + | *Minimum* | *Preferred* | *Maximum* | ++----------------+----------------------+-----------------------+--------------------------+ +|USER (explicit) | Layout.minimumWidth | Layout.preferredWidth | Layout.maximumWidth | +|HINT (implicit) | Layout.minimumWidth | implicitWidth | Layout.maximumWidth | +|FALLBACK | 0 | width | Number.POSITIVE_INFINITY | ++----------------+----------------------+-----------------------+--------------------------+ + */ +void QQuickLayout::effectiveSizeHints_helper(QQuickItem *item, QSizeF *cachedSizeHints, QQuickLayoutAttached **attachedInfo, bool useFallbackToWidthOrHeight) +{ + for (int i = 0; i < Qt::NSizeHints; ++i) + cachedSizeHints[i] = QSizeF(); + QQuickLayoutAttached *info = attachedLayoutObject(item, false); + // First, retrieve the user-specified hints from the attached "Layout." properties + if (info) { + struct Getters { + SizeGetter call[NSizes]; + }; + + static Getters horGetters = { + {&QQuickLayoutAttached::minimumWidth, &QQuickLayoutAttached::preferredWidth, &QQuickLayoutAttached::maximumWidth}, + }; + + static Getters verGetters = { + {&QQuickLayoutAttached::minimumHeight, &QQuickLayoutAttached::preferredHeight, &QQuickLayoutAttached::maximumHeight} + }; + for (int i = 0; i < NSizes; ++i) { + SizeGetter getter = horGetters.call[i]; + Q_ASSERT(getter); + + if (info->isExtentExplicitlySet(Qt::Horizontal, (Qt::SizeHint)i)) + cachedSizeHints[i].setWidth((info->*getter)()); + + getter = verGetters.call[i]; + Q_ASSERT(getter); + if (info->isExtentExplicitlySet(Qt::Vertical, (Qt::SizeHint)i)) + cachedSizeHints[i].setHeight((info->*getter)()); + } + } + + QSizeF &minS = cachedSizeHints[Qt::MinimumSize]; + QSizeF &prefS = cachedSizeHints[Qt::PreferredSize]; + QSizeF &maxS = cachedSizeHints[Qt::MaximumSize]; + QSizeF &descentS = cachedSizeHints[Qt::MinimumDescent]; + + // For instance, will normalize the following user-set hints + // from: [10, 5, 60] + // to: [10, 10, 60] + normalizeHints(minS.rwidth(), prefS.rwidth(), maxS.rwidth(), descentS.rwidth()); + normalizeHints(minS.rheight(), prefS.rheight(), maxS.rheight(), descentS.rheight()); + + // All explicit values gathered, now continue to gather the implicit sizes + + //--- GATHER MAXIMUM SIZE HINTS --- + combineImplicitHints(info, Qt::MaximumSize, &maxS); + combineSize(maxS, QSizeF(std::numeric_limits<qreal>::infinity(), std::numeric_limits<qreal>::infinity())); + // implicit max or min sizes should not limit an explicitly set preferred size + expandSize(maxS, prefS); + expandSize(maxS, minS); + + //--- GATHER MINIMUM SIZE HINTS --- + combineImplicitHints(info, Qt::MinimumSize, &minS); + expandSize(minS, QSizeF(0,0)); + boundSize(minS, prefS); + boundSize(minS, maxS); + + //--- GATHER PREFERRED SIZE HINTS --- + // First, from implicitWidth/Height + qreal &prefWidth = prefS.rwidth(); + qreal &prefHeight = prefS.rheight(); + if (prefWidth < 0 && item->implicitWidth() > 0) + prefWidth = qCeil(item->implicitWidth()); + if (prefHeight < 0 && item->implicitHeight() > 0) + prefHeight = qCeil(item->implicitHeight()); + + // If that fails, make an ultimate fallback to width/height + + if (!info && (prefWidth < 0 || prefHeight < 0)) + info = attachedLayoutObject(item); + + if (useFallbackToWidthOrHeight && info) { + /* This block is a bit hacky, but if we want to support using width/height + as preferred size hints in layouts, (which we think most people expect), + we only want to use the initial width. + This is because the width will change due to layout rearrangement, and the preferred + width should return the same value, regardless of the current width. + We therefore store the width in the implicitWidth attached property. + Since the layout listens to changes of implicitWidth, (it will + basically cause an invalidation of the layout), we have to disable that + notification while we set the implicit width (and height). + + Only use this fallback the first time the size hint is queried. Otherwise, we might + end up picking a width that is different than what was specified in the QML. + */ + if (prefWidth < 0 || prefHeight < 0) { + item->blockSignals(true); + if (prefWidth < 0) { + prefWidth = item->width(); + item->setImplicitWidth(prefWidth); + } + if (prefHeight < 0) { + prefHeight = item->height(); + item->setImplicitHeight(prefHeight); + } + item->blockSignals(false); + } + } + + + + // Normalize again after the implicit hints have been gathered + expandSize(prefS, minS); + boundSize(prefS, maxS); + + //--- GATHER DESCENT + // Minimum descent is only applicable for the effective minimum height, + // so we gather the descent last. + const qreal minimumDescent = minS.height() - item->baselineOffset(); + descentS.setHeight(minimumDescent); + + if (info) { + QMarginsF margins = info->qMargins(); + QSizeF extraMargins(margins.left() + margins.right(), margins.top() + margins.bottom()); + minS += extraMargins; + prefS += extraMargins; + maxS += extraMargins; + descentS += extraMargins; + } + if (attachedInfo) + *attachedInfo = info; +} + +/*! + \internal + + Assumes \a info is set (if the object has an attached property) + */ +QLayoutPolicy::Policy QQuickLayout::effectiveSizePolicy_helper(QQuickItem *item, Qt::Orientation orientation, QQuickLayoutAttached *info) +{ + bool fillExtent = false; + bool isSet = false; + if (info) { + if (orientation == Qt::Horizontal) { + isSet = info->isFillWidthSet(); + if (isSet) fillExtent = info->fillWidth(); + } else { + isSet = info->isFillHeightSet(); + if (isSet) fillExtent = info->fillHeight(); + } + } + if (!isSet && qobject_cast<QQuickLayout*>(item)) + fillExtent = true; + return fillExtent ? QLayoutPolicy::Preferred : QLayoutPolicy::Fixed; + +} + + + +QT_END_NAMESPACE diff --git a/src/imports/layouts/qquicklayout_p.h b/src/imports/layouts/qquicklayout_p.h new file mode 100644 index 0000000000..c7f04c1fed --- /dev/null +++ b/src/imports/layouts/qquicklayout_p.h @@ -0,0 +1,326 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Layouts module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKLAYOUT_P_H +#define QQUICKLAYOUT_P_H + +#include <QPointer> +#include <QQuickItem> +#include <private/qquickitem_p.h> +#include <QtQuick/private/qquickitemchangelistener_p.h> +#include <QtGui/private/qlayoutpolicy_p.h> + +QT_BEGIN_NAMESPACE + +class QQuickLayoutAttached; + +#if 0 && !defined(QT_NO_DEBUG) && !defined(QT_NO_DEBUG_OUTPUT) +# define quickLayoutDebug QMessageLogger(__FILE__, __LINE__, Q_FUNC_INFO).debug +#else +# define quickLayoutDebug QT_NO_QDEBUG_MACRO +#endif + +class QQuickLayoutPrivate; +class QQuickLayout : public QQuickItem, public QQuickItemChangeListener + +{ + Q_OBJECT +public: + enum SizeHint { + MinimumSize = 0, + PreferredSize, + MaximumSize, + NSizes + }; + + explicit QQuickLayout(QQuickLayoutPrivate &dd, QQuickItem *parent = 0); + ~QQuickLayout(); + + static QQuickLayoutAttached *qmlAttachedProperties(QObject *object); + + + void componentComplete() Q_DECL_OVERRIDE; + virtual QSizeF sizeHint(Qt::SizeHint whichSizeHint) const = 0; + virtual void setAlignment(QQuickItem *item, Qt::Alignment align) = 0; + virtual void invalidate(QQuickItem * childItem = 0); + virtual void updateLayoutItems() = 0; + + // iterator + virtual QQuickItem *itemAt(int index) const = 0; + virtual int itemCount() const = 0; + + virtual void rearrange(const QSizeF &); + bool arrangementIsDirty() const { return m_dirty; } + + static void effectiveSizeHints_helper(QQuickItem *item, QSizeF *cachedSizeHints, QQuickLayoutAttached **info, bool useFallbackToWidthOrHeight); + static QLayoutPolicy::Policy effectiveSizePolicy_helper(QQuickItem *item, Qt::Orientation orientation, QQuickLayoutAttached *info); + bool shouldIgnoreItem(QQuickItem *child, QQuickLayoutAttached *&info, QSizeF *sizeHints) const; + + void itemChange(ItemChange change, const ItemChangeData &value) Q_DECL_OVERRIDE; + void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) Q_DECL_OVERRIDE; + bool isReady() const; + + + /* QQuickItemChangeListener */ + void itemSiblingOrderChanged(QQuickItem *item) Q_DECL_OVERRIDE; + +protected: + void updatePolish() Q_DECL_OVERRIDE; + + enum Orientation { + Vertical = 0, + Horizontal, + NOrientations + }; + +protected slots: + void invalidateSenderItem(); + +private: + bool m_dirty; + + Q_DECLARE_PRIVATE(QQuickLayout) + + friend class QQuickLayoutAttached; +}; + + +class QQuickLayoutPrivate : public QQuickItemPrivate +{ + Q_DECLARE_PUBLIC(QQuickLayout) +public: + QQuickLayoutPrivate() : m_isReady(false), m_disableRearrange(true) {} + +protected: + unsigned m_isReady : 1; + unsigned m_disableRearrange : 1; + mutable QSet<QQuickItem *> m_ignoredItems; +}; + + +class QQuickLayoutAttached : public QObject +{ + Q_OBJECT + Q_PROPERTY(qreal minimumWidth READ minimumWidth WRITE setMinimumWidth NOTIFY minimumWidthChanged) + Q_PROPERTY(qreal minimumHeight READ minimumHeight WRITE setMinimumHeight NOTIFY minimumHeightChanged) + Q_PROPERTY(qreal preferredWidth READ preferredWidth WRITE setPreferredWidth NOTIFY preferredWidthChanged) + Q_PROPERTY(qreal preferredHeight READ preferredHeight WRITE setPreferredHeight NOTIFY preferredHeightChanged) + Q_PROPERTY(qreal maximumWidth READ maximumWidth WRITE setMaximumWidth NOTIFY maximumWidthChanged) + Q_PROPERTY(qreal maximumHeight READ maximumHeight WRITE setMaximumHeight NOTIFY maximumHeightChanged) + Q_PROPERTY(bool fillHeight READ fillHeight WRITE setFillHeight NOTIFY fillHeightChanged) + Q_PROPERTY(bool fillWidth READ fillWidth WRITE setFillWidth NOTIFY fillWidthChanged) + Q_PROPERTY(int row READ row WRITE setRow NOTIFY rowChanged) + Q_PROPERTY(int column READ column WRITE setColumn NOTIFY columnChanged) + Q_PROPERTY(int rowSpan READ rowSpan WRITE setRowSpan NOTIFY rowSpanChanged) + Q_PROPERTY(int columnSpan READ columnSpan WRITE setColumnSpan NOTIFY columnSpanChanged) + Q_PROPERTY(Qt::Alignment alignment READ alignment WRITE setAlignment NOTIFY alignmentChanged) + + Q_PROPERTY(qreal margins READ margins WRITE setMargins NOTIFY marginsChanged) + Q_PROPERTY(qreal leftMargin READ leftMargin WRITE setLeftMargin RESET resetLeftMargin NOTIFY leftMarginChanged) + Q_PROPERTY(qreal topMargin READ topMargin WRITE setTopMargin RESET resetTopMargin NOTIFY topMarginChanged) + Q_PROPERTY(qreal rightMargin READ rightMargin WRITE setRightMargin RESET resetRightMargin NOTIFY rightMarginChanged) + Q_PROPERTY(qreal bottomMargin READ bottomMargin WRITE setBottomMargin RESET resetBottomMargin NOTIFY bottomMarginChanged) + +public: + QQuickLayoutAttached(QObject *object); + + qreal minimumWidth() const { return !m_isMinimumWidthSet ? sizeHint(Qt::MinimumSize, Qt::Horizontal) : m_minimumWidth; } + void setMinimumWidth(qreal width); + + qreal minimumHeight() const { return !m_isMinimumHeightSet ? sizeHint(Qt::MinimumSize, Qt::Vertical) : m_minimumHeight; } + void setMinimumHeight(qreal height); + + qreal preferredWidth() const { return m_preferredWidth; } + void setPreferredWidth(qreal width); + + qreal preferredHeight() const { return m_preferredHeight; } + void setPreferredHeight(qreal width); + + qreal maximumWidth() const { return !m_isMaximumWidthSet ? sizeHint(Qt::MaximumSize, Qt::Horizontal) : m_maximumWidth; } + void setMaximumWidth(qreal width); + + qreal maximumHeight() const { return !m_isMaximumHeightSet ? sizeHint(Qt::MaximumSize, Qt::Vertical) : m_maximumHeight; } + void setMaximumHeight(qreal height); + + void setMinimumImplicitSize(const QSizeF &sz); + void setMaximumImplicitSize(const QSizeF &sz); + + bool fillWidth() const { return m_fillWidth; } + void setFillWidth(bool fill); + bool isFillWidthSet() const { return m_isFillWidthSet; } + + bool fillHeight() const { return m_fillHeight; } + void setFillHeight(bool fill); + bool isFillHeightSet() const { return m_isFillHeightSet; } + + int row() const { return qMax(m_row, 0); } + void setRow(int row); + bool isRowSet() const { return m_row >= 0; } + int column() const { return qMax(m_column, 0); } + void setColumn(int column); + bool isColumnSet() const { return m_column >= 0; } + + int rowSpan() const { return m_rowSpan; } + void setRowSpan(int span); + int columnSpan() const { return m_columnSpan; } + void setColumnSpan(int span); + + Qt::Alignment alignment() const { return m_alignment; } + void setAlignment(Qt::Alignment align); + + qreal margins() const { return m_defaultMargins; } + void setMargins(qreal m); + + qreal leftMargin() const { return m_isLeftMarginSet ? m_margins.left() : m_defaultMargins; } + void setLeftMargin(qreal m); + void resetLeftMargin(); + + qreal topMargin() const { return m_isTopMarginSet ? m_margins.top() : m_defaultMargins; } + void setTopMargin(qreal m); + void resetTopMargin(); + + qreal rightMargin() const { return m_isRightMarginSet ? m_margins.right() : m_defaultMargins; } + void setRightMargin(qreal m); + void resetRightMargin(); + + qreal bottomMargin() const { return m_isBottomMarginSet ? m_margins.bottom() : m_defaultMargins; } + void setBottomMargin(qreal m); + void resetBottomMargin(); + + QMarginsF qMargins() const { + return QMarginsF(leftMargin(), topMargin(), rightMargin(), bottomMargin()); + } + + bool setChangesNotificationEnabled(bool enabled) + { + const bool old = m_changesNotificationEnabled; + m_changesNotificationEnabled = enabled; + return old; + } + + qreal sizeHint(Qt::SizeHint which, Qt::Orientation orientation) const; + + bool isExtentExplicitlySet(Qt::Orientation o, Qt::SizeHint whichSize) const + { + switch (whichSize) { + case Qt::MinimumSize: + return o == Qt::Horizontal ? m_isMinimumWidthSet : m_isMinimumHeightSet; + case Qt::MaximumSize: + return o == Qt::Horizontal ? m_isMaximumWidthSet : m_isMaximumHeightSet; + case Qt::PreferredSize: + return true; // Layout.preferredWidth is always explicitly set + case Qt::MinimumDescent: // Not supported + case Qt::NSizeHints: + return false; + } + return false; + } + +signals: + void minimumWidthChanged(); + void minimumHeightChanged(); + void preferredWidthChanged(); + void preferredHeightChanged(); + void maximumWidthChanged(); + void maximumHeightChanged(); + void fillWidthChanged(); + void fillHeightChanged(); + void leftMarginChanged(); + void topMarginChanged(); + void rightMarginChanged(); + void bottomMarginChanged(); + void marginsChanged(); + void rowChanged(); + void columnChanged(); + void rowSpanChanged(); + void columnSpanChanged(); + void alignmentChanged(); + +private: + void invalidateItem(); + void repopulateLayout(); + QQuickLayout *parentLayout() const; + QQuickItem *item() const; +private: + qreal m_minimumWidth; + qreal m_minimumHeight; + qreal m_preferredWidth; + qreal m_preferredHeight; + qreal m_maximumWidth; + qreal m_maximumHeight; + + qreal m_defaultMargins; + QMarginsF m_margins; + + // GridLayout specific properties + int m_row; + int m_column; + int m_rowSpan; + int m_columnSpan; + + unsigned m_fillWidth : 1; + unsigned m_fillHeight : 1; + unsigned m_isFillWidthSet : 1; + unsigned m_isFillHeightSet : 1; + unsigned m_isMinimumWidthSet : 1; + unsigned m_isMinimumHeightSet : 1; + // preferredWidth and preferredHeight are always explicit, since + // their implicit equivalent is implicitWidth and implicitHeight + unsigned m_isMaximumWidthSet : 1; + unsigned m_isMaximumHeightSet : 1; + unsigned m_changesNotificationEnabled : 1; + unsigned m_isLeftMarginSet : 1; + unsigned m_isTopMarginSet : 1; + unsigned m_isRightMarginSet : 1; + unsigned m_isBottomMarginSet : 1; + Qt::Alignment m_alignment; + friend class QQuickLayout; +}; + +inline QQuickLayoutAttached *attachedLayoutObject(QQuickItem *item, bool create = true) +{ + return static_cast<QQuickLayoutAttached *>(qmlAttachedPropertiesObject<QQuickLayout>(item, create)); +} + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickLayout) +QML_DECLARE_TYPEINFO(QQuickLayout, QML_HAS_ATTACHED_PROPERTIES) + +#endif // QQUICKLAYOUT_P_H diff --git a/src/imports/layouts/qquicklayoutstyleinfo.cpp b/src/imports/layouts/qquicklayoutstyleinfo.cpp new file mode 100644 index 0000000000..c33ceffb2d --- /dev/null +++ b/src/imports/layouts/qquicklayoutstyleinfo.cpp @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Layouts module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui/private/qfont_p.h> + +#include "qquicklayoutstyleinfo_p.h" + + +QT_BEGIN_NAMESPACE + +QQuickLayoutStyleInfo::QQuickLayoutStyleInfo() +{ +} + +qreal QQuickLayoutStyleInfo::spacing(Qt::Orientation /*orientation*/) const +{ +#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS) || defined(Q_OS_BLACKBERRY) || defined(Q_OS_QNX) || defined(Q_OS_WINRT) + // On Android and iOS the default spacing between each UI element is 8dp + qreal spacing = 8.0; +#else + qreal spacing = 5.0; +#endif + +#ifndef Q_OS_OSX + // On OS X the DPI is always 72 so we should not scale it + spacing = qRound(spacing * (qreal(qt_defaultDpiX()) / 96.0)); +#endif + + return spacing; +} + +qreal QQuickLayoutStyleInfo::windowMargin(Qt::Orientation /*orientation*/) const +{ + return 0; +} + +bool QQuickLayoutStyleInfo::hasChangedCore() const +{ + // never changes + return false; +} + +QT_END_NAMESPACE + diff --git a/src/imports/layouts/qquicklayoutstyleinfo_p.h b/src/imports/layouts/qquicklayoutstyleinfo_p.h new file mode 100644 index 0000000000..ce86c2a37d --- /dev/null +++ b/src/imports/layouts/qquicklayoutstyleinfo_p.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Layouts module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKLAYOUTSTYLEINFO_P_H +#define QQUICKLAYOUTSTYLEINFO_P_H + +#include <QtGui/private/qabstractlayoutstyleinfo_p.h> + +QT_BEGIN_NAMESPACE + +class QQuickLayoutStyleInfo : public QAbstractLayoutStyleInfo +{ +public: + QQuickLayoutStyleInfo(); + + qreal spacing(Qt::Orientation orientation) const Q_DECL_OVERRIDE; + qreal windowMargin(Qt::Orientation orientation) const Q_DECL_OVERRIDE; + bool hasChangedCore() const Q_DECL_OVERRIDE; + +}; + +QT_END_NAMESPACE + +#endif // QQUICKLAYOUTSTYLEINFO_P_H diff --git a/src/imports/layouts/qquicklinearlayout.cpp b/src/imports/layouts/qquicklinearlayout.cpp new file mode 100644 index 0000000000..2f8af4c58b --- /dev/null +++ b/src/imports/layouts/qquicklinearlayout.cpp @@ -0,0 +1,908 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Layouts module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquicklinearlayout_p.h" +#include "qquickgridlayoutengine_p.h" +#include "qquicklayoutstyleinfo_p.h" +#include <QtCore/qnumeric.h> +#include "qdebug.h" +#include <limits> + +/*! + \qmltype RowLayout + \instantiates QQuickRowLayout + \inherits Item + \inqmlmodule QtQuick.Layouts + \ingroup layouts + \brief Identical to \l GridLayout, but having only one row. + + It is available as a convenience for developers, as it offers a cleaner API. + + Items in a RowLayout support these attached properties: + \list + \li \l{Layout::minimumWidth}{Layout.minimumWidth} + \li \l{Layout::minimumHeight}{Layout.minimumHeight} + \li \l{Layout::preferredWidth}{Layout.preferredWidth} + \li \l{Layout::preferredHeight}{Layout.preferredHeight} + \li \l{Layout::maximumWidth}{Layout.maximumWidth} + \li \l{Layout::maximumHeight}{Layout.maximumHeight} + \li \l{Layout::fillWidth}{Layout.fillWidth} + \li \l{Layout::fillHeight}{Layout.fillHeight} + \li \l{Layout::alignment}{Layout.alignment} + \endlist + + \image rowlayout.png + + \code + RowLayout { + id: layout + anchors.fill: parent + spacing: 6 + Rectangle { + color: 'teal' + Layout.fillWidth: true + Layout.minimumWidth: 50 + Layout.preferredWidth: 100 + Layout.maximumWidth: 300 + Layout.minimumHeight: 150 + Text { + anchors.centerIn: parent + text: parent.width + 'x' + parent.height + } + } + Rectangle { + color: 'plum' + Layout.fillWidth: true + Layout.minimumWidth: 100 + Layout.preferredWidth: 200 + Layout.preferredHeight: 100 + Text { + anchors.centerIn: parent + text: parent.width + 'x' + parent.height + } + } + } + \endcode + + Read more about attached properties \l{QML Object Attributes}{here}. + \sa ColumnLayout + \sa GridLayout + \sa Row +*/ + +/*! + \qmltype ColumnLayout + \instantiates QQuickColumnLayout + \inherits Item + \inqmlmodule QtQuick.Layouts + \ingroup layouts + \brief Identical to \l GridLayout, but having only one column. + + It is available as a convenience for developers, as it offers a cleaner API. + + Items in a ColumnLayout support these attached properties: + \list + \li \l{Layout::minimumWidth}{Layout.minimumWidth} + \li \l{Layout::minimumHeight}{Layout.minimumHeight} + \li \l{Layout::preferredWidth}{Layout.preferredWidth} + \li \l{Layout::preferredHeight}{Layout.preferredHeight} + \li \l{Layout::maximumWidth}{Layout.maximumWidth} + \li \l{Layout::maximumHeight}{Layout.maximumHeight} + \li \l{Layout::fillWidth}{Layout.fillWidth} + \li \l{Layout::fillHeight}{Layout.fillHeight} + \li \l{Layout::alignment}{Layout.alignment} + \endlist + + \image columnlayout.png + + \code + ColumnLayout{ + spacing: 2 + + Rectangle { + Layout.alignment: Qt.AlignCenter + color: "red" + Layout.preferredWidth: 40 + Layout.preferredHeight: 40 + } + + Rectangle { + Layout.alignment: Qt.AlignRight + color: "green" + Layout.preferredWidth: 40 + Layout.preferredHeight: 70 + } + + Rectangle { + Layout.alignment: Qt.AlignBottom + Layout.fillHeight: true + color: "blue" + Layout.preferredWidth: 70 + Layout.preferredHeight: 40 + } + } + \endcode + + Read more about attached properties \l{QML Object Attributes}{here}. + + \sa RowLayout + \sa GridLayout + \sa Column +*/ + + +/*! + \qmltype GridLayout + \instantiates QQuickGridLayout + \inherits Item + \inqmlmodule QtQuick.Layouts + \ingroup layouts + \brief Provides a way of dynamically arranging items in a grid. + + + + If the GridLayout is resized, all items in the layout will be rearranged. It is similar + to the widget-based QGridLayout. All visible children of the GridLayout element will belong to + the layout. If you want a layout with just one row or one column, you can use the + \l RowLayout or \l ColumnLayout. These offer a bit more convenient API, and improve + readability. + + By default items will be arranged according to the \l flow property. The default value of + the \l flow property is \c GridLayout.LeftToRight. + + If the \l columns property is specified, it will be treated as a maximum limit of how many + columns the layout can have, before the auto-positioning wraps back to the beginning of the + next row. The \l columns property is only used when \l flow is \c GridLayout.LeftToRight. + + \image gridlayout.png + + \code + GridLayout { + id: grid + columns: 3 + + Text { text: "Three"; font.bold: true; } + Text { text: "words"; color: "red" } + Text { text: "in"; font.underline: true } + Text { text: "a"; font.pixelSize: 20 } + Text { text: "row"; font.strikeout: true } + } + \endcode + + The \l rows property works in a similar way, but items are auto-positioned vertically. The \l + rows property is only used when \l flow is \c GridLayout.TopToBottom. + + You can specify which cell you want an item to occupy by setting the + \l{Layout::row}{Layout.row} and \l{Layout::column}{Layout.column} properties. You can also + specify the row span or column span by setting the \l{Layout::rowSpan}{Layout.rowSpan} or + \l{Layout::columnSpan}{Layout.columnSpan} properties. + + + Items in a GridLayout support these attached properties: + \list + \li \l{Layout::row}{Layout.row} + \li \l{Layout::column}{Layout.column} + \li \l{Layout::rowSpan}{Layout.rowSpan} + \li \l{Layout::columnSpan}{Layout.columnSpan} + \li \l{Layout::minimumWidth}{Layout.minimumWidth} + \li \l{Layout::minimumHeight}{Layout.minimumHeight} + \li \l{Layout::preferredWidth}{Layout.preferredWidth} + \li \l{Layout::preferredHeight}{Layout.preferredHeight} + \li \l{Layout::maximumWidth}{Layout.maximumWidth} + \li \l{Layout::maximumHeight}{Layout.maximumHeight} + \li \l{Layout::fillWidth}{Layout.fillWidth} + \li \l{Layout::fillHeight}{Layout.fillHeight} + \li \l{Layout::alignment}{Layout.alignment} + \endlist + + Read more about attached properties \l{QML Object Attributes}{here}. + + \sa RowLayout + \sa ColumnLayout + \sa Grid +*/ + + + +QT_BEGIN_NAMESPACE + +QQuickGridLayoutBase::QQuickGridLayoutBase() + : QQuickLayout(*new QQuickGridLayoutBasePrivate) +{ + +} + +QQuickGridLayoutBase::QQuickGridLayoutBase(QQuickGridLayoutBasePrivate &dd, + Qt::Orientation orientation, + QQuickItem *parent /*= 0*/) + : QQuickLayout(dd, parent) +{ + Q_D(QQuickGridLayoutBase); + d->orientation = orientation; + d->styleInfo = new QQuickLayoutStyleInfo; +} + +Qt::Orientation QQuickGridLayoutBase::orientation() const +{ + Q_D(const QQuickGridLayoutBase); + return d->orientation; +} + +void QQuickGridLayoutBase::setOrientation(Qt::Orientation orientation) +{ + Q_D(QQuickGridLayoutBase); + if (d->orientation == orientation) + return; + + d->orientation = orientation; + invalidate(); +} + +QSizeF QQuickGridLayoutBase::sizeHint(Qt::SizeHint whichSizeHint) const +{ + Q_D(const QQuickGridLayoutBase); + return d->engine.sizeHint(whichSizeHint, QSizeF(), d->styleInfo); +} + +/*! + \qmlproperty enumeration GridLayout::layoutDirection + \since QtQuick.Layouts 1.1 + + This property holds the layout direction of the grid layout - it controls whether items are + laid out from left to right or right to left. If \c Qt.RightToLeft is specified, + left-aligned items will be right-aligned and right-aligned items will be left-aligned. + + Possible values: + + \list + \li Qt.LeftToRight (default) - Items are laid out from left to right. + \li Qt.RightToLeft - Items are laid out from right to left. + \endlist + + \sa RowLayout::layoutDirection, ColumnLayout::layoutDirection +*/ +Qt::LayoutDirection QQuickGridLayoutBase::layoutDirection() const +{ + Q_D(const QQuickGridLayoutBase); + return d->m_layoutDirection; +} + +void QQuickGridLayoutBase::setLayoutDirection(Qt::LayoutDirection dir) +{ + Q_D(QQuickGridLayoutBase); + d->m_layoutDirection = dir; + invalidate(); +} + +Qt::LayoutDirection QQuickGridLayoutBase::effectiveLayoutDirection() const +{ + Q_D(const QQuickGridLayoutBase); + return !d->effectiveLayoutMirror == (layoutDirection() == Qt::LeftToRight) + ? Qt::LeftToRight : Qt::RightToLeft; +} + +void QQuickGridLayoutBase::setAlignment(QQuickItem *item, Qt::Alignment alignment) +{ + Q_D(QQuickGridLayoutBase); + d->engine.setAlignment(item, alignment); +} + +QQuickGridLayoutBase::~QQuickGridLayoutBase() +{ + Q_D(QQuickGridLayoutBase); + + /* Avoid messy deconstruction, should give: + * Faster deconstruction + * Less risk of signals reaching already deleted objects + */ + for (int i = 0; i < itemCount(); ++i) { + QQuickItem *item = itemAt(i); + QObject::disconnect(item, SIGNAL(destroyed()), this, SLOT(onItemDestroyed())); + QObject::disconnect(item, SIGNAL(visibleChanged()), this, SLOT(onItemVisibleChanged())); + QObject::disconnect(item, SIGNAL(implicitWidthChanged()), this, SLOT(invalidateSenderItem())); + QObject::disconnect(item, SIGNAL(implicitHeightChanged()), this, SLOT(invalidateSenderItem())); + } + delete d->styleInfo; +} + +void QQuickGridLayoutBase::componentComplete() +{ + quickLayoutDebug() << objectName() << "QQuickGridLayoutBase::componentComplete()" << parent(); + QQuickLayout::componentComplete(); + updateLayoutItems(); + + QQuickItem *par = parentItem(); + if (qobject_cast<QQuickLayout*>(par)) + return; + rearrange(QSizeF(width(), height())); +} + +/* + Invalidation happens like this as a reaction to that a size hint changes on an item "a": + + Suppose we have the following Qml document: + RowLayout { + id: l1 + RowLayout { + id: l2 + Item { + id: a + } + Item { + id: b + } + } + } + + 1. l2->invalidateChildItem(a) is called on l2, where item refers to "a". + (this will dirty the cached size hints of item "a") + 2. l2->invalidate() is called + this will : + i) invalidate the layout engine + ii) dirty the cached size hints of item "l2" (by calling parentLayout()->invalidateChildItem + + */ +/*! + \internal + + Invalidates \a childItem and this layout. + After a call to invalidate, the next call to retrieve e.g. sizeHint will be up-to date. + This function will also call QQuickLayout::invalidate(0), to ensure that the parent layout + is invalidated. + */ +void QQuickGridLayoutBase::invalidate(QQuickItem *childItem) +{ + Q_D(QQuickGridLayoutBase); + if (!isReady()) + return; + if (d->m_rearranging) { + d->m_invalidateAfterRearrange << childItem; + return; + } + + quickLayoutDebug() << "QQuickGridLayoutBase::invalidate()"; + + if (childItem) { + if (QQuickGridLayoutItem *layoutItem = d->engine.findLayoutItem(childItem)) + layoutItem->invalidate(); + if (d->m_ignoredItems.contains(childItem)) { + updateLayoutItems(); + return; + } + } + // invalidate engine + d->engine.invalidate(); + + QQuickLayout::invalidate(this); + + QQuickLayoutAttached *info = attachedLayoutObject(this); + + const QSizeF min = sizeHint(Qt::MinimumSize); + const QSizeF pref = sizeHint(Qt::PreferredSize); + const QSizeF max = sizeHint(Qt::MaximumSize); + + const bool old = info->setChangesNotificationEnabled(false); + info->setMinimumImplicitSize(min); + info->setMaximumImplicitSize(max); + info->setChangesNotificationEnabled(old); + if (pref.width() == implicitWidth() && pref.height() == implicitHeight()) { + // In case setImplicitSize does not emit implicit{Width|Height}Changed + if (QQuickLayout *parentLayout = qobject_cast<QQuickLayout *>(parentItem())) + parentLayout->invalidate(this); + } else { + setImplicitSize(pref.width(), pref.height()); + } +} + +void QQuickGridLayoutBase::updateLayoutItems() +{ + Q_D(QQuickGridLayoutBase); + if (!isReady()) + return; + if (d->m_rearranging) { + d->m_updateAfterRearrange = true; + return; + } + + quickLayoutDebug() << "QQuickGridLayoutBase::updateLayoutItems"; + d->engine.deleteItems(); + insertLayoutItems(); + + invalidate(); + quickLayoutDebug() << "QQuickGridLayoutBase::updateLayoutItems LEAVING"; +} + +QQuickItem *QQuickGridLayoutBase::itemAt(int index) const +{ + Q_D(const QQuickGridLayoutBase); + return static_cast<QQuickGridLayoutItem*>(d->engine.itemAt(index))->layoutItem(); +} + +int QQuickGridLayoutBase::itemCount() const +{ + Q_D(const QQuickGridLayoutBase); + return d->engine.itemCount(); +} + +void QQuickGridLayoutBase::itemChange(ItemChange change, const ItemChangeData &value) +{ + if (change == ItemChildAddedChange) { + quickLayoutDebug() << "ItemChildAddedChange"; + QQuickItem *item = value.item; + QObject::connect(item, SIGNAL(destroyed()), this, SLOT(onItemDestroyed())); + QObject::connect(item, SIGNAL(visibleChanged()), this, SLOT(onItemVisibleChanged())); + } else if (change == ItemChildRemovedChange) { + quickLayoutDebug() << "ItemChildRemovedChange"; + QQuickItem *item = value.item; + QObject::disconnect(item, SIGNAL(destroyed()), this, SLOT(onItemDestroyed())); + QObject::disconnect(item, SIGNAL(visibleChanged()), this, SLOT(onItemVisibleChanged())); + } + + QQuickLayout::itemChange(change, value); +} + +void QQuickGridLayoutBase::removeGridItem(QGridLayoutItem *gridItem) +{ + Q_D(QQuickGridLayoutBase); + const int index = gridItem->firstRow(d->orientation); + d->engine.removeItem(gridItem); + d->engine.removeRows(index, 1, d->orientation); +} + +void QQuickGridLayoutBase::onItemVisibleChanged() +{ + if (!isReady()) + return; + quickLayoutDebug() << "QQuickGridLayoutBase::onItemVisibleChanged"; + updateLayoutItems(); +} + +void QQuickGridLayoutBase::onItemDestroyed() +{ + if (!isReady()) + return; + Q_D(QQuickGridLayoutBase); + quickLayoutDebug() << "QQuickGridLayoutBase::onItemDestroyed"; + QQuickItem *inDestruction = static_cast<QQuickItem *>(sender()); + if (QQuickGridLayoutItem *gridItem = d->engine.findLayoutItem(inDestruction)) { + removeGridItem(gridItem); + delete gridItem; + invalidate(); + } +} + +void QQuickGridLayoutBase::rearrange(const QSizeF &size) +{ + Q_D(QQuickGridLayoutBase); + if (!isReady()) + return; + + d->m_rearranging = true; + quickLayoutDebug() << objectName() << "QQuickGridLayoutBase::rearrange()" << size; + Qt::LayoutDirection visualDir = effectiveLayoutDirection(); + d->engine.setVisualDirection(visualDir); + + /* + qreal left, top, right, bottom; + left = top = right = bottom = 0; // ### support for margins? + if (visualDir == Qt::RightToLeft) + qSwap(left, right); + */ + + // Set m_dirty to false in case size hint changes during arrangement. + // This could happen if there is a binding like implicitWidth: height + QQuickLayout::rearrange(size); + d->engine.setGeometries(QRectF(QPointF(0,0), size), d->styleInfo); + d->m_rearranging = false; + + for (QQuickItem *invalid : qAsConst(d->m_invalidateAfterRearrange)) + invalidate(invalid); + d->m_invalidateAfterRearrange.clear(); + + if (d->m_updateAfterRearrange) { + updateLayoutItems(); + d->m_updateAfterRearrange = false; + } +} + +/********************************** + ** + ** QQuickGridLayout + ** + **/ +QQuickGridLayout::QQuickGridLayout(QQuickItem *parent /* = 0*/) + : QQuickGridLayoutBase(*new QQuickGridLayoutPrivate, Qt::Horizontal, parent) +{ +} + +/*! + \qmlproperty real GridLayout::columnSpacing + + This property holds the spacing between each column. + The default value is \c 5. +*/ +qreal QQuickGridLayout::columnSpacing() const +{ + Q_D(const QQuickGridLayout); + return d->engine.spacing(Qt::Horizontal, d->styleInfo); +} + +void QQuickGridLayout::setColumnSpacing(qreal spacing) +{ + Q_D(QQuickGridLayout); + if (qIsNaN(spacing) || columnSpacing() == spacing) + return; + + d->engine.setSpacing(spacing, Qt::Horizontal); + invalidate(); +} + +/*! + \qmlproperty real GridLayout::rowSpacing + + This property holds the spacing between each row. + The default value is \c 5. +*/ +qreal QQuickGridLayout::rowSpacing() const +{ + Q_D(const QQuickGridLayout); + return d->engine.spacing(Qt::Vertical, d->styleInfo); +} + +void QQuickGridLayout::setRowSpacing(qreal spacing) +{ + Q_D(QQuickGridLayout); + if (qIsNaN(spacing) || rowSpacing() == spacing) + return; + + d->engine.setSpacing(spacing, Qt::Vertical); + invalidate(); +} + +/*! + \qmlproperty int GridLayout::columns + + This property holds the column limit for items positioned if \l flow is + \c GridLayout.LeftToRight. + The default value is that there is no limit. +*/ +int QQuickGridLayout::columns() const +{ + Q_D(const QQuickGridLayout); + return d->columns; +} + +void QQuickGridLayout::setColumns(int columns) +{ + Q_D(QQuickGridLayout); + if (d->columns == columns) + return; + d->columns = columns; + updateLayoutItems(); + emit columnsChanged(); +} + + +/*! + \qmlproperty int GridLayout::rows + + This property holds the row limit for items positioned if \l flow is \c GridLayout.TopToBottom. + The default value is that there is no limit. +*/ +int QQuickGridLayout::rows() const +{ + Q_D(const QQuickGridLayout); + return d->rows; +} + +void QQuickGridLayout::setRows(int rows) +{ + Q_D(QQuickGridLayout); + if (d->rows == rows) + return; + d->rows = rows; + updateLayoutItems(); + emit rowsChanged(); +} + + +/*! + \qmlproperty enumeration GridLayout::flow + + This property holds the flow direction of items that does not have an explicit cell + position set. + It is used together with the \l columns or \l rows property, where + they specify when flow is reset to the next row or column respectively. + + Possible values are: + + \list + \li GridLayout.LeftToRight (default) - Items are positioned next to + each other, then wrapped to the next line. + \li GridLayout.TopToBottom - Items are positioned next to each + other from top to bottom, then wrapped to the next column. + \endlist + + \sa rows + \sa columns +*/ +QQuickGridLayout::Flow QQuickGridLayout::flow() const +{ + Q_D(const QQuickGridLayout); + return d->flow; +} + +void QQuickGridLayout::setFlow(QQuickGridLayout::Flow flow) +{ + Q_D(QQuickGridLayout); + if (d->flow == flow) + return; + d->flow = flow; + // If flow is changed, the layout needs to be repopulated + updateLayoutItems(); + emit flowChanged(); +} + +void QQuickGridLayout::insertLayoutItems() +{ + Q_D(QQuickGridLayout); + + int nextCellPos[2] = {0,0}; + int &nextColumn = nextCellPos[0]; + int &nextRow = nextCellPos[1]; + + const int flowOrientation = flow(); + int &flowColumn = nextCellPos[flowOrientation]; + int &flowRow = nextCellPos[1 - flowOrientation]; + int flowBound = (flowOrientation == QQuickGridLayout::LeftToRight) ? columns() : rows(); + + if (flowBound < 0) + flowBound = std::numeric_limits<int>::max(); + + d->m_ignoredItems.clear(); + QSizeF sizeHints[Qt::NSizeHints]; + const auto items = childItems(); + for (QQuickItem *child : items) { + QQuickLayoutAttached *info = 0; + + // Will skip all items with effective maximum width/height == 0 + if (shouldIgnoreItem(child, info, sizeHints)) + continue; + + Qt::Alignment alignment = 0; + int row = -1; + int column = -1; + int span[2] = {1,1}; + int &columnSpan = span[0]; + int &rowSpan = span[1]; + + bool invalidRowColumn = false; + if (info) { + if (info->isRowSet() || info->isColumnSet()) { + // If row is specified and column is not specified (or vice versa), + // the unspecified component of the cell position should default to 0 + row = column = 0; + if (info->isRowSet()) { + row = info->row(); + invalidRowColumn = row < 0; + } + if (info->isColumnSet()) { + column = info->column(); + invalidRowColumn = column < 0; + } + } + if (invalidRowColumn) { + qWarning("QQuickGridLayoutBase::insertLayoutItems: invalid row/column: %d", + row < 0 ? row : column); + return; + } + rowSpan = info->rowSpan(); + columnSpan = info->columnSpan(); + if (columnSpan < 1 || rowSpan < 1) { + qWarning("QQuickGridLayoutBase::addItem: invalid row span/column span: %d", + rowSpan < 1 ? rowSpan : columnSpan); + return; + } + + alignment = info->alignment(); + } + + Q_ASSERT(columnSpan >= 1); + Q_ASSERT(rowSpan >= 1); + const int sp = span[flowOrientation]; + if (sp > flowBound) + return; + + if (row >= 0) + nextRow = row; + if (column >= 0) + nextColumn = column; + + if (row < 0 || column < 0) { + /* if row or column is not specified, find next position by + advancing in the flow direction until there is a cell that + can accept the item. + + The acceptance rules are pretty simple, but complexity arises + when an item requires several cells (due to spans): + 1. Check if the cells that the item will require + does not extend beyond columns (for LeftToRight) or + rows (for TopToBottom). + 2. Check if the cells that the item will require is not already + taken by another item. + */ + bool cellAcceptsItem; + while (true) { + // Check if the item does not span beyond the layout bound + cellAcceptsItem = (flowColumn + sp) <= flowBound; + + // Check if all the required cells are not taken + for (int rs = 0; cellAcceptsItem && rs < rowSpan; ++rs) { + for (int cs = 0; cellAcceptsItem && cs < columnSpan; ++cs) { + if (d->engine.itemAt(nextRow + rs, nextColumn + cs)) { + cellAcceptsItem = false; + } + } + } + if (cellAcceptsItem) + break; + ++flowColumn; + if (flowColumn == flowBound) { + flowColumn = 0; + ++flowRow; + } + } + } + column = nextColumn; + row = nextRow; + QQuickGridLayoutItem *layoutItem = new QQuickGridLayoutItem(child, row, column, rowSpan, columnSpan, alignment); + layoutItem->setCachedSizeHints(sizeHints); + + d->engine.insertItem(layoutItem, -1); + } +} + +/********************************** + ** + ** QQuickLinearLayout + ** + **/ +QQuickLinearLayout::QQuickLinearLayout(Qt::Orientation orientation, + QQuickItem *parent /*= 0*/) + : QQuickGridLayoutBase(*new QQuickLinearLayoutPrivate, orientation, parent) +{ +} + +/*! + \qmlproperty enumeration RowLayout::layoutDirection + \since QtQuick.Layouts 1.1 + + This property holds the layout direction of the row layout - it controls whether items are laid + out from left ro right or right to left. If \c Qt.RightToLeft is specified, + left-aligned items will be right-aligned and right-aligned items will be left-aligned. + + Possible values: + + \list + \li Qt.LeftToRight (default) - Items are laid out from left to right. + \li Qt.RightToLeft - Items are laid out from right to left + \endlist + + \sa GridLayout::layoutDirection, ColumnLayout::layoutDirection +*/ +/*! + \qmlproperty enumeration ColumnLayout::layoutDirection + \since QtQuick.Layouts 1.1 + + This property holds the layout direction of the column layout - it controls whether items are laid + out from left ro right or right to left. If \c Qt.RightToLeft is specified, + left-aligned items will be right-aligned and right-aligned items will be left-aligned. + + Possible values: + + \list + \li Qt.LeftToRight (default) - Items are laid out from left to right. + \li Qt.RightToLeft - Items are laid out from right to left + \endlist + + \sa GridLayout::layoutDirection, RowLayout::layoutDirection +*/ + + +/*! + \qmlproperty real RowLayout::spacing + + This property holds the spacing between each cell. + The default value is \c 5. +*/ +/*! + \qmlproperty real ColumnLayout::spacing + + This property holds the spacing between each cell. + The default value is \c 5. +*/ + +qreal QQuickLinearLayout::spacing() const +{ + Q_D(const QQuickLinearLayout); + return d->engine.spacing(d->orientation, d->styleInfo); +} + +void QQuickLinearLayout::setSpacing(qreal space) +{ + Q_D(QQuickLinearLayout); + if (qIsNaN(space) || spacing() == space) + return; + + d->engine.setSpacing(space, Qt::Horizontal | Qt::Vertical); + invalidate(); +} + +void QQuickLinearLayout::insertLayoutItems() +{ + Q_D(QQuickLinearLayout); + d->m_ignoredItems.clear(); + QSizeF sizeHints[Qt::NSizeHints]; + const auto items = childItems(); + for (QQuickItem *child : items) { + Q_ASSERT(child); + QQuickLayoutAttached *info = 0; + + // Will skip all items with effective maximum width/height == 0 + if (shouldIgnoreItem(child, info, sizeHints)) + continue; + + Qt::Alignment alignment = 0; + if (info) + alignment = info->alignment(); + + const int index = d->engine.rowCount(d->orientation); + d->engine.insertRow(index, d->orientation); + + int gridRow = 0; + int gridColumn = index; + if (d->orientation == Qt::Vertical) + qSwap(gridRow, gridColumn); + QQuickGridLayoutItem *layoutItem = new QQuickGridLayoutItem(child, gridRow, gridColumn, 1, 1, alignment); + layoutItem->setCachedSizeHints(sizeHints); + d->engine.insertItem(layoutItem, index); + } +} + +QT_END_NAMESPACE diff --git a/src/imports/layouts/qquicklinearlayout_p.h b/src/imports/layouts/qquicklinearlayout_p.h new file mode 100644 index 0000000000..86404f8d79 --- /dev/null +++ b/src/imports/layouts/qquicklinearlayout_p.h @@ -0,0 +1,250 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Layouts module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKLINEARLAYOUT_P_H +#define QQUICKLINEARLAYOUT_P_H + +#include "qquicklayout_p.h" +#include "qquickgridlayoutengine_p.h" + +QT_BEGIN_NAMESPACE + +/********************************** + ** + ** QQuickGridLayoutBase + ** + **/ +class QQuickGridLayoutBasePrivate; + +class QQuickGridLayoutBase : public QQuickLayout +{ + Q_OBJECT + + Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged REVISION 1) + +public: + + QQuickGridLayoutBase(); + + explicit QQuickGridLayoutBase(QQuickGridLayoutBasePrivate &dd, + Qt::Orientation orientation, + QQuickItem *parent = 0); + + ~QQuickGridLayoutBase(); + void componentComplete() Q_DECL_OVERRIDE; + void invalidate(QQuickItem *childItem = 0) Q_DECL_OVERRIDE; + Qt::Orientation orientation() const; + void setOrientation(Qt::Orientation orientation); + QSizeF sizeHint(Qt::SizeHint whichSizeHint) const Q_DECL_OVERRIDE; + Qt::LayoutDirection layoutDirection() const; + void setLayoutDirection(Qt::LayoutDirection dir); + Qt::LayoutDirection effectiveLayoutDirection() const; + void setAlignment(QQuickItem *item, Qt::Alignment align) Q_DECL_OVERRIDE; + +protected: + void updateLayoutItems() Q_DECL_OVERRIDE; + QQuickItem *itemAt(int index) const Q_DECL_OVERRIDE; + int itemCount() const Q_DECL_OVERRIDE; + + void rearrange(const QSizeF &size) Q_DECL_OVERRIDE; + virtual void insertLayoutItems() {} + void itemChange(ItemChange change, const ItemChangeData &data) Q_DECL_OVERRIDE; + +signals: + Q_REVISION(1) void layoutDirectionChanged(); + +protected slots: + void onItemVisibleChanged(); + void onItemDestroyed(); + +private: + void removeGridItem(QGridLayoutItem *gridItem); + Q_DECLARE_PRIVATE(QQuickGridLayoutBase) +}; + +class QQuickLayoutStyleInfo; + +class QQuickGridLayoutBasePrivate : public QQuickLayoutPrivate +{ + Q_DECLARE_PUBLIC(QQuickGridLayoutBase) + +public: + QQuickGridLayoutBasePrivate() : m_rearranging(false) + , m_updateAfterRearrange(false) + , m_layoutDirection(Qt::LeftToRight) + {} + + void mirrorChange() Q_DECL_OVERRIDE + { + Q_Q(QQuickGridLayoutBase); + q->invalidate(); + } + + QQuickGridLayoutEngine engine; + Qt::Orientation orientation; + unsigned m_rearranging : 1; + unsigned m_updateAfterRearrange : 1; + QVector<QQuickItem *> m_invalidateAfterRearrange; + Qt::LayoutDirection m_layoutDirection : 2; + + QQuickLayoutStyleInfo *styleInfo; +}; + +/********************************** + ** + ** QQuickGridLayout + ** + **/ +class QQuickGridLayoutPrivate; +class QQuickGridLayout : public QQuickGridLayoutBase +{ + Q_OBJECT + + Q_PROPERTY(qreal columnSpacing READ columnSpacing WRITE setColumnSpacing NOTIFY columnSpacingChanged) + Q_PROPERTY(qreal rowSpacing READ rowSpacing WRITE setRowSpacing NOTIFY rowSpacingChanged) + Q_PROPERTY(int columns READ columns WRITE setColumns NOTIFY columnsChanged) + Q_PROPERTY(int rows READ rows WRITE setRows NOTIFY rowsChanged) + Q_PROPERTY(Flow flow READ flow WRITE setFlow NOTIFY flowChanged) +public: + explicit QQuickGridLayout(QQuickItem *parent = 0); + qreal columnSpacing() const; + void setColumnSpacing(qreal spacing); + qreal rowSpacing() const; + void setRowSpacing(qreal spacing); + + int columns() const; + void setColumns(int columns); + int rows() const; + void setRows(int rows); + + Q_ENUMS(Flow) + enum Flow { LeftToRight, TopToBottom }; + Flow flow() const; + void setFlow(Flow flow); + + void insertLayoutItems(); + +signals: + void columnSpacingChanged(); + void rowSpacingChanged(); + + void columnsChanged(); + void rowsChanged(); + + void flowChanged(); +private: + Q_DECLARE_PRIVATE(QQuickGridLayout) +}; + +class QQuickGridLayoutPrivate : public QQuickGridLayoutBasePrivate +{ + Q_DECLARE_PUBLIC(QQuickGridLayout) +public: + QQuickGridLayoutPrivate(): columns(-1), rows(-1), flow(QQuickGridLayout::LeftToRight) {} + int columns; + int rows; + QQuickGridLayout::Flow flow; +}; + + +/********************************** + ** + ** QQuickLinearLayout + ** + **/ +class QQuickLinearLayoutPrivate; +class QQuickLinearLayout : public QQuickGridLayoutBase +{ + Q_OBJECT + Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing NOTIFY spacingChanged) +public: + explicit QQuickLinearLayout(Qt::Orientation orientation, + QQuickItem *parent = 0); + void insertLayoutItem(QQuickItem *item); + qreal spacing() const; + void setSpacing(qreal spacing); + + void insertLayoutItems(); + +signals: + void spacingChanged(); +private: + Q_DECLARE_PRIVATE(QQuickLinearLayout) +}; + +class QQuickLinearLayoutPrivate : public QQuickGridLayoutBasePrivate +{ + Q_DECLARE_PUBLIC(QQuickLinearLayout) +public: + QQuickLinearLayoutPrivate() {} +}; + + +/********************************** + ** + ** QQuickRowLayout + ** + **/ +class QQuickRowLayout : public QQuickLinearLayout +{ + Q_OBJECT + +public: + explicit QQuickRowLayout(QQuickItem *parent = 0) + : QQuickLinearLayout(Qt::Horizontal, parent) {} +}; + + +/********************************** + ** + ** QQuickColumnLayout + ** + **/ +class QQuickColumnLayout : public QQuickLinearLayout +{ + Q_OBJECT + +public: + explicit QQuickColumnLayout(QQuickItem *parent = 0) + : QQuickLinearLayout(Qt::Vertical, parent) {} +}; + +QT_END_NAMESPACE + +#endif // QQUICKLINEARLAYOUT_P_H diff --git a/src/imports/layouts/qquickstacklayout.cpp b/src/imports/layouts/qquickstacklayout.cpp new file mode 100644 index 0000000000..a223dd0374 --- /dev/null +++ b/src/imports/layouts/qquickstacklayout.cpp @@ -0,0 +1,339 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Layouts module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickstacklayout_p.h" +#include <limits> + +/*! + \qmltype StackLayout + \instantiates QQuickStackLayout + \inherits Item + \inqmlmodule QtQuick.Layouts + \ingroup layouts + \brief The StackLayout class provides a stack of items where + only one item is visible at a time. + + The current visible item can be modified by setting the \l currentIndex property. + The index corresponds to the order of the StackLayout's children. + + In contrast to most other layouts, child Items' \l{Layout::fillWidth}{Layout.fillWidth} and \l{Layout::fillHeight}{Layout.fillHeight} properties + default to \c true. As a consequence, child items are by default filled to match the size of the StackLayout as long as their + \l{Layout::maximumWidth}{Layout.maximumWidth} or \l{Layout::maximumHeight}{Layout.maximumHeight} does not prevent it. + + Items are added to the layout by reparenting the item to the layout. Similarly, removal is done by reparenting the item from the layout. + Both of these operations will affect the layout's \l count property. + + The following code will create a StackLayout where only the 'plum' rectangle is visible. + \code + StackLayout { + id: layout + anchors.fill: parent + currentIndex: 1 + Rectangle { + color: 'teal' + implicitWidth: 200 + implicitHeight: 200 + } + Rectangle { + color: 'plum' + implicitWidth: 300 + implicitHeight: 200 + } + } + \endcode + + Items in a StackLayout support these attached properties: + \list + \li \l{Layout::minimumWidth}{Layout.minimumWidth} + \li \l{Layout::minimumHeight}{Layout.minimumHeight} + \li \l{Layout::preferredWidth}{Layout.preferredWidth} + \li \l{Layout::preferredHeight}{Layout.preferredHeight} + \li \l{Layout::maximumWidth}{Layout.maximumWidth} + \li \l{Layout::maximumHeight}{Layout.maximumHeight} + \li \l{Layout::fillWidth}{Layout.fillWidth} + \li \l{Layout::fillHeight}{Layout.fillHeight} + \endlist + + Read more about attached properties \l{QML Object Attributes}{here}. + \sa ColumnLayout + \sa GridLayout + \sa RowLayout + \sa StackView +*/ + +QQuickStackLayout::QQuickStackLayout(QQuickItem *parent) : + QQuickLayout(*new QQuickStackLayoutPrivate, parent) +{ +} + +/*! + \qmlproperty int StackLayout::count + + This property holds the number of items that belong to the layout. + + Only items that are children of the StackLayout will be candidates for layouting. +*/ +int QQuickStackLayout::count() const +{ + Q_D(const QQuickStackLayout); + return d->count; +} + +/*! + \qmlproperty int StackLayout::currentIndex + + This property holds the index of the child item that is currently visible in the StackLayout. + By default it will be \c -1 for an empty layout, otherwise the default is \c 0 (referring to the first item). +*/ +int QQuickStackLayout::currentIndex() const +{ + Q_D(const QQuickStackLayout); + return d->currentIndex; +} + +void QQuickStackLayout::setCurrentIndex(int index) +{ + Q_D(QQuickStackLayout); + if (index != d->currentIndex) { + QQuickItem *prev = itemAt(d->currentIndex); + QQuickItem *next = itemAt(index); + d->currentIndex = index; + d->explicitCurrentIndex = true; + if (prev) + prev->setVisible(false); + if (next) + next->setVisible(true); + + if (isComponentComplete()) { + rearrange(QSizeF(width(), height())); + emit currentIndexChanged(); + } + } +} + +void QQuickStackLayout::componentComplete() +{ + QQuickLayout::componentComplete(); // will call our geometryChange(), (where isComponentComplete() == true) + + updateLayoutItems(); + + QQuickItem *par = parentItem(); + if (qobject_cast<QQuickLayout*>(par)) + return; + + rearrange(QSizeF(width(), height())); +} + +QSizeF QQuickStackLayout::sizeHint(Qt::SizeHint whichSizeHint) const +{ + QSizeF &askingFor = m_cachedSizeHints[whichSizeHint]; + if (!askingFor.isValid()) { + QSizeF &minS = m_cachedSizeHints[Qt::MinimumSize]; + QSizeF &prefS = m_cachedSizeHints[Qt::PreferredSize]; + QSizeF &maxS = m_cachedSizeHints[Qt::MaximumSize]; + + minS = QSizeF(0,0); + prefS = QSizeF(0,0); + maxS = QSizeF(std::numeric_limits<qreal>::infinity(), std::numeric_limits<qreal>::infinity()); + + const int count = itemCount(); + m_cachedItemSizeHints.resize(count); + for (int i = 0; i < count; ++i) { + SizeHints &hints = m_cachedItemSizeHints[i]; + QQuickStackLayout::collectItemSizeHints(itemAt(i), hints.array); + minS = minS.expandedTo(hints.min()); + prefS = prefS.expandedTo(hints.pref()); + //maxS = maxS.boundedTo(hints.max()); // Can be resized to be larger than any of its items. + // This is the same as QStackLayout does it. + // Not sure how descent makes sense here... + } + } + return askingFor; +} + +int QQuickStackLayout::indexOf(QQuickItem *childItem) const +{ + if (childItem) { + int indexOfItem = 0; + const auto items = childItems(); + for (QQuickItem *item : items) { + if (shouldIgnoreItem(item)) + continue; + if (childItem == item) + return indexOfItem; + ++indexOfItem; + } + } + return -1; +} + +QQuickItem *QQuickStackLayout::itemAt(int index) const +{ + const auto items = childItems(); + for (QQuickItem *item : items) { + if (shouldIgnoreItem(item)) + continue; + if (index == 0) + return item; + --index; + } + return 0; +} + +int QQuickStackLayout::itemCount() const +{ + int count = 0; + const auto items = childItems(); + for (QQuickItem *item : items) { + if (shouldIgnoreItem(item)) + continue; + ++count; + } + return count; +} + +void QQuickStackLayout::setAlignment(QQuickItem * /*item*/, Qt::Alignment /*align*/) +{ + // ### Do we have to respect alignment? +} + +void QQuickStackLayout::invalidate(QQuickItem *childItem) +{ + Q_D(QQuickStackLayout); + if (d->m_ignoredItems.contains(childItem)) { + // If an invalid item gets a valid size, it should be included, as it was added to the layout + updateLayoutItems(); + return; + } + + const int indexOfChild = indexOf(childItem); + if (indexOfChild >= 0 && indexOfChild < m_cachedItemSizeHints.count()) { + m_cachedItemSizeHints[indexOfChild].min() = QSizeF(); + m_cachedItemSizeHints[indexOfChild].pref() = QSizeF(); + m_cachedItemSizeHints[indexOfChild].max() = QSizeF(); + } + + for (int i = 0; i < Qt::NSizeHints; ++i) + m_cachedSizeHints[i] = QSizeF(); + QQuickLayout::invalidate(this); + + QQuickLayoutAttached *info = attachedLayoutObject(this); + + const QSizeF min = sizeHint(Qt::MinimumSize); + const QSizeF pref = sizeHint(Qt::PreferredSize); + const QSizeF max = sizeHint(Qt::MaximumSize); + + const bool old = info->setChangesNotificationEnabled(false); + info->setMinimumImplicitSize(min); + info->setMaximumImplicitSize(max); + info->setChangesNotificationEnabled(old); + if (pref.width() == implicitWidth() && pref.height() == implicitHeight()) { + // In case setImplicitSize does not emit implicit{Width|Height}Changed + if (QQuickLayout *parentLayout = qobject_cast<QQuickLayout *>(parentItem())) + parentLayout->invalidate(this); + } else { + setImplicitSize(pref.width(), pref.height()); + } +} + +void QQuickStackLayout::updateLayoutItems() +{ + Q_D(QQuickStackLayout); + d->m_ignoredItems.clear(); + const int count = itemCount(); + int oldIndex = d->currentIndex; + if (!d->explicitCurrentIndex) + d->currentIndex = (count > 0 ? 0 : -1); + + if (d->currentIndex != oldIndex) + emit currentIndexChanged(); + + if (count != d->count) { + d->count = count; + emit countChanged(); + } + for (int i = 0; i < count; ++i) + itemAt(i)->setVisible(d->currentIndex == i); + + invalidate(); +} + +void QQuickStackLayout::rearrange(const QSizeF &newSize) +{ + Q_D(QQuickStackLayout); + if (newSize.isNull() || !newSize.isValid()) + return; + (void)sizeHint(Qt::PreferredSize); // Make sure m_cachedItemSizeHints are valid + + if (d->currentIndex == -1 || d->currentIndex >= m_cachedItemSizeHints.count()) + return; + QQuickStackLayout::SizeHints &hints = m_cachedItemSizeHints[d->currentIndex]; + QQuickItem *item = itemAt(d->currentIndex); + Q_ASSERT(item); + item->setPosition(QPointF(0,0)); // ### respect alignment? + item->setSize(newSize.expandedTo(hints.min()).boundedTo(hints.max())); + QQuickLayout::rearrange(newSize); +} + +void QQuickStackLayout::collectItemSizeHints(QQuickItem *item, QSizeF *sizeHints) +{ + QQuickLayoutAttached *info = 0; + QQuickLayout::effectiveSizeHints_helper(item, sizeHints, &info, true); + if (!info) + return; + if (info->isFillWidthSet() && !info->fillWidth()) { + const qreal pref = sizeHints[Qt::PreferredSize].width(); + sizeHints[Qt::MinimumSize].setWidth(pref); + sizeHints[Qt::MaximumSize].setWidth(pref); + } + + if (info->isFillHeightSet() && !info->fillHeight()) { + const qreal pref = sizeHints[Qt::PreferredSize].height(); + sizeHints[Qt::MinimumSize].setHeight(pref); + sizeHints[Qt::MaximumSize].setHeight(pref); + } +} + +bool QQuickStackLayout::shouldIgnoreItem(QQuickItem *item) const +{ + const bool ignored = QQuickItemPrivate::get(item)->isTransparentForPositioner(); + if (ignored) + d_func()->m_ignoredItems << item; + return ignored; +} diff --git a/src/imports/layouts/qquickstacklayout_p.h b/src/imports/layouts/qquickstacklayout_p.h new file mode 100644 index 0000000000..7b6400c3a3 --- /dev/null +++ b/src/imports/layouts/qquickstacklayout_p.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Layouts module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKSTACKLAYOUT_H +#define QQUICKSTACKLAYOUT_H + +#include <qquicklayout_p.h> + +class QQuickStackLayoutPrivate; + +class QQuickStackLayout : public QQuickLayout +{ + Q_OBJECT + Q_PROPERTY(int count READ count NOTIFY countChanged) + Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged) + +public: + explicit QQuickStackLayout(QQuickItem *parent = 0); + int count() const; + int currentIndex() const; + void setCurrentIndex(int index); + + void componentComplete() Q_DECL_OVERRIDE; + QSizeF sizeHint(Qt::SizeHint whichSizeHint) const Q_DECL_OVERRIDE; + void setAlignment(QQuickItem *item, Qt::Alignment align) Q_DECL_OVERRIDE; + void invalidate(QQuickItem *childItem = 0) Q_DECL_OVERRIDE; + void updateLayoutItems() Q_DECL_OVERRIDE; + void rearrange(const QSizeF &) Q_DECL_OVERRIDE; + + // iterator + Q_INVOKABLE QQuickItem *itemAt(int index) const Q_DECL_OVERRIDE; + int itemCount() const Q_DECL_OVERRIDE; + int indexOf(QQuickItem *item) const; + + + +signals: + void currentIndexChanged(); + void countChanged(); + +public slots: + +private: + static void collectItemSizeHints(QQuickItem *item, QSizeF *sizeHints); + bool shouldIgnoreItem(QQuickItem *item) const; + Q_DECLARE_PRIVATE(QQuickStackLayout) + + QList<QQuickItem*> m_items; + + typedef struct { + inline QSizeF &min() { return array[Qt::MinimumSize]; } + inline QSizeF &pref() { return array[Qt::PreferredSize]; } + inline QSizeF &max() { return array[Qt::MaximumSize]; } + QSizeF array[Qt::NSizeHints]; + } SizeHints; + + mutable QVector<SizeHints> m_cachedItemSizeHints; + mutable QSizeF m_cachedSizeHints[Qt::NSizeHints]; +}; + +class QQuickStackLayoutPrivate : public QQuickLayoutPrivate +{ + Q_DECLARE_PUBLIC(QQuickStackLayout) +public: + QQuickStackLayoutPrivate() : count(0), currentIndex(-1), explicitCurrentIndex(false) {} +private: + int count; + int currentIndex; + bool explicitCurrentIndex; +}; + +#endif // QQUICKSTACKLAYOUT_H diff --git a/src/particles/particles.pro b/src/particles/particles.pro index ba65ee3002..ab1c854253 100644 --- a/src/particles/particles.pro +++ b/src/particles/particles.pro @@ -1,4 +1,5 @@ TARGET = QtQuickParticles +MODULE = quickparticles CONFIG += internal_module @@ -13,7 +14,6 @@ exists("qqml_enable_gcov") { LIBS_PRIVATE += -lgcov } -MODULE = quickparticles -load(qt_module) - include(particles.pri) + +load(qt_module) diff --git a/src/particles/qquickparticleemitter.cpp b/src/particles/qquickparticleemitter.cpp index 7e1a31f206..4d9f834492 100644 --- a/src/particles/qquickparticleemitter.cpp +++ b/src/particles/qquickparticleemitter.cpp @@ -343,7 +343,7 @@ void QQuickParticleEmitter::emitWindow(int timeStamp) { if (m_system == 0) return; - if ((!m_enabled || !m_particlesPerSecond)&& !m_pulseLeft && m_burstQueue.isEmpty()){ + if ((!m_enabled || m_particlesPerSecond <= 0)&& !m_pulseLeft && m_burstQueue.isEmpty()){ m_reset_last = true; return; } diff --git a/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro b/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro index 3703d0fe0b..27b3a5b513 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro +++ b/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro @@ -1,10 +1,6 @@ TARGET = qmldbg_debugger QT = qml-private core-private packetprotocol-private -PLUGIN_TYPE = qmltooling -PLUGIN_CLASS_NAME = QQmlDebuggerServiceFactory -load(qt_plugin) - SOURCES += \ $$PWD/qdebugmessageservice.cpp \ $$PWD/qqmldebuggerservicefactory.cpp \ @@ -37,3 +33,6 @@ INCLUDEPATH += $$PWD \ OTHER_FILES += \ $$PWD/qqmldebuggerservice.json +PLUGIN_TYPE = qmltooling +PLUGIN_CLASS_NAME = QQmlDebuggerServiceFactory +load(qt_plugin) diff --git a/src/plugins/qmltooling/qmldbg_inspector/qmldbg_inspector.pro b/src/plugins/qmltooling/qmldbg_inspector/qmldbg_inspector.pro index c2ee733db6..a8844944e0 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qmldbg_inspector.pro +++ b/src/plugins/qmltooling/qmldbg_inspector/qmldbg_inspector.pro @@ -1,10 +1,6 @@ TARGET = qmldbg_inspector QT += qml-private quick-private core-private gui-private packetprotocol-private -PLUGIN_TYPE = qmltooling -PLUGIN_CLASS_NAME = QQmlInspectorServiceFactory -load(qt_plugin) - INCLUDEPATH *= $$PWD $$PWD/../shared SOURCES += \ @@ -24,3 +20,7 @@ HEADERS += \ OTHER_FILES += \ qqmlinspectorservice.json + +PLUGIN_TYPE = qmltooling +PLUGIN_CLASS_NAME = QQmlInspectorServiceFactory +load(qt_plugin) diff --git a/src/plugins/qmltooling/qmldbg_local/qmldbg_local.pro b/src/plugins/qmltooling/qmldbg_local/qmldbg_local.pro index 491be04b15..d731e47b7e 100644 --- a/src/plugins/qmltooling/qmldbg_local/qmldbg_local.pro +++ b/src/plugins/qmltooling/qmldbg_local/qmldbg_local.pro @@ -1,10 +1,6 @@ TARGET = qmldbg_local QT = qml-private -PLUGIN_TYPE = qmltooling -PLUGIN_CLASS_NAME = QLocalClientConnectionFactory -load(qt_plugin) - SOURCES += \ $$PWD/qlocalclientconnection.cpp @@ -18,3 +14,7 @@ INCLUDEPATH += $$PWD \ OTHER_FILES += \ $$PWD/qlocalclientconnection.json + +PLUGIN_TYPE = qmltooling +PLUGIN_CLASS_NAME = QLocalClientConnectionFactory +load(qt_plugin) diff --git a/src/plugins/qmltooling/qmldbg_native/qmldbg_native.pro b/src/plugins/qmltooling/qmldbg_native/qmldbg_native.pro index d490d77e50..b3fe1681e8 100644 --- a/src/plugins/qmltooling/qmldbg_native/qmldbg_native.pro +++ b/src/plugins/qmltooling/qmldbg_native/qmldbg_native.pro @@ -1,10 +1,6 @@ TARGET = qmldbg_native QT += qml-private core-private packetprotocol-private -PLUGIN_TYPE = qmltooling -PLUGIN_CLASS_NAME = QQmlNativeDebugConnectorFactory -load(qt_plugin) - HEADERS += \ $$PWD/../shared/qqmldebugpacket.h \ $$PWD/qqmlnativedebugconnector.h @@ -17,3 +13,7 @@ INCLUDEPATH += $$PWD \ OTHER_FILES += \ $$PWD/qqmlnativedebugconnector.json + +PLUGIN_TYPE = qmltooling +PLUGIN_CLASS_NAME = QQmlNativeDebugConnectorFactory +load(qt_plugin) diff --git a/src/plugins/qmltooling/qmldbg_profiler/qmldbg_profiler.pro b/src/plugins/qmltooling/qmldbg_profiler/qmldbg_profiler.pro index 6efe9eacad..4629a7b81e 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qmldbg_profiler.pro +++ b/src/plugins/qmltooling/qmldbg_profiler/qmldbg_profiler.pro @@ -1,10 +1,6 @@ TARGET = qmldbg_profiler QT = qml-private core-private packetprotocol-private -PLUGIN_TYPE = qmltooling -PLUGIN_CLASS_NAME = QQmlProfilerServiceFactory -load(qt_plugin) - SOURCES += \ $$PWD/qqmlenginecontrolservice.cpp \ $$PWD/qqmlprofileradapter.cpp \ @@ -27,3 +23,6 @@ INCLUDEPATH += $$PWD \ OTHER_FILES += \ $$PWD/qqmlprofilerservice.json +PLUGIN_TYPE = qmltooling +PLUGIN_CLASS_NAME = QQmlProfilerServiceFactory +load(qt_plugin) diff --git a/src/plugins/qmltooling/qmldbg_server/qmldbg_server.pro b/src/plugins/qmltooling/qmldbg_server/qmldbg_server.pro index 923faa01f3..fffdb4c888 100644 --- a/src/plugins/qmltooling/qmldbg_server/qmldbg_server.pro +++ b/src/plugins/qmltooling/qmldbg_server/qmldbg_server.pro @@ -1,10 +1,6 @@ TARGET = qmldbg_server QT = qml-private packetprotocol-private -PLUGIN_TYPE = qmltooling -PLUGIN_CLASS_NAME = QQmlDebugServerFactory -load(qt_plugin) - SOURCES += \ $$PWD/qqmldebugserver.cpp @@ -19,3 +15,7 @@ INCLUDEPATH += $$PWD \ OTHER_FILES += \ qqmldebugserver.json + +PLUGIN_TYPE = qmltooling +PLUGIN_CLASS_NAME = QQmlDebugServerFactory +load(qt_plugin) diff --git a/src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro b/src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro index fd419aeb56..1face1813e 100644 --- a/src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro +++ b/src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro @@ -1,10 +1,6 @@ TARGET = qmldbg_tcp QT = qml-private network -PLUGIN_TYPE = qmltooling -PLUGIN_CLASS_NAME = QTcpServerConnectionFactory -load(qt_plugin) - SOURCES += \ $$PWD/qtcpserverconnection.cpp @@ -18,3 +14,7 @@ INCLUDEPATH += $$PWD \ OTHER_FILES += \ $$PWD/qtcpserverconnection.json + +PLUGIN_TYPE = qmltooling +PLUGIN_CLASS_NAME = QTcpServerConnectionFactory +load(qt_plugin) diff --git a/src/plugins/qmltooling/qmltooling.pro b/src/plugins/qmltooling/qmltooling.pro index 3728126dd9..7682e7b075 100644 --- a/src/plugins/qmltooling/qmltooling.pro +++ b/src/plugins/qmltooling/qmltooling.pro @@ -1,30 +1,32 @@ TEMPLATE = subdirs -# Utilities -SUBDIRS += \ - packetprotocol +!no_network { + # Utilities + SUBDIRS += \ + packetprotocol -# Connectors -SUBDIRS += \ - qmldbg_native \ - qmldbg_server \ + # Connectors + SUBDIRS += \ + qmldbg_native \ + qmldbg_server \ qmldbg_local \ qmldbg_tcp -# Services -SUBDIRS += \ - qmldbg_debugger \ - qmldbg_profiler + # Services + SUBDIRS += \ + qmldbg_debugger \ + qmldbg_profiler -qmldbg_server.depends = packetprotocol -qmldbg_native.depends = packetprotocol -qmldbg_debugger.depends = packetprotocol -qmldbg_profiler.depends = packetprotocol + qmldbg_server.depends = packetprotocol + qmldbg_native.depends = packetprotocol + qmldbg_debugger.depends = packetprotocol + qmldbg_profiler.depends = packetprotocol -qtHaveModule(quick) { - SUBDIRS += \ - qmldbg_inspector \ - qmldbg_quickprofiler - qmldbg_inspector.depends = packetprotocol - qmldbg_quickprofiler.depends = packetprotocol + qtHaveModule(quick) { + SUBDIRS += \ + qmldbg_inspector \ + qmldbg_quickprofiler + qmldbg_inspector.depends = packetprotocol + qmldbg_quickprofiler.depends = packetprotocol + } } diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 9fcfe53b05..a34c1cbf0e 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -411,7 +411,7 @@ bool IRBuilder::generateFromQml(const QString &code, const QString &url, Documen bool IRBuilder::isSignalPropertyName(const QString &name) { if (name.length() < 3) return false; - if (!name.startsWith(QStringLiteral("on"))) return false; + if (!name.startsWith(QLatin1String("on"))) return false; int ns = name.length(); for (int i = 2; i < ns; ++i) { const QChar curr = name.at(i); @@ -1061,7 +1061,7 @@ void IRBuilder::appendBinding(QQmlJS::AST::UiQualifiedId *name, QQmlJS::AST::Sta Object *object = 0; if (!resolveQualifiedId(&name, &object)) return; - if (_object == object && name->name == QStringLiteral("id")) { + if (_object == object && name->name == QLatin1String("id")) { setId(name->identifierToken, value); return; } @@ -1097,7 +1097,7 @@ void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLo void IRBuilder::appendBinding(const QQmlJS::AST::SourceLocation &qualifiedNameLocation, const QQmlJS::AST::SourceLocation &nameLocation, quint32 propertyNameIndex, int objectIndex, bool isListItem, bool isOnAssignment) { - if (stringAt(propertyNameIndex) == QStringLiteral("id")) { + if (stringAt(propertyNameIndex) == QLatin1String("id")) { recordError(nameLocation, tr("Invalid component id specification")); return; } @@ -1192,7 +1192,7 @@ bool IRBuilder::resolveQualifiedId(QQmlJS::AST::UiQualifiedId **nameToResolve, O { QQmlJS::AST::UiQualifiedId *qualifiedIdElement = *nameToResolve; - if (qualifiedIdElement->name == QStringLiteral("id") && qualifiedIdElement->next) + if (qualifiedIdElement->name == QLatin1String("id") && qualifiedIdElement->next) COMPILE_EXCEPTION(qualifiedIdElement->identifierToken, tr( "Invalid use of id property")); // If it's a namespace, prepend the qualifier and we'll resolve it later to the correct type. @@ -1918,7 +1918,7 @@ QQmlPropertyData *PropertyResolver::signal(const QString &name, bool *notInRevis return d; } - if (name.endsWith(QStringLiteral("Changed"))) { + if (name.endsWith(QLatin1String("Changed"))) { QString propName = name.mid(0, name.length() - static_cast<int>(strlen("Changed"))); d = property(propName, notInRevision); diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 2b3cd93052..33716d57b8 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -972,7 +972,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio QmlIR::PropertyResolver resolver(propertyCache); - Q_ASSERT(propertyName.startsWith(QStringLiteral("on"))); + Q_ASSERT(propertyName.startsWith(QLatin1String("on"))); propertyName.remove(0, 2); // Note that the property name could start with any alpha or '_' or '$' character, @@ -1039,7 +1039,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio } QHash<QString, QStringList>::ConstIterator entry = customSignals.constFind(propertyName); - if (entry == customSignals.constEnd() && propertyName.endsWith(QStringLiteral("Changed"))) { + if (entry == customSignals.constEnd() && propertyName.endsWith(QLatin1String("Changed"))) { QString alternateName = propertyName.mid(0, propertyName.length() - static_cast<int>(strlen("Changed"))); entry = customSignals.constFind(alternateName); } @@ -1163,6 +1163,17 @@ struct StaticQtMetaObject : public QObject { return &staticQtMetaObject; } }; +bool QQmlEnumTypeResolver::assignEnumToBinding(QmlIR::Binding *binding, const QString &enumName, int enumValue, bool isQtObject) +{ + if (enumName.length() > 0 && enumName[0].isLower() && !isQtObject) { + COMPILE_EXCEPTION(binding, tr("Invalid property assignment: Enum value \"%1\" cannot start with a lowercase letter").arg(enumName)); + } + binding->type = QV4::CompiledData::Binding::Type_Number; + binding->value.d = (double)enumValue; + binding->flags |= QV4::CompiledData::Binding::IsResolvedEnum; + return true; +} + bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, const QQmlPropertyCache *propertyCache, const QQmlPropertyData *prop, QmlIR::Binding *binding) { bool isIntProp = (prop->propType == QMetaType::Int) && !prop->isEnum(); @@ -1185,6 +1196,7 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, return true; QHashedStringRef typeName(string.constData(), dot); + const bool isQtObject = (typeName == QLatin1String("Qt")); QString enumValue = string.mid(dot+1); if (isIntProp) { @@ -1192,16 +1204,15 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, bool ok; int enumval = evaluateEnum(typeName.toString(), enumValue.toUtf8(), &ok); if (ok) { - binding->type = QV4::CompiledData::Binding::Type_Number; - binding->value.d = (double)enumval; - binding->flags |= QV4::CompiledData::Binding::IsResolvedEnum; + if (!assignEnumToBinding(binding, enumValue, enumval, isQtObject)) + return false; } return true; } QQmlType *type = 0; imports->resolveType(typeName, &type, 0, 0, 0); - if (!type && typeName != QLatin1String("Qt")) + if (!type && !isQtObject) return true; int value = 0; @@ -1234,10 +1245,7 @@ bool QQmlEnumTypeResolver::tryQualifiedEnumAssignment(const QmlIR::Object *obj, if (!ok) return true; - binding->type = QV4::CompiledData::Binding::Type_Number; - binding->value.d = (double)value; - binding->flags |= QV4::CompiledData::Binding::IsResolvedEnum; - return true; + return assignEnumToBinding(binding, enumValue, value, isQtObject); } int QQmlEnumTypeResolver::evaluateEnum(const QString &scope, const QByteArray &enumValue, bool *ok) const @@ -2749,7 +2757,7 @@ bool QQmlJavaScriptBindingExpressionSimplificationPass::simplifyBinding(QV4::IR: bool QQmlJavaScriptBindingExpressionSimplificationPass::detectTranslationCallAndConvertBinding(QmlIR::Binding *binding) { - if (*_nameOfFunctionCalled == QStringLiteral("qsTr")) { + if (*_nameOfFunctionCalled == QLatin1String("qsTr")) { QString translation; QV4::CompiledData::TranslationData translationData; translationData.number = -1; @@ -2791,7 +2799,7 @@ bool QQmlJavaScriptBindingExpressionSimplificationPass::detectTranslationCallAnd binding->stringIndex = compiler->registerString(translation); binding->value.translationData = translationData; return true; - } else if (*_nameOfFunctionCalled == QStringLiteral("qsTrId")) { + } else if (*_nameOfFunctionCalled == QLatin1String("qsTrId")) { QString id; QV4::CompiledData::TranslationData translationData; translationData.number = -1; @@ -2825,7 +2833,7 @@ bool QQmlJavaScriptBindingExpressionSimplificationPass::detectTranslationCallAnd binding->stringIndex = compiler->registerString(id); binding->value.translationData = translationData; return true; - } else if (*_nameOfFunctionCalled == QStringLiteral("QT_TR_NOOP") || *_nameOfFunctionCalled == QStringLiteral("QT_TRID_NOOP")) { + } else if (*_nameOfFunctionCalled == QLatin1String("QT_TR_NOOP") || *_nameOfFunctionCalled == QLatin1String("QT_TRID_NOOP")) { QVector<int>::ConstIterator param = _functionParameters.constBegin(); QVector<int>::ConstIterator end = _functionParameters.constEnd(); if (param == end) @@ -2842,7 +2850,7 @@ bool QQmlJavaScriptBindingExpressionSimplificationPass::detectTranslationCallAnd binding->type = QV4::CompiledData::Binding::Type_String; binding->stringIndex = compiler->registerString(*stringParam->value); return true; - } else if (*_nameOfFunctionCalled == QStringLiteral("QT_TRANSLATE_NOOP")) { + } else if (*_nameOfFunctionCalled == QLatin1String("QT_TRANSLATE_NOOP")) { QVector<int>::ConstIterator param = _functionParameters.constBegin(); QVector<int>::ConstIterator end = _functionParameters.constEnd(); if (param == end) diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h index 3404350ece..240f591f91 100644 --- a/src/qml/compiler/qqmltypecompiler_p.h +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -196,6 +196,7 @@ public: bool resolveEnumBindings(); private: + bool assignEnumToBinding(QmlIR::Binding *binding, const QString &enumName, int enumValue, bool isQtObject); bool tryQualifiedEnumAssignment(const QmlIR::Object *obj, const QQmlPropertyCache *propertyCache, const QQmlPropertyData *prop, QmlIR::Binding *binding); diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index eab5b7fd2d..d08d2aafa2 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -115,7 +115,7 @@ void Codegen::ScanFunctions::checkDirectivePrologue(SourceElements *ast) if (strLit->literalToken.length < 2) continue; QStringRef str = _sourceCode.midRef(strLit->literalToken.offset + 1, strLit->literalToken.length - 2); - if (str == QStringLiteral("use strict")) { + if (str == QLatin1String("use strict")) { _env->isStrict = true; } else { // TODO: give a warning. @@ -148,7 +148,7 @@ void Codegen::ScanFunctions::checkName(const QStringRef &name, const SourceLocat void Codegen::ScanFunctions::checkForArguments(AST::FormalParameterList *parameters) { while (parameters) { - if (parameters->name == QStringLiteral("arguments")) + if (parameters->name == QLatin1String("arguments")) _env->usesArgumentsObject = Environment::ArgumentsObjectNotUsed; parameters = parameters->next; } @@ -170,7 +170,7 @@ bool Codegen::ScanFunctions::visit(CallExpression *ast) { if (! _env->hasDirectEval) { if (IdentifierExpression *id = cast<IdentifierExpression *>(ast->base)) { - if (id->name == QStringLiteral("eval")) { + if (id->name == QLatin1String("eval")) { if (_env->usesArgumentsObject == Environment::ArgumentsObjectUnknown) _env->usesArgumentsObject = Environment::ArgumentsObjectUsed; _env->hasDirectEval = true; @@ -241,7 +241,7 @@ bool Codegen::ScanFunctions::visit(ExpressionStatement *ast) return false; } else { SourceLocation firstToken = ast->firstSourceLocation(); - if (_sourceCode.midRef(firstToken.offset, firstToken.length) == QStringLiteral("function")) { + if (_sourceCode.midRef(firstToken.offset, firstToken.length) == QLatin1String("function")) { _cg->throwSyntaxError(firstToken, QStringLiteral("unexpected token")); } } @@ -1441,7 +1441,7 @@ IR::Expr *Codegen::identifier(const QString &name, int line, int col) Q_ASSERT (index < e->members.size()); if (index != -1) { IR::ArgLocal *al = _block->LOCAL(index, scope); - if (name == QStringLiteral("arguments") || name == QStringLiteral("eval")) + if (name == QLatin1String("arguments") || name == QLatin1String("eval")) al->isArgumentsOrEval = true; return al; } diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp index 49e7d5c66e..0ae08160ab 100644 --- a/src/qml/compiler/qv4isel_p.cpp +++ b/src/qml/compiler/qv4isel_p.cpp @@ -95,7 +95,7 @@ void IRDecoder::visitMove(IR::Move *s) } } else if (s->target->asTemp() || s->target->asArgLocal()) { if (IR::Name *n = s->source->asName()) { - if (n->id && *n->id == QStringLiteral("this")) // TODO: `this' should be a builtin. + if (n->id && *n->id == QLatin1String("this")) // TODO: `this' should be a builtin. loadThisObject(s->target); else if (n->builtin == IR::Name::builtin_qml_context) loadQmlContext(s->target); diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp index c2b6fa477b..4c87b7557e 100644 --- a/src/qml/compiler/qv4jsir.cpp +++ b/src/qml/compiler/qv4jsir.cpp @@ -1145,7 +1145,7 @@ void IRPrinter::visitRegExp(RegExp *e) void IRPrinter::visitName(Name *e) { if (e->id) { - if (*e->id != QStringLiteral("this")) + if (*e->id != QLatin1String("this")) *out << '.'; *out << *e->id; } else { diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index 0ff3b52870..7881ab951a 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -570,7 +570,7 @@ class DominatorTree bucket[s].push_back(n); link(p, n); if (bucket.contains(p)) { - foreach (BasicBlockIndex v, bucket[p]) { + for (BasicBlockIndex v : bucket[p]) { BasicBlockIndex y = ancestorWithLowestSemi(v, worklist); BasicBlockIndex semi_v = d->semi[v]; if (d->semi[y] == semi_v) @@ -670,7 +670,7 @@ public: foreach (BasicBlock *y, function->basicBlock(node)->out) if (idom[y->index()] != node) S.insert(y); - foreach (BasicBlockIndex child, np.children) { + for (BasicBlockIndex child : np.children) { const BasicBlockSet &ws = DF[child]; for (BasicBlockSet::const_iterator it = ws.begin(), eit = ws.end(); it != eit; ++it) { BasicBlock *w = *it; @@ -1733,7 +1733,7 @@ void convertToSSA(IR::Function *function, const DominatorTree &df, DefUses &defU W.reserve(8); // Place phi functions: - foreach (const Temp &a, variables.allTemps()) { + for (const Temp &a : variables.allTemps()) { if (a.isInvalid()) continue; if (!variables.isNonLocal(a)) @@ -1791,7 +1791,7 @@ void cleanupPhis(DefUses &defUses) std::vector<Phi *> allPhis; allPhis.reserve(32); - foreach (const Temp *def, defUses.defs()) { + for (const Temp *def : defUses.defs()) { Stmt *defStmt = defUses.defStmt(*def); if (!defStmt) continue; @@ -1808,7 +1808,7 @@ void cleanupPhis(DefUses &defUses) toRemove |= collectedPhis; } - foreach (Phi *phi, allPhis) { + for (Phi *phi : allPhis) { if (!toRemove.at(phi->id())) continue; @@ -2070,7 +2070,7 @@ protected: return; // TODO: maybe we can distinguish between built-ins of which we know that they do not have // a side-effect. - if (e->builtin == Name::builtin_invalid || (e->id && *e->id != QStringLiteral("this"))) + if (e->builtin == Name::builtin_invalid || (e->id && *e->id != QLatin1String("this"))) markAsSideEffect(); } diff --git a/src/qml/debugger/qqmldebugconnector.cpp b/src/qml/debugger/qqmldebugconnector.cpp index f00d4b24f7..6edd28ea01 100644 --- a/src/qml/debugger/qqmldebugconnector.cpp +++ b/src/qml/debugger/qqmldebugconnector.cpp @@ -129,7 +129,7 @@ QQmlDebugConnector *QQmlDebugConnector::instance() if (!params->instance) { const QString serverConnector = QStringLiteral("QQmlDebugServer"); const QString nativeConnector = QStringLiteral("QQmlNativeDebugConnector"); - const bool isNative = params->arguments.startsWith(QStringLiteral("native")); + const bool isNative = params->arguments.startsWith(QLatin1String("native")); if (!params->pluginKey.isEmpty()) { if (params->pluginKey == serverConnector || params->pluginKey == nativeConnector) params->instance = loadQQmlDebugConnector(params->pluginKey); diff --git a/src/qml/doc/src/qmlfunctions.qdoc b/src/qml/doc/src/qmlfunctions.qdoc index 4203cca8b3..6f738752a7 100644 --- a/src/qml/doc/src/qmlfunctions.qdoc +++ b/src/qml/doc/src/qmlfunctions.qdoc @@ -30,8 +30,6 @@ \relates QQmlEngine Equivalent to \c Q_DECLARE_METATYPE(TYPE *) and \c Q_DECLARE_METATYPE(QQmlListProperty<TYPE>) - - #include <QtQml> to use this macro. */ /*! @@ -44,8 +42,6 @@ Current the only supported type info is \c QML_HAS_ATTACHED_PROPERTIES which declares that the \a Type supports \l {Attached Properties and Attached Signal Handlers} {attached properties}. - - #include <QtQml> to use this macro. */ /*! @@ -58,8 +54,6 @@ Any existing QQmlEngines must be deleted before calling this function. This function only affects the application global cache. Delete the QQmlEngine to clear all cached data relating to that engine. - - #include <QtQml> to use this method. */ @@ -93,10 +87,6 @@ "com.mycompany.qmlcomponents": \code - #include <QtQml> - - ... - qmlRegisterType<MySliderItem>("com.mycompany.qmlcomponents", 1, 0, "Slider"); \endcode @@ -151,8 +141,6 @@ Returns the QML type id. - #include <QtQml> to use this function. - \sa qmlRegisterTypeNotAvailable() */ @@ -167,8 +155,6 @@ Returns the QML type id. - #include <QtQml> to use this function. - \sa qmlRegisterType(), {Registering Extension Objects} */ @@ -190,8 +176,6 @@ Returns the QML type id. - #include <QtQml> to use this function. - \sa qmlRegisterUncreatableType() */ @@ -208,8 +192,6 @@ the \a parser provided. Returns the QML type id. - - #include <QtQml> to use this function. */ /*! @@ -244,8 +226,6 @@ Without this, a generic "Game is not a type" message would be given. - #include <QtQml> to use this function. - \sa qmlRegisterUncreatableType() */ @@ -258,8 +238,6 @@ system. Instances of this type cannot be created from the QML system. - #include <QtQml> to use this function. - Returns the QML type id. */ @@ -270,8 +248,6 @@ This template function registers the C++ type in the QML system under the name \a typeName. - #include <QtQml> to use this function. - Returns the QML type id. */ @@ -305,10 +281,7 @@ } // Second, register the singleton type provider with QML by calling this function in an initialization function. - #include <QtQml> - ... qmlRegisterSingletonType("Qt.example.qjsvalueApi", 1, 0, "MyApi", example_qjsvalue_singletontype_provider); - ... \endcode In order to use the registered singleton type in QML, you must import the singleton type. @@ -408,10 +381,7 @@ } // Third, register the singleton type provider with QML by calling this function in an initialization function. - #include <QtQml> - ... qmlRegisterSingletonType<SingletonTypeExample>("Qt.example.qobjectSingleton", 1, 0, "MyApi", example_qobject_singletontype_provider); - ... \endcode In order to use the registered singleton type in QML, you must import the singleton type. @@ -481,10 +451,7 @@ \code // Second, register the QML singleton type by calling this function in an initialization function. - #include <QtQml> - ... qmlRegisterSingletonType(QUrl("file:///absolute/path/SingletonType.qml"), "Qt.example.qobjectSingleton", 1, 0, "RegisteredSingleton"); - ... \endcode In order to use the registered singleton type in QML, you must import the singleton type. @@ -514,8 +481,6 @@ Normally QML files can be loaded as types directly from other QML files, or using a qmldir file. This function allows registration of files to types from C++ code, such as when the type mapping needs to be procedurally determined at startup. - #include <QtQml> to use this function. - Returns -1 if the registration was not successful. */ @@ -538,8 +503,6 @@ uri, major version combination will lead to a runtime error. Call this after you have registered all of your types with the engine. - #include <QtQml> to use this function. - Returns true if the module with \a uri as a \l{Identified Modules} {module identifier} and \a majVersion as a major version number was found and locked, otherwise returns false. The module must contain exported types diff --git a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc index c0b74c4fc6..04d769e4dc 100644 --- a/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc +++ b/src/qml/doc/src/qmllanguageref/syntax/objectattributes.qdoc @@ -448,8 +448,8 @@ right-hand-side of the property declaration must be a valid alias reference: [default] property alias <name>: <alias reference> \endcode -Unlike an ordinary property, an alias can only refer to a object, or the -property of a object, that is within the scope of the \l{QML Object Types} +Unlike an ordinary property, an alias can only refer to an object, or the +property of an object, that is within the scope of the \l{QML Object Types} {type} within which the alias is declared. It cannot contain arbitrary JavaScript expressions and it cannot refer to objects declared outside of the scope of its type. Also note the \e {alias reference} is not optional, diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp index f66e3e0875..a6e085a913 100644 --- a/src/qml/jit/qv4regalloc.cpp +++ b/src/qml/jit/qv4regalloc.cpp @@ -1398,7 +1398,7 @@ LifeTimeInterval *RegisterAllocator::cloneFixedInterval(int reg, bool isFP, cons void RegisterAllocator::prepareRanges() { LifeTimeInterval ltiWithCalls = createFixedInterval(int(_info->calls().size())); - foreach (int callPosition, _info->calls()) + for (int callPosition : _info->calls()) ltiWithCalls.addRange(callPosition, callPosition); const int regCount = _normalRegisters.size(); diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index c28df7d74a..317eb7a8a7 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -1250,7 +1250,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int return ld->d()->locale; if (const QV4::DateObject *d = value.as<DateObject>()) return d->toQDateTime(); - if (const QV4::ArrayBuffer *d = value.as<ArrayBuffer>()) + if (const ArrayBuffer *d = value.as<ArrayBuffer>()) return d->asByteArray(); // NOTE: since we convert QTime to JS Date, round trip will change the variant type (to QDateTime)! @@ -1378,6 +1378,8 @@ QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant) return QV4::Encode(*reinterpret_cast<const double*>(ptr)); case QMetaType::QString: return newString(*reinterpret_cast<const QString*>(ptr))->asReturnedValue(); + case QMetaType::QByteArray: + return newArrayBuffer(*reinterpret_cast<const QByteArray*>(ptr))->asReturnedValue(); case QMetaType::Float: return QV4::Encode(*reinterpret_cast<const float*>(ptr)); case QMetaType::Short: @@ -1554,6 +1556,8 @@ QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data) return QV4::Encode(*reinterpret_cast<const double*>(data)); case QMetaType::QString: return newString(*reinterpret_cast<const QString*>(data))->asReturnedValue(); + case QMetaType::QByteArray: + return newArrayBuffer(*reinterpret_cast<const QByteArray*>(data))->asReturnedValue(); case QMetaType::Float: return QV4::Encode(*reinterpret_cast<const float*>(data)); case QMetaType::Short: @@ -1646,6 +1650,12 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data) else *reinterpret_cast<QString*>(data) = value->toQString(); return true; + case QMetaType::QByteArray: + if (const ArrayBuffer *ab = value->as<ArrayBuffer>()) + *reinterpret_cast<QByteArray*>(data) = ab->asByteArray(); + else + *reinterpret_cast<QByteArray*>(data) = QByteArray(); + return true; case QMetaType::Float: *reinterpret_cast<float*>(data) = value->toNumber(); return true; diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp index 29f83da522..b3462fe9b1 100644 --- a/src/qml/jsruntime/qv4include.cpp +++ b/src/qml/jsruntime/qv4include.cpp @@ -41,8 +41,10 @@ #include "qv4scopedvalue_p.h" #include <QtQml/qjsengine.h> +#ifndef QT_NO_NETWORK #include <QtNetwork/qnetworkrequest.h> #include <QtNetwork/qnetworkreply.h> +#endif #include <QtCore/qfile.h> #include <QtQml/qqmlfile.h> @@ -57,7 +59,10 @@ QT_BEGIN_NAMESPACE QV4Include::QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, QV4::QmlContext *qmlContext, const QV4::Value &callback) - : v4(engine), m_network(0), m_reply(0), m_url(url), m_redirectCount(0) + : v4(engine), m_url(url) +#ifndef QT_NO_NETWORK + , m_redirectCount(0), m_network(0) , m_reply(0) +#endif { if (qmlContext) m_qmlContext.set(engine, *qmlContext); @@ -66,6 +71,7 @@ QV4Include::QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, m_resultObject.set(v4, resultValue(v4)); +#ifndef QT_NO_NETWORK m_network = engine->v8Engine->networkAccessManager(); QNetworkRequest request; @@ -73,11 +79,17 @@ QV4Include::QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, m_reply = m_network->get(request); QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished())); +#else + finished(); +#endif } QV4Include::~QV4Include() { - delete m_reply; m_reply = 0; +#ifndef QT_NO_NETWORK + delete m_reply; + m_reply = 0; +#endif } QV4::ReturnedValue QV4Include::resultValue(QV4::ExecutionEngine *v4, Status status) @@ -123,6 +135,7 @@ QV4::ReturnedValue QV4Include::result() #define INCLUDE_MAXIMUM_REDIRECT_RECURSION 15 void QV4Include::finished() { +#ifndef QT_NO_NETWORK m_redirectCount++; if (m_redirectCount < INCLUDE_MAXIMUM_REDIRECT_RECURSION) { @@ -166,6 +179,12 @@ void QV4Include::finished() } else { resultObj->put(status, QV4::ScopedValue(scope, QV4::Primitive::fromInt32(NetworkError))); } +#else + QV4::Scope scope(v4); + QV4::ScopedObject resultObj(scope, m_resultObject.value()); + QV4::ScopedString status(scope, v4->newString(QStringLiteral("status"))); + resultObj->put(status, QV4::ScopedValue(scope, QV4::Primitive::fromInt32(NetworkError))); +#endif //QT_NO_NETWORK QV4::ScopedValue cb(scope, m_callbackFunction.value()); callback(cb, resultObj); @@ -188,14 +207,15 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx) if (!context || !context->isJSContext) V4THROW_ERROR("Qt.include(): Can only be called from JavaScript files"); - QUrl url(scope.engine->resolvedUrl(ctx->args()[0].toQStringNoThrow())); - if (scope.engine->qmlEngine() && scope.engine->qmlEngine()->urlInterceptor()) - url = scope.engine->qmlEngine()->urlInterceptor()->intercept(url, QQmlAbstractUrlInterceptor::JavaScriptFile); - QV4::ScopedValue callbackFunction(scope, QV4::Primitive::undefinedValue()); if (ctx->argc() >= 2 && ctx->args()[1].as<QV4::FunctionObject>()) callbackFunction = ctx->args()[1]; +#ifndef QT_NO_NETWORK + QUrl url(scope.engine->resolvedUrl(ctx->args()[0].toQStringNoThrow())); + if (scope.engine->qmlEngine() && scope.engine->qmlEngine()->urlInterceptor()) + url = scope.engine->qmlEngine()->urlInterceptor()->intercept(url, QQmlAbstractUrlInterceptor::JavaScriptFile); + QString localFile = QQmlFile::urlToLocalFileOrQrc(url); QV4::ScopedValue result(scope); @@ -243,6 +263,12 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx) } return result->asReturnedValue(); +#else + QV4::ScopedValue result(scope); + result = resultValue(scope.engine, NetworkError); + callback(callbackFunction, result); + return result->asReturnedValue(); +#endif } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4include_p.h b/src/qml/jsruntime/qv4include_p.h index 257dc05e65..1750e6a7e1 100644 --- a/src/qml/jsruntime/qv4include_p.h +++ b/src/qml/jsruntime/qv4include_p.h @@ -62,7 +62,9 @@ QT_BEGIN_NAMESPACE class QQmlEngine; +#ifndef QT_NO_NETWORK class QNetworkAccessManager; +#endif class QNetworkReply; class QV4Include : public QObject { @@ -90,15 +92,16 @@ private: static void callback(const QV4::Value &callback, const QV4::Value &status); QV4::ExecutionEngine *v4; - QNetworkAccessManager *m_network; - QPointer<QNetworkReply> m_reply; - QUrl m_url; + +#ifndef QT_NO_NETWORK int m_redirectCount; + QNetworkAccessManager *m_network; + QPointer<QNetworkReply> m_reply; +#endif QV4::PersistentValue m_callbackFunction; QV4::PersistentValue m_resultObject; - QV4::PersistentValue m_qmlContext; }; diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp index f264ec028e..8c5e7d8be1 100644 --- a/src/qml/jsruntime/qv4mathobject.cpp +++ b/src/qml/jsruntime/qv4mathobject.cpp @@ -51,8 +51,6 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(MathObject); -static const double qt_PI = 2.0 * ::asin(1.0); - Heap::MathObject::MathObject() { Scope scope(internalClass->engine); diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 8aae4dff1e..596a97a444 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -54,6 +54,7 @@ #include <private/qqmlbuiltinfunctions_p.h> #include <private/qv8engine_p.h> +#include <private/qv4arraybuffer_p.h> #include <private/qv4functionobject_p.h> #include <private/qv4runtime_p.h> #include <private/qv4variantobject_p.h> @@ -336,6 +337,8 @@ ReturnedValue QObjectWrapper::getProperty(ExecutionEngine *engine, QObject *obje } else if (property->isV4Function()) { Scope scope(engine); ScopedContext global(scope, engine->qmlContext()); + if (!global) + global = engine->rootContext(); return QV4::QObjectMethod::create(global, object, property->coreIndex); } else if (property->isSignalHandler()) { QmlSignalHandler::initProto(engine); @@ -1099,6 +1102,7 @@ private: // Pointers to allocData union { QString *qstringPtr; + QByteArray *qbyteArrayPtr; QVariant *qvariantPtr; QList<QObject *> *qlistPtr; QJSValue *qjsValuePtr; @@ -1220,6 +1224,13 @@ static int MatchScore(const QV4::Value &actual, int conversionType) default: return 10; } + } else if (actual.as<ArrayBuffer>()) { + switch (conversionType) { + case QMetaType::QByteArray: + return 0; + default: + return 10; + } } else if (actual.as<ArrayObject>()) { switch (conversionType) { case QMetaType::QJsonArray: @@ -1476,6 +1487,8 @@ void CallArgument::cleanup() { if (type == QMetaType::QString) { qstringPtr->~QString(); + } else if (type == QMetaType::QByteArray) { + qbyteArrayPtr->~QByteArray(); } else if (type == -1 || type == QMetaType::QVariant) { qvariantPtr->~QVariant(); } else if (type == qMetaTypeId<QJSValue>()) { @@ -1578,6 +1591,12 @@ void CallArgument::fromValue(int callType, QV4::ExecutionEngine *engine, const Q else qstringPtr = new (&allocData) QString(value.toQStringNoThrow()); type = callType; + } else if (callType == QMetaType::QByteArray) { + if (const ArrayBuffer *ab = value.as<ArrayBuffer>()) + qbyteArrayPtr = new (&allocData) QByteArray(ab->asByteArray()); + else + qbyteArrayPtr = new (&allocData) QByteArray(); + type = callType; } else if (callType == QMetaType::QObjectStar) { qobjectPtr = 0; if (const QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>()) @@ -1675,6 +1694,8 @@ QV4::ReturnedValue CallArgument::toValue(QV4::ExecutionEngine *engine) return QV4::Encode(floatValue); } else if (type == QMetaType::QString) { return QV4::Encode(engine->newString(*qstringPtr)); + } else if (type == QMetaType::QByteArray) { + return QV4::Encode(engine->newArrayBuffer(*qbyteArrayPtr)); } else if (type == QMetaType::QObjectStar) { QObject *object = qobjectPtr; if (object) diff --git a/src/qml/qml.pro b/src/qml/qml.pro index d75262bf0b..b119aa12af 100644 --- a/src/qml/qml.pro +++ b/src/qml/qml.pro @@ -1,5 +1,11 @@ TARGET = QtQml -QT = core-private network +QT = core-private + +no_network { + DEFINES += QT_NO_NETWORK +} else { + QT += network +} DEFINES += QT_NO_URL_CAST_FROM_STRING QT_NO_INTEGER_EVENT_COORDINATES @@ -11,9 +17,6 @@ solaris-cc*:QMAKE_CXXFLAGS_RELEASE -= -O2 # Ensure this gcc optimization is switched off for mips platforms to avoid trouble with JIT. gcc:isEqual(QT_ARCH, "mips"): QMAKE_CXXFLAGS += -fno-reorder-blocks -MODULE_PLUGIN_TYPES = \ - qmltooling - exists("qqml_enable_gcov") { QMAKE_CXXFLAGS = -fprofile-arcs -ftest-coverage -fno-elide-constructors LIBS_PRIVATE += -lgcov @@ -29,8 +32,6 @@ greaterThan(QT_CLANG_MAJOR_VERSION, 3)|greaterThan(QT_CLANG_MINOR_VERSION, 3)| \ if(equals(QT_APPLE_CLANG_MAJOR_VERSION, 5):greaterThan(QT_APPLE_CLANG_MINOR_VERSION, 0)): \ WERROR += -Wno-error=unused-const-variable -load(qt_module) - HEADERS += qtqmlglobal.h \ qtqmlglobal_p.h @@ -46,3 +47,7 @@ include(qml/qml.pri) include(debugger/debugger.pri) include(animations/animations.pri) include(types/types.pri) + +MODULE_PLUGIN_TYPES = \ + qmltooling +load(qt_module) diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index b8bd0f7f1d..fbd2d13e40 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -378,6 +378,13 @@ QQmlComponent::~QQmlComponent() if (d->state.completePending) { qWarning("QQmlComponent: Component destroyed while completion pending"); + + if (isError()) { + qWarning() << "This may have been caused by one of the following errors:"; + foreach (const QQmlError &error, d->state.errors) + qWarning().nospace().noquote() << QLatin1String(" ") << error; + } + d->completeCreate(); } diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 0e99e4ca89..a5c920d28a 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -53,7 +53,6 @@ #include "qqmlscriptstring.h" #include "qqmlglobal_p.h" #include "qqmlcomponent_p.h" -#include "qqmlnetworkaccessmanagerfactory.h" #include "qqmldirparser_p.h" #include "qqmlextensioninterface.h" #include "qqmllist_p.h" @@ -63,25 +62,25 @@ #include "qqmlincubator.h" #include "qqmlabstracturlinterceptor.h" #include <private/qqmlboundsignal_p.h> - #include <QtCore/qstandardpaths.h> #include <QtCore/qsettings.h> - #include <QtCore/qmetaobject.h> -#include <QNetworkAccessManager> #include <QDebug> #include <QtCore/qcoreapplication.h> #include <QtCore/qdir.h> #include <QtCore/qmutex.h> #include <QtCore/qthread.h> #include <private/qthread_p.h> + +#ifndef QT_NO_NETWORK +#include "qqmlnetworkaccessmanagerfactory.h" +#include <QNetworkAccessManager> #include <QtNetwork/qnetworkconfigmanager.h> +#endif #include <private/qobject_p.h> #include <private/qmetaobject_p.h> - #include <private/qqmllocale_p.h> - #include <private/qqmlbind_p.h> #include <private/qqmlconnections_p.h> #include <private/qqmltimer_p.h> @@ -493,6 +492,10 @@ The following functions are also on the Qt object. from right to left. \endlist \row + \li \c application.font + \li This read-only property holds the default application font as + returned by \l QGuiApplication::font(). + \row \li \c application.arguments \li This is a string list of the arguments the executable was invoked with. \row @@ -531,6 +534,7 @@ The following functions are also on the Qt object. \li application.active \li application.state \li application.layoutDirection + \li application.font \endlist */ @@ -605,9 +609,11 @@ QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e) cleanup(0), erroredBindings(0), inProgressCreations(0), workerScriptEngine(0), activeObjectCreator(0), - networkAccessManager(0), networkAccessManagerFactory(0), urlInterceptor(0), - scarceResourcesRefCount(0), typeLoader(e), importDatabase(e), uniqueId(1), - incubatorCount(0), incubationController(0) +#ifndef QT_NO_NETWORK + networkAccessManager(0), networkAccessManagerFactory(0), +#endif + urlInterceptor(0), scarceResourcesRefCount(0), importDatabase(e), typeLoader(e), + uniqueId(1), incubatorCount(0), incubationController(0) { } @@ -1066,7 +1072,17 @@ QQmlAbstractUrlInterceptor *QQmlEngine::urlInterceptor() const return d->urlInterceptor; } +void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index) +{ + if (activeObjectCreator) { + activeObjectCreator->finalizeCallbacks()->append(qMakePair(QPointer<QObject>(obj), index)); + } else { + void *args[] = { 0 }; + QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, args); + } +} +#ifndef QT_NO_NETWORK /*! Sets the \a factory to use for creating QNetworkAccessManager(s). @@ -1095,16 +1111,6 @@ QQmlNetworkAccessManagerFactory *QQmlEngine::networkAccessManagerFactory() const return d->networkAccessManagerFactory; } -void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index) -{ - if (activeObjectCreator) { - activeObjectCreator->finalizeCallbacks()->append(qMakePair(QPointer<QObject>(obj), index)); - } else { - void *args[] = { 0 }; - QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, args); - } -} - QNetworkAccessManager *QQmlEnginePrivate::createNetworkAccessManager(QObject *parent) const { QMutexLocker locker(&networkAccessManagerMutex); @@ -1143,6 +1149,7 @@ QNetworkAccessManager *QQmlEngine::networkAccessManager() const Q_D(const QQmlEngine); return d->getNetworkAccessManager(); } +#endif // QT_NO_NETWORK /*! diff --git a/src/qml/qml/qqmlengine.h b/src/qml/qml/qqmlengine.h index eee0587531..28bd66047e 100644 --- a/src/qml/qml/qqmlengine.h +++ b/src/qml/qml/qqmlengine.h @@ -44,6 +44,7 @@ #include <QtCore/qobject.h> #include <QtCore/qmap.h> #include <QtQml/qjsengine.h> +#include <QtQml/qqml.h> #include <QtQml/qqmlerror.h> #include <QtQml/qqmldebug.h> @@ -86,8 +87,10 @@ class QQmlExpression; class QQmlContext; class QQmlType; class QUrl; +#ifndef QT_NO_NETWORK class QNetworkAccessManager; class QQmlNetworkAccessManagerFactory; +#endif class QQmlIncubationController; class Q_QML_EXPORT QQmlEngine : public QJSEngine { @@ -114,10 +117,12 @@ public: bool importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors); +#ifndef QT_NO_NETWORK void setNetworkAccessManagerFactory(QQmlNetworkAccessManagerFactory *); QQmlNetworkAccessManagerFactory *networkAccessManagerFactory() const; QNetworkAccessManager *networkAccessManager() const; +#endif void setUrlInterceptor(QQmlAbstractUrlInterceptor* urlInterceptor); QQmlAbstractUrlInterceptor* urlInterceptor() const; diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index e56a3fc57f..7258ffe6ed 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -158,12 +158,12 @@ public: void registerFinalizeCallback(QObject *obj, int index); QQmlObjectCreator *activeObjectCreator; - +#ifndef QT_NO_NETWORK QNetworkAccessManager *createNetworkAccessManager(QObject *parent) const; QNetworkAccessManager *getNetworkAccessManager() const; mutable QNetworkAccessManager *networkAccessManager; mutable QQmlNetworkAccessManagerFactory *networkAccessManagerFactory; - +#endif QHash<QString,QSharedPointer<QQmlImageProviderBase> > imageProviders; QQmlAbstractUrlInterceptor* urlInterceptor; @@ -172,9 +172,8 @@ public: void referenceScarceResources(); void dereferenceScarceResources(); - QQmlTypeLoader typeLoader; QQmlImportDatabase importDatabase; - + QQmlTypeLoader typeLoader; QString offlineStoragePath; diff --git a/src/qml/qml/qqmlfile.cpp b/src/qml/qml/qqmlfile.cpp index ea4e9a1013..8ce0cc2026 100644 --- a/src/qml/qml/qqmlfile.cpp +++ b/src/qml/qml/qqmlfile.cpp @@ -67,6 +67,8 @@ static char assets_string[] = "assets"; #endif class QQmlFilePrivate; + +#ifndef QT_NO_NETWORK class QQmlFileNetworkReply : public QObject { Q_OBJECT @@ -97,6 +99,7 @@ private: int m_redirectCount; QNetworkReply *m_reply; }; +#endif class QQmlFilePrivate { @@ -114,10 +117,12 @@ public: Error error; QString errorString; - +#ifndef QT_NO_NETWORK QQmlFileNetworkReply *reply; +#endif }; +#ifndef QT_NO_NETWORK int QQmlFileNetworkReply::finishedIndex = -1; int QQmlFileNetworkReply::downloadProgressIndex = -1; int QQmlFileNetworkReply::networkFinishedIndex = -1; @@ -200,9 +205,13 @@ void QQmlFileNetworkReply::networkDownloadProgress(qint64 a, qint64 b) { emit downloadProgress(a, b); } +#endif // QT_NO_NETWORK QQmlFilePrivate::QQmlFilePrivate() -: error(None), reply(0) +: error(None) +#ifndef QT_NO_NETWORK +, reply(0) +#endif { } @@ -225,7 +234,9 @@ QQmlFile::QQmlFile(QQmlEngine *e, const QString &url) QQmlFile::~QQmlFile() { +#ifndef QT_NO_NETWORK delete d->reply; +#endif delete d; d = 0; } @@ -263,8 +274,10 @@ QQmlFile::Status QQmlFile::status() const { if (d->url.isEmpty() && d->urlString.isEmpty()) return Null; +#ifndef QT_NO_NETWORK else if (d->reply) return Loading; +#endif else if (d->error != QQmlFilePrivate::None) return Error; else @@ -321,7 +334,11 @@ void QQmlFile::load(QQmlEngine *engine, const QUrl &url) d->error = QQmlFilePrivate::NotFound; } } else { +#ifndef QT_NO_NETWORK d->reply = new QQmlFileNetworkReply(engine, d, url); +#else + d->error = QQmlFilePrivate::NotFound; +#endif } } @@ -348,10 +365,14 @@ void QQmlFile::load(QQmlEngine *engine, const QString &url) d->error = QQmlFilePrivate::NotFound; } } else { +#ifndef QT_NO_NETWORK QUrl qurl(url); d->url = qurl; d->urlString = QString(); d->reply = new QQmlFileNetworkReply(engine, d, qurl); +#else + d->error = QQmlFilePrivate::NotFound; +#endif } } @@ -368,6 +389,7 @@ void QQmlFile::clear(QObject *) clear(); } +#ifndef QT_NO_NETWORK bool QQmlFile::connectFinished(QObject *object, const char *method) { if (!d || !d->reply) { @@ -411,6 +433,7 @@ bool QQmlFile::connectDownloadProgress(QObject *object, int method) return QMetaObject::connect(d->reply, QQmlFileNetworkReply::downloadProgressIndex, object, method); } +#endif /*! Returns true if QQmlFile will open \a url synchronously. diff --git a/src/qml/qml/qqmlfile.h b/src/qml/qml/qqmlfile.h index b0910cc0f4..3dd683a2cd 100644 --- a/src/qml/qml/qqmlfile.h +++ b/src/qml/qml/qqmlfile.h @@ -80,10 +80,12 @@ public: void clear(); void clear(QObject *); +#ifndef QT_NO_NETWORK bool connectFinished(QObject *, const char *); bool connectFinished(QObject *, int); bool connectDownloadProgress(QObject *, const char *); bool connectDownloadProgress(QObject *, int); +#endif static bool isSynchronous(const QString &url); static bool isSynchronous(const QUrl &url); diff --git a/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp b/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp index f9fea0279e..c94db8e168 100644 --- a/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp +++ b/src/qml/qml/qqmlnetworkaccessmanagerfactory.cpp @@ -41,6 +41,8 @@ QT_BEGIN_NAMESPACE +#ifndef QT_NO_NETWORK + /*! \class QQmlNetworkAccessManagerFactory \since 5.0 @@ -101,4 +103,6 @@ QQmlNetworkAccessManagerFactory::~QQmlNetworkAccessManagerFactory() implementation of this method is reentrant. */ +#endif //QT_NO_NETWORK + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlnetworkaccessmanagerfactory.h b/src/qml/qml/qqmlnetworkaccessmanagerfactory.h index 8e3b94fad3..ba3561b9f4 100644 --- a/src/qml/qml/qqmlnetworkaccessmanagerfactory.h +++ b/src/qml/qml/qqmlnetworkaccessmanagerfactory.h @@ -45,6 +45,7 @@ QT_BEGIN_NAMESPACE +#ifndef QT_NO_NETWORK class QNetworkAccessManager; class Q_QML_EXPORT QQmlNetworkAccessManagerFactory @@ -55,6 +56,8 @@ public: }; +#endif //QT_NO_NETWORK + QT_END_NAMESPACE #endif // QQMLNETWORKACCESSMANAGERFACTORY_H diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index b516cc7d89..1a7896bde8 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -640,7 +640,7 @@ void QQmlObjectCreator::setupBindings(const QBitArray &bindingsToSkip) if (_compiledObject->idIndex) { const QQmlPropertyData *idProperty = propertyData.last(); - Q_ASSERT(!idProperty || !idProperty->isValid() || idProperty->name(_qobject) == QStringLiteral("id")); + Q_ASSERT(!idProperty || !idProperty->isValid() || idProperty->name(_qobject) == QLatin1String("id")); if (idProperty && idProperty->isValid() && idProperty->isWritable() && idProperty->propType == QMetaType::QString) { QV4::CompiledData::Binding idBinding; idBinding.propertyNameIndex = 0; // Not used diff --git a/src/qml/qml/qqmlscriptstring.cpp b/src/qml/qml/qqmlscriptstring.cpp index b027f043ec..3230e69b6d 100644 --- a/src/qml/qml/qqmlscriptstring.cpp +++ b/src/qml/qml/qqmlscriptstring.cpp @@ -135,10 +135,10 @@ bool QQmlScriptString::operator==(const QQmlScriptString &other) const if (d->isStringLiteral || other.d->isStringLiteral) return d->isStringLiteral && other.d->isStringLiteral && d->script == other.d->script; - if (d->script == QStringLiteral("true") || - d->script == QStringLiteral("false") || - d->script == QStringLiteral("undefined") || - d->script == QStringLiteral("null")) + if (d->script == QLatin1String("true") || + d->script == QLatin1String("false") || + d->script == QLatin1String("undefined") || + d->script == QLatin1String("null")) return d->script == other.d->script; return d->context == other.d->context && @@ -172,7 +172,7 @@ Returns whether the content of the QQmlScriptString is the \c undefined literal. */ bool QQmlScriptString::isUndefinedLiteral() const { - return d->script == QStringLiteral("undefined"); + return d->script == QLatin1String("undefined"); } /*! @@ -180,7 +180,7 @@ Returns whether the content of the QQmlScriptString is the \c null literal. */ bool QQmlScriptString::isNullLiteral() const { - return d->script == QStringLiteral("null"); + return d->script == QLatin1String("null"); } /*! @@ -211,8 +211,8 @@ sets \a ok to true. Otherwise returns false and sets \a ok to false. */ bool QQmlScriptString::booleanLiteral(bool *ok) const { - bool isTrue = d->script == QStringLiteral("true"); - bool isFalse = !isTrue && d->script == QStringLiteral("false"); + bool isTrue = d->script == QLatin1String("true"); + bool isFalse = !isTrue && d->script == QLatin1String("false"); if (ok) *ok = isTrue || isFalse; return isTrue ? true : false; diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 52a7562b58..15e8d62efc 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -112,6 +112,7 @@ namespace { }; } +#ifndef QT_NO_NETWORK // This is a lame object that we need to ensure that slots connected to // QNetworkReply get called in the correct thread (the loader thread). // As QQmlTypeLoader lives in the main thread, and we can't use @@ -131,6 +132,7 @@ public slots: private: QQmlTypeLoader *l; }; +#endif // QT_NO_NETWORK class QQmlTypeLoaderThread : public QQmlThread { @@ -138,9 +140,10 @@ class QQmlTypeLoaderThread : public QQmlThread public: QQmlTypeLoaderThread(QQmlTypeLoader *loader); +#ifndef QT_NO_NETWORK QNetworkAccessManager *networkAccessManager() const; QQmlTypeLoaderNetworkReplyProxy *networkReplyProxy() const; - +#endif // QT_NO_NETWORK void load(QQmlDataBlob *b); void loadAsync(QQmlDataBlob *b); void loadWithStaticData(QQmlDataBlob *b, const QByteArray &); @@ -163,11 +166,13 @@ private: void initializeEngineMain(QQmlExtensionInterface *iface, const char *uri); QQmlTypeLoader *m_loader; +#ifndef QT_NO_NETWORK mutable QNetworkAccessManager *m_networkAccessManager; mutable QQmlTypeLoaderNetworkReplyProxy *m_networkReplyProxy; +#endif // QT_NO_NETWORK }; - +#ifndef QT_NO_NETWORK QQmlTypeLoaderNetworkReplyProxy::QQmlTypeLoaderNetworkReplyProxy(QQmlTypeLoader *l) : l(l) { @@ -196,7 +201,7 @@ void QQmlTypeLoaderNetworkReplyProxy::manualFinished(QNetworkReply *reply) l->networkReplyProgress(reply, replySize, replySize); l->networkReplyFinished(reply); } - +#endif // QT_NO_NETWORK /*! \class QQmlDataBlob @@ -480,6 +485,7 @@ void QQmlDataBlob::done() { } +#ifndef QT_NO_NETWORK /*! Invoked if there is a network error while fetching this blob. @@ -532,6 +538,7 @@ void QQmlDataBlob::networkError(QNetworkReply::NetworkError networkError) setError(error); } +#endif // QT_NO_NETWORK /*! Called if \a blob, which was previously waited for, has an error. @@ -730,12 +737,16 @@ void QQmlDataBlob::ThreadData::setProgress(quint8 v) } QQmlTypeLoaderThread::QQmlTypeLoaderThread(QQmlTypeLoader *loader) -: m_loader(loader), m_networkAccessManager(0), m_networkReplyProxy(0) +: m_loader(loader) +#ifndef QT_NO_NETWORK +, m_networkAccessManager(0), m_networkReplyProxy(0) +#endif // QT_NO_NETWORK { // Do that after initializing all the members. startup(); } +#ifndef QT_NO_NETWORK QNetworkAccessManager *QQmlTypeLoaderThread::networkAccessManager() const { Q_ASSERT(isThisThread()); @@ -753,6 +764,7 @@ QQmlTypeLoaderNetworkReplyProxy *QQmlTypeLoaderThread::networkReplyProxy() const Q_ASSERT(m_networkReplyProxy); // Must call networkAccessManager() first return m_networkReplyProxy; } +#endif // QT_NO_NETWORK void QQmlTypeLoaderThread::load(QQmlDataBlob *b) { @@ -810,10 +822,12 @@ void QQmlTypeLoaderThread::initializeEngine(QQmlExtensionInterface *iface, void QQmlTypeLoaderThread::shutdownThread() { +#ifndef QT_NO_NETWORK delete m_networkAccessManager; m_networkAccessManager = 0; delete m_networkReplyProxy; m_networkReplyProxy = 0; +#endif // QT_NO_NETWORK } void QQmlTypeLoaderThread::loadThread(QQmlDataBlob *b) @@ -899,12 +913,14 @@ void QQmlTypeLoader::invalidate() m_thread = 0; } +#ifndef QT_NO_NETWORK // Need to delete the network replies after // the loader thread is shutdown as it could be // getting new replies while we clear them for (NetworkReplies::Iterator iter = m_networkReplies.begin(); iter != m_networkReplies.end(); ++iter) (*iter)->release(); m_networkReplies.clear(); +#endif // QT_NO_NETWORK } void QQmlTypeLoader::lock() @@ -1082,7 +1098,7 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob) setData(blob, &file); } else { - +#ifndef QT_NO_NETWORK QNetworkReply *reply = m_thread->networkAccessManager()->get(QNetworkRequest(blob->m_url)); QQmlTypeLoaderNetworkReplyProxy *nrp = m_thread->networkReplyProxy(); blob->addref(); @@ -1099,13 +1115,14 @@ void QQmlTypeLoader::loadThread(QQmlDataBlob *blob) #ifdef DATABLOB_DEBUG qWarning("QQmlDataBlob: requested %s", qPrintable(blob->url().toString())); -#endif - +#endif // DATABLOB_DEBUG +#endif // QT_NO_NETWORK } } #define DATALOADER_MAXIMUM_REDIRECT_RECURSION 16 +#ifndef QT_NO_NETWORK void QQmlTypeLoader::networkReplyFinished(QNetworkReply *reply) { Q_ASSERT(m_thread->isThisThread()); @@ -1161,6 +1178,7 @@ void QQmlTypeLoader::networkReplyProgress(QNetworkReply *reply, m_thread->callDownloadProgressChanged(blob, blob->m_data.progress()); } } +#endif // QT_NO_NETWORK /*! Return the QQmlEngine associated with this loader diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 01d223bbce..49a4ac716a 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -53,7 +53,9 @@ #include <QtCore/qobject.h> #include <QtCore/qatomic.h> +#ifndef QT_NO_NETWORK #include <QtNetwork/qnetworkreply.h> +#endif #include <QtQml/qqmlerror.h> #include <QtQml/qqmlengine.h> #include <QtQml/qqmlfile.h> @@ -156,7 +158,9 @@ protected: virtual void dataReceived(const Data &) = 0; virtual void initializeFromCachedUnit(const QQmlPrivate::CachedQmlUnit*) = 0; virtual void done(); +#ifndef QT_NO_NETWORK virtual void networkError(QNetworkReply::NetworkError); +#endif virtual void dependencyError(QQmlDataBlob *); virtual void dependencyComplete(QQmlDataBlob *); virtual void allDependenciesDone(); @@ -320,17 +324,21 @@ public: private: friend class QQmlDataBlob; friend class QQmlTypeLoaderThread; +#ifndef QT_NO_NETWORK friend class QQmlTypeLoaderNetworkReplyProxy; +#endif // QT_NO_NETWORK void shutdownThread(); void loadThread(QQmlDataBlob *); void loadWithStaticDataThread(QQmlDataBlob *, const QByteArray &); void loadWithCachedUnitThread(QQmlDataBlob *blob, const QQmlPrivate::CachedQmlUnit *unit); +#ifndef QT_NO_NETWORK void networkReplyFinished(QNetworkReply *); void networkReplyProgress(QNetworkReply *, qint64, qint64); typedef QHash<QNetworkReply *, QQmlDataBlob *> NetworkReplies; +#endif void setData(QQmlDataBlob *, const QByteArray &); void setData(QQmlDataBlob *, QQmlFile *); @@ -362,7 +370,9 @@ private: QQmlEngine *m_engine; QQmlTypeLoaderThread *m_thread; +#ifndef QT_NO_NETWORK NetworkReplies m_networkReplies; +#endif TypeCache m_typeCache; ScriptCache m_scriptCache; QmldirCache m_qmldirCache; diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 2f2c6cf7dc..33fe655368 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -125,6 +125,28 @@ ReturnedValue QmlTypeWrapper::create(QV4::ExecutionEngine *engine, QObject *o, Q return w.asReturnedValue(); } +static int enumForSingleton(String *name, QObject *qobjectSingleton) +{ + // ### Optimize + QByteArray enumName = name->toQString().toUtf8(); + const QMetaObject *metaObject = qobjectSingleton->metaObject(); + for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) { + QMetaEnum e = metaObject->enumerator(ii); + bool ok; + int value = e.keyToValue(enumName.constData(), &ok); + if (ok) + return value; + } + return -1; +} + +static ReturnedValue throwLowercaseEnumError(QV4::ExecutionEngine *v4, String *name, QQmlType *type) +{ + const QString message = + QStringLiteral("Cannot access enum value '%1' of '%2', enum values need to start with an uppercase letter.") + .arg(name->toQString()).arg(QLatin1String(type->typeName())); + return v4->throwTypeError(message); +} ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasProperty) { @@ -141,9 +163,9 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope QQmlContextData *context = v4->callingQmlContext(); QObject *object = w->d()->object; + QQmlType *type = w->d()->type; - if (w->d()->type) { - QQmlType *type = w->d()->type; + if (type) { // singleton types are handled differently to other types. if (type->isSingleton()) { @@ -153,24 +175,29 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope QObject *qobjectSingleton = siinfo->qobjectApi(e); if (qobjectSingleton) { + // check for enum value - if (name->startsWithUpper()) { - if (w->d()->mode == Heap::QmlTypeWrapper::IncludeEnums) { - // ### Optimize - QByteArray enumName = name->toQString().toUtf8(); - const QMetaObject *metaObject = qobjectSingleton->metaObject(); - for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) { - QMetaEnum e = metaObject->enumerator(ii); - bool ok; - int value = e.keyToValue(enumName.constData(), &ok); - if (ok) - return QV4::Primitive::fromInt32(value).asReturnedValue(); - } - } + const bool includeEnums = w->d()->mode == Heap::QmlTypeWrapper::IncludeEnums; + if (includeEnums && name->startsWithUpper()) { + const int value = enumForSingleton(name, qobjectSingleton); + if (value != -1) + return QV4::Primitive::fromInt32(value).asReturnedValue(); } // check for property. - return QV4::QObjectWrapper::getQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, hasProperty); + bool ok; + const ReturnedValue result = QV4::QObjectWrapper::getQmlProperty(v4, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, &ok); + if (hasProperty) + *hasProperty = ok; + + // Warn when attempting to access a lowercased enum value, singleton case + if (!ok && includeEnums && !name->startsWithUpper()) { + const int value = enumForSingleton(name, qobjectSingleton); + if (value != -1) + return throwLowercaseEnumError(v4, name, type); + } + + return result; } else if (!siinfo->scriptApi(e).isUndefined()) { // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable. QV4::ScopedObject o(scope, QJSValuePrivate::convertedToValue(v4, siinfo->scriptApi(e))); @@ -227,9 +254,20 @@ ReturnedValue QmlTypeWrapper::get(const Managed *m, String *name, bool *hasPrope Q_ASSERT(!"Unreachable"); } + bool ok = false; + const ReturnedValue result = Object::get(m, name, &ok); if (hasProperty) - *hasProperty = false; - return Object::get(m, name, hasProperty); + *hasProperty = ok; + + // Warn when attempting to access a lowercased enum value, non-singleton case + if (!ok && type && !type->isSingleton() && !name->startsWithUpper()) { + bool enumOk = false; + type->enumValue(QQmlEnginePrivate::get(v4->qmlEngine()), name, &enumOk); + if (enumOk) + return throwLowercaseEnumError(v4, name, type); + } + + return result; } diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index fe02c6633e..af94ec757c 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -70,7 +70,7 @@ using namespace QV4; -#ifndef QT_NO_XMLSTREAMREADER +#if !defined(QT_NO_XMLSTREAMREADER) && !defined(QT_NO_NETWORK) #define V4THROW_REFERENCE(string) { \ ScopedObject error(scope, ctx->engine()->newReferenceErrorObject(QStringLiteral(string))); \ @@ -2040,6 +2040,6 @@ void *qt_add_qmlxmlhttprequest(ExecutionEngine *v4) QT_END_NAMESPACE -#endif // QT_NO_XMLSTREAMREADER +#endif // QT_NO_XMLSTREAMREADER && QT_NO_NETWORK #include <qqmlxmlhttprequest.moc> diff --git a/src/qml/qml/qqmlxmlhttprequest_p.h b/src/qml/qml/qqmlxmlhttprequest_p.h index 7bbfb5243c..df30873915 100644 --- a/src/qml/qml/qqmlxmlhttprequest_p.h +++ b/src/qml/qml/qqmlxmlhttprequest_p.h @@ -55,7 +55,7 @@ #include <QtCore/qglobal.h> #include <private/qqmlglobal_p.h> -#ifndef QT_NO_XMLSTREAMREADER +#if !defined(QT_NO_XMLSTREAMREADER) && !defined(QT_NO_NETWORK) QT_BEGIN_NAMESPACE @@ -64,7 +64,7 @@ void qt_rem_qmlxmlhttprequest(QV4::ExecutionEngine *engine, void *); QT_END_NAMESPACE -#endif // QT_NO_XMLSTREAMREADER +#endif // QT_NO_XMLSTREAMREADER && QT_NO_NETWORK #endif // QQMLXMLHTTPREQUEST_P_H diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index d322088f61..89f128a0e7 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -159,18 +159,22 @@ QV8Engine::~QV8Engine() delete m_extensionData[ii]; m_extensionData.clear(); +#if !defined(QT_NO_XMLSTREAMREADER) && defined(QT_NO_NETWORK) qt_rem_qmlxmlhttprequest(m_v4Engine, m_xmlHttpRequestData); m_xmlHttpRequestData = 0; +#endif delete m_listModelData; m_listModelData = 0; delete m_v4Engine; } +#ifndef QT_NO_NETWORK QNetworkAccessManager *QV8Engine::networkAccessManager() { return QQmlEnginePrivate::get(m_engine)->getNetworkAccessManager(); } +#endif const QSet<QString> &QV8Engine::illegalNames() const { @@ -189,8 +193,10 @@ void QV8Engine::initializeGlobal() QQmlDateExtension::registerExtension(m_v4Engine); QQmlNumberExtension::registerExtension(m_v4Engine); +#if !defined(QT_NO_XMLSTREAMREADER) && !defined(QT_NO_NETWORK) qt_add_domexceptions(m_v4Engine); m_xmlHttpRequestData = qt_add_qmlxmlhttprequest(m_v4Engine); +#endif qt_add_sqlexceptions(m_v4Engine); diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h index 4ffd36ca34..9054c731db 100644 --- a/src/qml/qml/v8/qv8engine_p.h +++ b/src/qml/qml/v8/qv8engine_p.h @@ -194,10 +194,12 @@ public: void freezeObject(const QV4::Value &value); +#ifndef QT_NO_NETWORK // Return the network access manager for this engine. By default this returns the network // access manager of the QQmlEngine. It is overridden in the case of a threaded v8 // instance (like in WorkerScript). virtual QNetworkAccessManager *networkAccessManager(); +#endif // Return the list of illegal id names (the names of the properties on the global object) const QSet<QString> &illegalNames() const; diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp index e2063dee7d..ed9a8533c0 100644 --- a/src/qml/types/qqmlbind.cpp +++ b/src/qml/types/qqmlbind.cpp @@ -75,7 +75,7 @@ public: void QQmlBindPrivate::validate(QObject *binding) const { - if (!obj) + if (!obj || (when.isValid() && !when)) return; if (!prop.isValid()) { @@ -185,6 +185,8 @@ void QQmlBind::setWhen(bool v) return; d->when = v; + if (v && d->componentComplete) + d->validate(this); eval(); } diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp index e819e4ee7d..bc15b2fd9b 100644 --- a/src/qml/types/qquickworkerscript.cpp +++ b/src/qml/types/qquickworkerscript.cpp @@ -52,10 +52,12 @@ #include <QtCore/qwaitcondition.h> #include <QtCore/qfile.h> #include <QtCore/qdatetime.h> -#include <QtNetwork/qnetworkaccessmanager.h> #include <QtQml/qqmlinfo.h> #include <QtQml/qqmlfile.h> +#ifndef QT_NO_NETWORK +#include <QtNetwork/qnetworkaccessmanager.h> #include "qqmlnetworkaccessmanagerfactory.h" +#endif #include <private/qv8engine_p.h> #include <private/qv4serialize_p.h> @@ -141,7 +143,10 @@ public: ~WorkerEngine(); void init(); + +#ifndef QT_NO_NETWORK virtual QNetworkAccessManager *networkAccessManager(); +#endif QQuickWorkerScriptEnginePrivate *p; @@ -150,7 +155,9 @@ public: QV4::PersistentValue onmessage; private: QV4::PersistentValue createsend; +#ifndef QT_NO_NETWORK QNetworkAccessManager *accessManager; +#endif }; WorkerEngine *workerEngine; @@ -194,14 +201,19 @@ private: }; QQuickWorkerScriptEnginePrivate::WorkerEngine::WorkerEngine(QQuickWorkerScriptEnginePrivate *parent) -: QV8Engine(0), p(parent), accessManager(0) +: QV8Engine(0), p(parent) +#ifndef QT_NO_NETWORK +, accessManager(0) +#endif { m_v4Engine->v8Engine = this; } QQuickWorkerScriptEnginePrivate::WorkerEngine::~WorkerEngine() { +#ifndef QT_NO_NETWORK delete accessManager; +#endif } void QQuickWorkerScriptEnginePrivate::WorkerEngine::init() @@ -262,6 +274,7 @@ QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::WorkerEngine::sendFunction(i return v->asReturnedValue(); } +#ifndef QT_NO_NETWORK QNetworkAccessManager *QQuickWorkerScriptEnginePrivate::WorkerEngine::networkAccessManager() { if (!accessManager) { @@ -273,6 +286,7 @@ QNetworkAccessManager *QQuickWorkerScriptEnginePrivate::WorkerEngine::networkAcc } return accessManager; } +#endif QQuickWorkerScriptEnginePrivate::QQuickWorkerScriptEnginePrivate(QQmlEngine *engine) : workerEngine(0), qmlengine(engine), m_nextId(0) diff --git a/src/qmldevtools/qmldevtools.pro b/src/qmldevtools/qmldevtools.pro index 0e32dc51e2..acd5c9729b 100644 --- a/src/qmldevtools/qmldevtools.pro +++ b/src/qmldevtools/qmldevtools.pro @@ -13,10 +13,10 @@ intel_icc: WERROR += -ww2415 clang:if(greaterThan(QT_CLANG_MAJOR_VERSION, 3)|greaterThan(QT_CLANG_MINOR_VERSION, 3)): \ WERROR += -Wno-error=unused-const-variable -load(qt_module) - include(../3rdparty/masm/masm-defs.pri) include(../qml/parser/parser.pri) include(../qml/jsruntime/jsruntime.pri) include(../qml/compiler/compiler.pri) include(../qml/memory/memory.pri) + +load(qt_module) diff --git a/src/qmltest/qmltest.pro b/src/qmltest/qmltest.pro index 289a0584e0..42224e9751 100644 --- a/src/qmltest/qmltest.pro +++ b/src/qmltest/qmltest.pro @@ -13,8 +13,6 @@ qtHaveModule(widgets) { DEFINES += QT_QMLTEST_WITH_WIDGETS } -load(qt_module) - # Install qmltestcase.prf into the Qt mkspecs so that "CONFIG += qmltestcase" # can be used in customer applications to build against QtQuickTest. feature.path = $$[QT_INSTALL_DATA]/mkspecs/features @@ -33,3 +31,5 @@ HEADERS += \ $$PWD/qtestoptions_p.h DEFINES += QT_QML_DEBUG_NO_WARNING + +load(qt_module) diff --git a/src/qmltest/quicktest.cpp b/src/qmltest/quicktest.cpp index adee4330d3..9ba93a1241 100644 --- a/src/qmltest/quicktest.cpp +++ b/src/qmltest/quicktest.cpp @@ -296,7 +296,7 @@ int quick_test_main(int argc, char **argv, const char *name, const char *sourceD const QFileInfo testPathInfo(testPath); if (testPathInfo.isFile()) { - if (!testPath.endsWith(QStringLiteral(".qml"))) { + if (!testPath.endsWith(QLatin1String(".qml"))) { qWarning("'%s' does not have the suffix '.qml'.", qPrintable(testPath)); return 1; } diff --git a/src/quick/designer/qquickdesignersupportitems.cpp b/src/quick/designer/qquickdesignersupportitems.cpp index 278e62d4f6..544ca04754 100644 --- a/src/quick/designer/qquickdesignersupportitems.cpp +++ b/src/quick/designer/qquickdesignersupportitems.cpp @@ -175,19 +175,19 @@ static QQmlType *getQmlType(const QString &typeName, int majorNumber, int minorN static bool isCrashingType(QQmlType *type) { if (type) { - if (type->qmlTypeName() == QStringLiteral("QtMultimedia/MediaPlayer")) + if (type->qmlTypeName() == QLatin1String("QtMultimedia/MediaPlayer")) return true; - if (type->qmlTypeName() == QStringLiteral("QtMultimedia/Audio")) + if (type->qmlTypeName() == QLatin1String("QtMultimedia/Audio")) return true; - if (type->qmlTypeName() == QStringLiteral("QtQuick.Controls/MenuItem")) + if (type->qmlTypeName() == QLatin1String("QtQuick.Controls/MenuItem")) return true; - if (type->qmlTypeName() == QStringLiteral("QtQuick.Controls/Menu")) + if (type->qmlTypeName() == QLatin1String("QtQuick.Controls/Menu")) return true; - if (type->qmlTypeName() == QStringLiteral("QtQuick/Timer")) + if (type->qmlTypeName() == QLatin1String("QtQuick/Timer")) return true; } diff --git a/src/quick/doc/images/columnlayout.png b/src/quick/doc/images/columnlayout.png Binary files differnew file mode 100644 index 0000000000..f03eb7b996 --- /dev/null +++ b/src/quick/doc/images/columnlayout.png diff --git a/src/quick/doc/images/gridlayout.png b/src/quick/doc/images/gridlayout.png Binary files differnew file mode 100644 index 0000000000..493813c481 --- /dev/null +++ b/src/quick/doc/images/gridlayout.png diff --git a/src/quick/doc/images/qtquicklayouts-example-layouts.png b/src/quick/doc/images/qtquicklayouts-example-layouts.png Binary files differnew file mode 100644 index 0000000000..94619bae3f --- /dev/null +++ b/src/quick/doc/images/qtquicklayouts-example-layouts.png diff --git a/src/quick/doc/images/rowlayout-minimum.png b/src/quick/doc/images/rowlayout-minimum.png Binary files differnew file mode 100644 index 0000000000..5875325c54 --- /dev/null +++ b/src/quick/doc/images/rowlayout-minimum.png diff --git a/src/quick/doc/images/rowlayout.png b/src/quick/doc/images/rowlayout.png Binary files differnew file mode 100644 index 0000000000..519a62fddd --- /dev/null +++ b/src/quick/doc/images/rowlayout.png diff --git a/src/quick/doc/qtquick.qdocconf b/src/quick/doc/qtquick.qdocconf index 044c1696ff..4f141a733a 100644 --- a/src/quick/doc/qtquick.qdocconf +++ b/src/quick/doc/qtquick.qdocconf @@ -33,7 +33,7 @@ qhp.QtQuick.subprojects.examples.selectors = fake:example tagfile = ../../../doc/qtquick/qtquick.tags -depends += qtcore qtxmlpatterns qtqml qtgui qtlinguist qtquickcontrols qtquicklayouts qtdoc qtquickdialogs qtsensors qtwidgets qmake qtmultimedia qtgraphicaleffects +depends += qtcore qtxmlpatterns qtqml qtgui qtlinguist qtquickcontrols qtdoc qtquickdialogs qtsensors qtwidgets qmake qtmultimedia qtgraphicaleffects headerdirs += ..\ ../../quickwidgets diff --git a/src/quick/doc/snippets/qml/windowconstraints.qml b/src/quick/doc/snippets/qml/windowconstraints.qml new file mode 100644 index 0000000000..3f3534f494 --- /dev/null +++ b/src/quick/doc/snippets/qml/windowconstraints.qml @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtQuick.Layouts 1.2 +import QtQuick.Window 2.2 + +Window { + //! [binddefaultsize] + width: layout.implicitWidth + height: layout.implicitHeight + //! [binddefaultsize] + //! [bindconstraints] + minimumWidth: layout.Layout.minimumWidth + minimumHeight: layout.Layout.minimumHeight + maximumWidth: 1000 + maximumHeight: layout.Layout.maximumHeight + //! [bindconstraints] + + //! [rowlayout] + //! [anchoring] + RowLayout { + id: layout + anchors.fill: parent + //! [anchoring] + spacing: 6 + Rectangle { + color: 'azure' + Layout.fillWidth: true + Layout.minimumWidth: 50 + Layout.preferredWidth: 100 + Layout.maximumWidth: 300 + Layout.minimumHeight: 150 + Text { + anchors.centerIn: parent + text: parent.width + 'x' + parent.height + } + } + Rectangle { + color: 'plum' + Layout.fillWidth: true + Layout.minimumWidth: 100 + Layout.preferredWidth: 200 + Layout.preferredHeight: 100 + Text { + anchors.centerIn: parent + text: parent.width + 'x' + parent.height + } + } + } + //! [rowlayout] +} diff --git a/src/quick/doc/src/concepts/layouts/qtquicklayouts-index.qdoc b/src/quick/doc/src/concepts/layouts/qtquicklayouts-index.qdoc new file mode 100644 index 0000000000..0be66fad2c --- /dev/null +++ b/src/quick/doc/src/concepts/layouts/qtquicklayouts-index.qdoc @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page qtquicklayouts-index.html + \title Qt Quick Layouts + \brief A module with a set of QML elements that arrange QML items in a user interface. + + Qt Quick Layouts are a set of QML types used to arrange items in a user interface. In contrast + to \l{Item Positioners}{positioners}, Qt Quick Layouts can also resize their items. This makes + them well suited for resizable user interfaces. Since layouts are items they can consequently + be nested. + + The module is new in Qt 5.1 and requires \l{Qt Quick} 2.1. + + Visit the \l{Qt Quick Layouts Overview} page to get started. + + \section1 Layouts + + \annotatedlist layouts + + \section1 Related information + + \list + \li \l{Qt Quick} + \li \l{Qt Quick Layouts Overview} + \li \l{Qt Quick Layouts - Basic Example} + \li \l{Qt Quick Layouts QML Types}{Qt Quick Layouts QML Types} + \endlist +*/ diff --git a/src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc b/src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc new file mode 100644 index 0000000000..1b6e7dc539 --- /dev/null +++ b/src/quick/doc/src/concepts/layouts/qtquicklayouts-overview.qdoc @@ -0,0 +1,176 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page qtquicklayouts-overview.html + \title Qt Quick Layouts Overview + \brief A set of APIs for arranging QML items in a user interface. + + Qt Quick Layouts are items that are used to arrange items in a user interface. Since Qt Quick + Layouts also resize their items, they are well suited for resizable user interfaces. + + \section1 Getting started + + The QML types can be imported into your application using the following import statement in your \c {.qml} file. + + \code + import QtQuick.Layouts 1.2 + \endcode + + \section1 Key Features + + + Some of the key features are: + + \list + \li \l{Layout::alignment}{Alignment} of items can be specified with the + \l{Layout::alignment}{Layout.alignment} property + \li \l{Layout::fillWidth}{Resizable items} can be specified with the + \l{Layout::fillWidth}{Layout.fillWidth} and \l{Layout::fillHeight}{Layout.fillHeight} + properties. + \li \l{Size constraints} can be specified with + \l{Layout::minimumWidth}{Layout.minimumWidth}, + \l{Layout::preferredWidth}{Layout.preferredWidth}, and + \l{Layout::maximumWidth}{Layout.maximumWidth} properties ("Width" can be replaced + with "Height" for specifying similar constraints to the height). + \li \l{RowLayout::spacing}{Spacings} can be specified with \l{RowLayout::spacing}{spacing}, + \l{GridLayout::rowSpacing}{rowSpacing} or \l{GridLayout::columnSpacing}{columnSpacing} + \endlist + + In addition to the above features, GridLayout adds these features: + \list + \li \l{Layout::row}{Grid coordinates} can be specified with the \l{Layout::row}{Layout.row} and + \l{Layout::column}{Layout.column}. + \li \l{GridLayout::flow}{Automatic grid coordinates} used together with the + \l{GridLayout::flow}{flow}, \l{GridLayout::rows}{rows}, and + \l{GridLayout::columns}{columns} properties. + \li \l{Layout::columnSpan}{Spans} across rows or columns can be specified with the + \l{Layout::rowSpan}{Layout.rowSpan} and \l{Layout::columnSpan}{Layout.columnSpan} + properties. + \endlist + + + + \section1 Size Constraints + Since an item can be resized by its layout, the layout needs to know the + \l{Layout::minimumWidth}{minimum}, \l{Layout::preferredWidth}{preferred}, + and \l{Layout::maximumWidth}{maximum} sizes of all items where \l{Layout::fillWidth}{Layout.fillWidth} or + \l{Layout::fillHeight}{Layout.fillHeight} is set to \c true. + For instance, the following will produce a layout with two rectangles lying side-by-side that + stretches horizontally. The azure rectangle can be resized from 50x150 to 300x150, and the plum + rectangle can be resized from 100x100 to ∞x100. + + \snippet windowconstraints.qml rowlayout + + \image rowlayout-minimum.png "RowLayout at its minimum" + + Combining each item's constraints will give these implicit constraints to the layout element: + + \table + \header + \li + \li minimum + \li preferred + \li maximum + \row + \li implicit constraints (width) + \li 156 + \li 306 + \li ∞ (\c Number.POSITIVE_INFINITY) + \row + \li implicit constraints (heights) + \li 150 + \li 150 + \li 150 + \endtable + + Thus, the layout cannot be narrower than 156 or be taller or shorter than 150 without breaking + any of the constraints of its child items. + + \section2 Specifying Preferred Size + For each item, the effective preferred size may come from one of several candidate properties. + For determining the effective preferred size, it will query these candidate properties in the + following order, and use the first candidate with a valid width or height. + + \table + \header + \li Candidate properties + \li Description + \row + \li \l{Layout::preferredWidth}{Layout.preferredWidth} or + \l{Layout::preferredHeight}{Layout.preferredHeight} + \li These properties are supposed to be modified by the application if the default implicit + size does not give the optimal arrangement. + \row + \li \l{Item::implicitWidth}{implicitWidth} or \l{Item::implicitHeight}{implicitHeight} + \li These properties are supposed to be supplied by each item to give a meaningful ideal size, + for example the size needed to display all the contents of a \l Text type. + An implicit width or height of \c 0 is interpreted as invalid. + \row + \li \l{Item::width}{width} and \l{Item::height}{height} + \li If none of the above properties are valid, the layout will resort to the + \l{Item::width}{width} and \l{Item::height}{height} properties. + \endtable + + An item can specify \l{Layout::preferredWidth}{Layout.preferredWidth} without having to specify + \l{Layout::preferredHeight}{Layout.preferredHeight}. In this case, the effective preferred + height will be determined from the \l{Item::implicitHeight}{implicitHeight} (or ultimately + \l{Item::height}{height}). + + \note Resorting to \l{Item::width}{width} or \l{Item::height}{height} properties is only + provided as a final fallback. If you want to override the preferred size, it is recommended to + use \l{Layout::preferredWidth}{Layout.preferredWidth} or + \l{Layout::preferredHeight}{Layout.preferredHeight}. Relying on the \l{Item::width}{width} or + \l{Item::height}{height} properties for specifying the preferred size might give some + unexpected behavior. For instance, changing the \l{Item::width}{width} or + \l{Item::height}{height} properties won't trigger a layout rearrangement. Also, when the layout + is forced to do a full rebuild it might use the actual width and height, and not the width and + height specified in the QML file. + + + \section1 Connecting windows and layouts + You can just use normal anchoring concepts to ensure that the layout will follow the window + resizing. + + \snippet qml/windowconstraints.qml anchoring + + The size constraints of layouts can be used to ensure that the window cannot be resized beyond + the layout constraints. You can take the size constraints from the layout and set these + constraints on the minimumWidth, minimumHeight, maximumWidth, and maximumHeight of the Window + element. The following code ensures that the window cannot be resized beyond the constraints of + the layout: + + \snippet qml/windowconstraints.qml bindconstraints + + \note Since layout.Layout.maximumWidth is infinite in this case, we cannot bind that to the + maximumWidth property of Window, since that is an integer number. We therefore set a fixed + maximum width to 1000. + + Finally, you usually want the initial size of the window to be the layout's implicit size: + + \snippet qml/windowconstraints.qml binddefaultsize +*/ diff --git a/src/quick/doc/src/concepts/layouts/qtquicklayouts.qdoc b/src/quick/doc/src/concepts/layouts/qtquicklayouts.qdoc new file mode 100644 index 0000000000..8f390c83db --- /dev/null +++ b/src/quick/doc/src/concepts/layouts/qtquicklayouts.qdoc @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \qmlmodule QtQuick.Layouts 1.3 + \title Qt Quick Layouts QML Types + \ingroup qmlmodules + \brief Provides QML types for arranging QML items in a user interface. + + The \l{Qt Quick Layouts} module provides QML types for arranging + QML items in a user interface. + These QML types work in conjunction with \l{Qt Quick} and + \l{Qt Quick Controls}. + + The QML types can be imported into your application using the + following import statement in your .qml file. + + \code + import QtQuick.Layouts 1.3 + \endcode + +*/ diff --git a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc index dffcabbd5b..cb281a2d4a 100644 --- a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc +++ b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc @@ -102,7 +102,7 @@ has changed. If the QList changes, it is necessary to reset the model by calling QQmlContext::setContextProperty() again. -\section2 QAbstractItemModel +\section2 QAbstractItemModel subclass A model can be defined by subclassing QAbstractItemModel. This is the best approach if you have a more complex model that cannot be supported diff --git a/src/quick/doc/src/qtquick.qdoc b/src/quick/doc/src/qtquick.qdoc index 98a77a48d8..4bdd02241d 100644 --- a/src/quick/doc/src/qtquick.qdoc +++ b/src/quick/doc/src/qtquick.qdoc @@ -101,6 +101,7 @@ Additional Qt Quick information: containing a JavaScript interface for an SQLite database \li \l{Qt Quick Particles QML Types}{Particles} - provides a particle system for Qt Quick + \li \l{Qt Quick Layouts}{Layouts} - provides layouts for arranging Qt Quick items \li \l{Qt Quick Window QML Types}{Window} - contains types for creating top-level windows and accessing screen information \li \l{Qt Quick Dialogs}{Dialogs} - contains types for creating and diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index 2d991bb670..bacdfad557 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -223,13 +223,13 @@ static bool qSetFontSizeFromToken(QFont &font, const QString &fontSizeToken) const QString value = trimmedToken.left(trimmedToken.size() - 2); bool ok = false; int size = 0; - if (unitStr == QStringLiteral("px")) { + if (unitStr == QLatin1String("px")) { size = qParseFontSizeFromToken(value, ok); if (ok) { font.setPixelSize(size); return true; } - } else if (unitStr == QStringLiteral("pt")) { + } else if (unitStr == QLatin1String("pt")) { size = qParseFontSizeFromToken(value, ok); if (ok) { font.setPointSize(size); @@ -368,9 +368,9 @@ static QFont qt_font_from_string(const QString& fontString, const QFont ¤t // We know that font-size must be specified and it must be before font-family // (which could potentially have "px" or "pt" in its name), so extract it now. - int fontSizeEnd = fontString.indexOf(QStringLiteral("px")); + int fontSizeEnd = fontString.indexOf(QLatin1String("px")); if (fontSizeEnd == -1) - fontSizeEnd = fontString.indexOf(QStringLiteral("pt")); + fontSizeEnd = fontString.indexOf(QLatin1String("pt")); if (fontSizeEnd == -1) { qWarning().nospace() << "Context2D: Invalid font size unit in font string."; return currentFont; @@ -769,53 +769,53 @@ void qt_image_boxblur(QImage& image, int radius, bool quality) static QPainter::CompositionMode qt_composite_mode_from_string(const QString &compositeOperator) { - if (compositeOperator == QStringLiteral("source-over")) { + if (compositeOperator == QLatin1String("source-over")) { return QPainter::CompositionMode_SourceOver; - } else if (compositeOperator == QStringLiteral("source-out")) { + } else if (compositeOperator == QLatin1String("source-out")) { return QPainter::CompositionMode_SourceOut; - } else if (compositeOperator == QStringLiteral("source-in")) { + } else if (compositeOperator == QLatin1String("source-in")) { return QPainter::CompositionMode_SourceIn; - } else if (compositeOperator == QStringLiteral("source-atop")) { + } else if (compositeOperator == QLatin1String("source-atop")) { return QPainter::CompositionMode_SourceAtop; - } else if (compositeOperator == QStringLiteral("destination-atop")) { + } else if (compositeOperator == QLatin1String("destination-atop")) { return QPainter::CompositionMode_DestinationAtop; - } else if (compositeOperator == QStringLiteral("destination-in")) { + } else if (compositeOperator == QLatin1String("destination-in")) { return QPainter::CompositionMode_DestinationIn; - } else if (compositeOperator == QStringLiteral("destination-out")) { + } else if (compositeOperator == QLatin1String("destination-out")) { return QPainter::CompositionMode_DestinationOut; - } else if (compositeOperator == QStringLiteral("destination-over")) { + } else if (compositeOperator == QLatin1String("destination-over")) { return QPainter::CompositionMode_DestinationOver; - } else if (compositeOperator == QStringLiteral("lighter")) { + } else if (compositeOperator == QLatin1String("lighter")) { return QPainter::CompositionMode_Lighten; - } else if (compositeOperator == QStringLiteral("copy")) { + } else if (compositeOperator == QLatin1String("copy")) { return QPainter::CompositionMode_Source; - } else if (compositeOperator == QStringLiteral("xor")) { + } else if (compositeOperator == QLatin1String("xor")) { return QPainter::CompositionMode_Xor; - } else if (compositeOperator == QStringLiteral("qt-clear")) { + } else if (compositeOperator == QLatin1String("qt-clear")) { return QPainter::CompositionMode_Clear; - } else if (compositeOperator == QStringLiteral("qt-destination")) { + } else if (compositeOperator == QLatin1String("qt-destination")) { return QPainter::CompositionMode_Destination; - } else if (compositeOperator == QStringLiteral("qt-multiply")) { + } else if (compositeOperator == QLatin1String("qt-multiply")) { return QPainter::CompositionMode_Multiply; - } else if (compositeOperator == QStringLiteral("qt-screen")) { + } else if (compositeOperator == QLatin1String("qt-screen")) { return QPainter::CompositionMode_Screen; - } else if (compositeOperator == QStringLiteral("qt-overlay")) { + } else if (compositeOperator == QLatin1String("qt-overlay")) { return QPainter::CompositionMode_Overlay; - } else if (compositeOperator == QStringLiteral("qt-darken")) { + } else if (compositeOperator == QLatin1String("qt-darken")) { return QPainter::CompositionMode_Darken; - } else if (compositeOperator == QStringLiteral("qt-lighten")) { + } else if (compositeOperator == QLatin1String("qt-lighten")) { return QPainter::CompositionMode_Lighten; - } else if (compositeOperator == QStringLiteral("qt-color-dodge")) { + } else if (compositeOperator == QLatin1String("qt-color-dodge")) { return QPainter::CompositionMode_ColorDodge; - } else if (compositeOperator == QStringLiteral("qt-color-burn")) { + } else if (compositeOperator == QLatin1String("qt-color-burn")) { return QPainter::CompositionMode_ColorBurn; - } else if (compositeOperator == QStringLiteral("qt-hard-light")) { + } else if (compositeOperator == QLatin1String("qt-hard-light")) { return QPainter::CompositionMode_HardLight; - } else if (compositeOperator == QStringLiteral("qt-soft-light")) { + } else if (compositeOperator == QLatin1String("qt-soft-light")) { return QPainter::CompositionMode_SoftLight; - } else if (compositeOperator == QStringLiteral("qt-difference")) { + } else if (compositeOperator == QLatin1String("qt-difference")) { return QPainter::CompositionMode_Difference; - } else if (compositeOperator == QStringLiteral("qt-exclusion")) { + } else if (compositeOperator == QLatin1String("qt-exclusion")) { return QPainter::CompositionMode_Exclusion; } return QPainter::CompositionMode_SourceOver; @@ -1314,7 +1314,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_globalCompositeOperation(QV4::C QString mode = ctx->args()[0].toQString(); QPainter::CompositionMode cm = qt_composite_mode_from_string(mode); - if (cm == QPainter::CompositionMode_SourceOver && mode != QStringLiteral("source-over")) + if (cm == QPainter::CompositionMode_SourceOver && mode != QLatin1String("source-over")) return QV4::Encode::undefined(); if (cm != r->d()->context->state.globalCompositeOperation) { @@ -1431,10 +1431,10 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_fillRule(QV4::CallContext *ctx) QV4::ScopedValue value(scope, ctx->argument(0)); - if ((value->isString() && value->toQString() == QStringLiteral("WindingFill")) + if ((value->isString() && value->toQString() == QLatin1String("WindingFill")) || (value->isInt32() && value->integerValue() == Qt::WindingFill)) { r->d()->context->state.fillRule = Qt::WindingFill; - } else if ((value->isString() && value->toQStringNoThrow() == QStringLiteral("OddEvenFill")) + } else if ((value->isString() && value->toQStringNoThrow() == QLatin1String("OddEvenFill")) || (value->isInt32() && value->integerValue() == Qt::OddEvenFill)) { r->d()->context->state.fillRule = Qt::OddEvenFill; } else { @@ -1730,16 +1730,16 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createPattern(QV4::CallCon pattern->d()->brush.setTextureImage(patternTexture); QString repetition = ctx->args()[1].toQStringNoThrow(); - if (repetition == QStringLiteral("repeat") || repetition.isEmpty()) { + if (repetition == QLatin1String("repeat") || repetition.isEmpty()) { pattern->d()->patternRepeatX = true; pattern->d()->patternRepeatY = true; - } else if (repetition == QStringLiteral("repeat-x")) { + } else if (repetition == QLatin1String("repeat-x")) { pattern->d()->patternRepeatX = true; pattern->d()->patternRepeatY = false; - } else if (repetition == QStringLiteral("repeat-y")) { + } else if (repetition == QLatin1String("repeat-y")) { pattern->d()->patternRepeatX = false; pattern->d()->patternRepeatY = true; - } else if (repetition == QStringLiteral("no-repeat")) { + } else if (repetition == QLatin1String("no-repeat")) { pattern->d()->patternRepeatX = false; pattern->d()->patternRepeatY = false; } else { @@ -1793,11 +1793,11 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_lineCap(QV4::CallContext *ctx) QString lineCap = ctx->args()[0].toQString(); Qt::PenCapStyle cap; - if (lineCap == QStringLiteral("round")) + if (lineCap == QLatin1String("round")) cap = Qt::RoundCap; - else if (lineCap == QStringLiteral("butt")) + else if (lineCap == QLatin1String("butt")) cap = Qt::FlatCap; - else if (lineCap == QStringLiteral("square")) + else if (lineCap == QLatin1String("square")) cap = Qt::SquareCap; else return QV4::Encode::undefined(); @@ -1852,11 +1852,11 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_lineJoin(QV4::CallContext *ctx) QString lineJoin = ctx->args()[0].toQString(); Qt::PenJoinStyle join; - if (lineJoin == QStringLiteral("round")) + if (lineJoin == QLatin1String("round")) join = Qt::RoundJoin; - else if (lineJoin == QStringLiteral("bevel")) + else if (lineJoin == QLatin1String("bevel")) join = Qt::BevelJoin; - else if (lineJoin == QStringLiteral("miter")) + else if (lineJoin == QLatin1String("miter")) join = Qt::SvgMiterJoin; else return QV4::Encode::undefined(); @@ -2733,15 +2733,15 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_textBaseline(QV4::CallContext * QString textBaseline = s->toQString(); QQuickContext2D::TextBaseLineType tb; - if (textBaseline == QStringLiteral("alphabetic")) + if (textBaseline == QLatin1String("alphabetic")) tb = QQuickContext2D::Alphabetic; - else if (textBaseline == QStringLiteral("hanging")) + else if (textBaseline == QLatin1String("hanging")) tb = QQuickContext2D::Hanging; - else if (textBaseline == QStringLiteral("top")) + else if (textBaseline == QLatin1String("top")) tb = QQuickContext2D::Top; - else if (textBaseline == QStringLiteral("bottom")) + else if (textBaseline == QLatin1String("bottom")) tb = QQuickContext2D::Bottom; - else if (textBaseline == QStringLiteral("middle")) + else if (textBaseline == QLatin1String("middle")) tb = QQuickContext2D::Middle; else return QV4::Encode::undefined(); diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp index 12bd95101f..f3513f447a 100644 --- a/src/quick/items/context2d/qquickcontext2dtexture.cpp +++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp @@ -605,6 +605,11 @@ QPaintDevice* QQuickContext2DFBOTexture::beginPainting() void QQuickContext2DFBOTexture::endPainting() { QQuickContext2DTexture::endPainting(); + + // There may not be an FBO due to zero width or height. + if (!m_fbo) + return; + if (m_multisampledFbo) QOpenGLFramebufferObject::blitFramebuffer(m_fbo, m_multisampledFbo); diff --git a/src/quick/items/qquickanimatedimage.cpp b/src/quick/items/qquickanimatedimage.cpp index 3ae2512c98..42033b6135 100644 --- a/src/quick/items/qquickanimatedimage.cpp +++ b/src/quick/items/qquickanimatedimage.cpp @@ -47,8 +47,10 @@ #include <QtQml/qqmlfile.h> #include <QtQml/qqmlengine.h> #include <QtGui/qmovie.h> +#ifndef QT_NO_NETWORK #include <QtNetwork/qnetworkrequest.h> #include <QtNetwork/qnetworkreply.h> +#endif QT_BEGIN_NAMESPACE @@ -144,8 +146,10 @@ QQuickAnimatedImage::QQuickAnimatedImage(QQuickItem *parent) QQuickAnimatedImage::~QQuickAnimatedImage() { Q_D(QQuickAnimatedImage); +#ifndef QT_NO_NETWORK if (d->reply) d->reply->deleteLater(); +#endif delete d->_movie; qDeleteAll(d->frameMap); d->frameMap.clear(); @@ -264,10 +268,12 @@ void QQuickAnimatedImage::setSource(const QUrl &url) if (url == d->url) return; +#ifndef QT_NO_NETWORK if (d->reply) { d->reply->deleteLater(); d->reply = 0; } +#endif d->setImage(QImage()); qDeleteAll(d->frameMap); @@ -318,6 +324,7 @@ void QQuickAnimatedImage::load() d->_movie = new QMovie(lf); movieRequestFinished(); } else { +#ifndef QT_NO_NETWORK if (d->status != Loading) { d->status = Loading; emit statusChanged(d->status); @@ -334,6 +341,7 @@ void QQuickAnimatedImage::load() this, SLOT(movieRequestFinished())); QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(requestProgress(qint64,qint64))); +#endif } } } @@ -342,8 +350,10 @@ void QQuickAnimatedImage::load() void QQuickAnimatedImage::movieRequestFinished() { + Q_D(QQuickAnimatedImage); +#ifndef QT_NO_NETWORK if (d->reply) { d->redirectCount++; if (d->redirectCount < ANIMATEDIMAGE_MAXIMUM_REDIRECT_RECURSION) { @@ -359,6 +369,7 @@ void QQuickAnimatedImage::movieRequestFinished() d->redirectCount=0; d->_movie = new QMovie(d->reply); } +#endif if (!d->_movie->isValid()) { qmlInfo(this) << "Error Reading Animated Image File " << d->url.toString(); diff --git a/src/quick/items/qquickanimatedimage_p_p.h b/src/quick/items/qquickanimatedimage_p_p.h index 9474254252..9b284f966d 100644 --- a/src/quick/items/qquickanimatedimage_p_p.h +++ b/src/quick/items/qquickanimatedimage_p_p.h @@ -58,7 +58,9 @@ QT_BEGIN_NAMESPACE class QMovie; +#ifndef QT_NO_NETWORK class QNetworkReply; +#endif class QQuickAnimatedImagePrivate : public QQuickImagePrivate { @@ -66,7 +68,10 @@ class QQuickAnimatedImagePrivate : public QQuickImagePrivate public: QQuickAnimatedImagePrivate() - : playing(true), paused(false), preset_currentframe(0), _movie(0), reply(0), redirectCount(0), oldPlaying(false) + : playing(true), paused(false), preset_currentframe(0), _movie(0), oldPlaying(false) +#ifndef QT_NO_NETWORK + , reply(0), redirectCount(0) +#endif { } @@ -76,9 +81,11 @@ public: bool paused; int preset_currentframe; QMovie *_movie; + bool oldPlaying; +#ifndef QT_NO_NETWORK QNetworkReply *reply; int redirectCount; - bool oldPlaying; +#endif QMap<int, QQuickPixmap *> frameMap; }; diff --git a/src/quick/items/qquickanimatedsprite.cpp b/src/quick/items/qquickanimatedsprite.cpp index b3c1e8fb40..f5df5763bb 100644 --- a/src/quick/items/qquickanimatedsprite.cpp +++ b/src/quick/items/qquickanimatedsprite.cpp @@ -544,6 +544,7 @@ QSGGeometryNode* QQuickAnimatedSprite::buildNode() m_node->setGeometry(g); m_node->setMaterial(m_material); m_node->setFlag(QSGGeometryNode::OwnsMaterial); + m_node->setFlag(QSGGeometryNode::OwnsGeometry); sizeVertices(); return m_node; } diff --git a/src/quick/items/qquickborderimage.cpp b/src/quick/items/qquickborderimage.cpp index 66f414d816..5f8dd7b989 100644 --- a/src/quick/items/qquickborderimage.cpp +++ b/src/quick/items/qquickborderimage.cpp @@ -43,7 +43,9 @@ #include <QtQml/qqmlinfo.h> #include <QtQml/qqmlfile.h> #include <QtQml/qqmlengine.h> +#ifndef QT_NO_NETWORK #include <QtNetwork/qnetworkreply.h> +#endif #include <QtCore/qfile.h> #include <QtCore/qmath.h> #include <QtGui/qguiapplication.h> @@ -169,9 +171,11 @@ QQuickBorderImage::QQuickBorderImage(QQuickItem *parent) QQuickBorderImage::~QQuickBorderImage() { +#ifndef QT_NO_NETWORK Q_D(QQuickBorderImage); if (d->sciReply) d->sciReply->deleteLater(); +#endif } /*! @@ -270,10 +274,12 @@ void QQuickBorderImage::setSource(const QUrl &url) if (url == d->url) return; +#ifndef QT_NO_NETWORK if (d->sciReply) { d->sciReply->deleteLater(); d->sciReply = 0; } +#endif d->url = url; d->sciurl = QUrl(); @@ -311,6 +317,7 @@ void QQuickBorderImage::load() setGridScaledImage(QQuickGridScaledImage(&file)); return; } else { +#ifndef QT_NO_NETWORK if (d->progress != 0.0) { d->progress = 0.0; emit progressChanged(d->progress); @@ -320,6 +327,7 @@ void QQuickBorderImage::load() d->sciReply = qmlEngine(this)->networkAccessManager()->get(req); qmlobject_connect(d->sciReply, QNetworkReply, SIGNAL(finished()), this, QQuickBorderImage, SLOT(sciRequestFinished())) +#endif } } else { QQuickPixmap::Options options; @@ -529,6 +537,7 @@ void QQuickBorderImage::requestFinished() pixmapChange(); } +#ifndef QT_NO_NETWORK #define BORDERIMAGE_MAX_REDIRECT 16 void QQuickBorderImage::sciRequestFinished() @@ -558,6 +567,7 @@ void QQuickBorderImage::sciRequestFinished() setGridScaledImage(sci); } } +#endif // QT_NO_NETWORK void QQuickBorderImage::doUpdate() { diff --git a/src/quick/items/qquickborderimage_p.h b/src/quick/items/qquickborderimage_p.h index 7f8b172a21..f2764660f6 100644 --- a/src/quick/items/qquickborderimage_p.h +++ b/src/quick/items/qquickborderimage_p.h @@ -101,7 +101,9 @@ private: private Q_SLOTS: void doUpdate(); void requestFinished() Q_DECL_OVERRIDE; +#ifndef QT_NO_NETWORK void sciRequestFinished(); +#endif private: Q_DISABLE_COPY(QQuickBorderImage) diff --git a/src/quick/items/qquickborderimage_p_p.h b/src/quick/items/qquickborderimage_p_p.h index 478de88a52..1dc530e34e 100644 --- a/src/quick/items/qquickborderimage_p_p.h +++ b/src/quick/items/qquickborderimage_p_p.h @@ -58,17 +58,20 @@ QT_BEGIN_NAMESPACE +#ifndef QT_NO_NETWORK class QNetworkReply; +#endif class QQuickBorderImagePrivate : public QQuickImageBasePrivate { Q_DECLARE_PUBLIC(QQuickBorderImage) public: QQuickBorderImagePrivate() - : border(0), sciReply(0), - horizontalTileMode(QQuickBorderImage::Stretch), - verticalTileMode(QQuickBorderImage::Stretch), - redirectCount(0), pixmapChanged(false) + : border(0), horizontalTileMode(QQuickBorderImage::Stretch), + verticalTileMode(QQuickBorderImage::Stretch), pixmapChanged(false) +#ifndef QT_NO_NETWORK + , sciReply(0), redirectCount(0) +#endif { } @@ -90,12 +93,14 @@ public: QQuickScaleGrid *border; QUrl sciurl; - QNetworkReply *sciReply; QQuickBorderImage::TileMode horizontalTileMode; QQuickBorderImage::TileMode verticalTileMode; - int redirectCount; - bool pixmapChanged : 1; + +#ifndef QT_NO_NETWORK + QNetworkReply *sciReply; + int redirectCount; +#endif }; QT_END_NAMESPACE diff --git a/src/quick/items/qquickflickable.cpp b/src/quick/items/qquickflickable.cpp index 3663b379bb..b0245f402b 100644 --- a/src/quick/items/qquickflickable.cpp +++ b/src/quick/items/qquickflickable.cpp @@ -65,6 +65,8 @@ static const int FlickThreshold = 15; // will ensure the Flickable retains the grab on consecutive flicks. static const int RetainGrabVelocity = 100; +static const int MovementEndingTimerInterval = 100; + static qreal EaseOvershoot(qreal t) { return qAtan(t); } @@ -244,6 +246,8 @@ void QQuickFlickablePrivate::init() contentItem->setParentItem(q); qmlobject_connect(&timeline, QQuickTimeLine, SIGNAL(completed()), q, QQuickFlickable, SLOT(timelineCompleted())) + qmlobject_connect(&velocityTimeline, QQuickTimeLine, SIGNAL(completed()), + q, QQuickFlickable, SLOT(velocityTimelineCompleted())) q->setAcceptedMouseButtons(Qt::LeftButton); q->setFiltersChildMouseEvents(true); QQuickItemPrivate *viewportPrivate = QQuickItemPrivate::get(contentItem); @@ -1202,6 +1206,8 @@ void QQuickFlickablePrivate::drag(qint64 currentTimestamp, QEvent::Type eventTyp hData.velocity = 0; } + if (momentum && !hData.flicking && !vData.flicking) + flickingStarted(hData.velocity != 0, vData.velocity != 0); draggingStarting(); if ((hMoved && !prevHMoved) || (vMoved && !prevVMoved)) @@ -1390,10 +1396,17 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event) d->timer.start(); d->maybeBeginDrag(currentTimestamp, event->posF()); break; + case Qt::NoScrollPhase: // default phase with an ordinary wheel mouse case Qt::ScrollUpdate: + if (d->scrollingPhase) { + d->pressed = true; + d->movementEndingTimer.start(MovementEndingTimerInterval, this); + } break; case Qt::ScrollEnd: + d->pressed = false; d->scrollingPhase = false; + d->movementEndingTimer.start(MovementEndingTimerInterval, this); d->draggingEnding(); event->accept(); returnToBounds(); @@ -1415,7 +1428,6 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event) valid = true; } if (valid) { - d->vData.flicking = false; d->flickY(d->vData.velocity); d->flickingStarted(false, true); if (d->vData.flicking) { @@ -1435,7 +1447,6 @@ void QQuickFlickable::wheelEvent(QWheelEvent *event) valid = true; } if (valid) { - d->hData.flicking = false; d->flickX(d->hData.velocity); d->flickingStarted(true, false); if (d->hData.flicking) { @@ -1548,6 +1559,12 @@ void QQuickFlickable::timerEvent(QTimerEvent *event) if (d->delayedPressEvent) { d->replayDelayedPress(); } + } else if (event->timerId() == d->movementEndingTimer.timerId()) { + d->movementEndingTimer.stop(); + d->pressed = false; + d->stealMouse = false; + if (!d->velocityTimeline.isActive()) + movementEnding(true, true); } } @@ -2475,6 +2492,22 @@ bool QQuickFlickable::isMovingVertically() const return d->vData.moving; } +void QQuickFlickable::velocityTimelineCompleted() +{ + Q_D(QQuickFlickable); + if ( (d->hData.transitionToBounds && d->hData.transitionToBounds->isActive()) + || (d->vData.transitionToBounds && d->vData.transitionToBounds->isActive()) ) { + return; + } + // With subclasses such as GridView, velocityTimeline.completed is emitted repeatedly: + // for example setting currentIndex results in a visual "flick" which the user + // didn't initiate directly. We don't want to end movement repeatedly, and in + // that case movementEnding will happen after the sequence of movements ends. + if (d->vData.flicking) + movementEnding(); + d->updateBeginningEnd(); +} + void QQuickFlickable::timelineCompleted() { Q_D(QQuickFlickable); diff --git a/src/quick/items/qquickflickable_p.h b/src/quick/items/qquickflickable_p.h index a7995c5025..6cf78dcf63 100644 --- a/src/quick/items/qquickflickable_p.h +++ b/src/quick/items/qquickflickable_p.h @@ -259,6 +259,7 @@ protected Q_SLOTS: void movementStarting(); void movementEnding(); void movementEnding(bool hMovementEnding, bool vMovementEnding); + void velocityTimelineCompleted(); void timelineCompleted(); protected: diff --git a/src/quick/items/qquickflickable_p_p.h b/src/quick/items/qquickflickable_p_p.h index 83e38af8a9..3c59b19ec2 100644 --- a/src/quick/items/qquickflickable_p_p.h +++ b/src/quick/items/qquickflickable_p_p.h @@ -218,6 +218,7 @@ public: bool calcVelocity : 1; bool pixelAligned : 1; QElapsedTimer timer; + QBasicTimer movementEndingTimer; qint64 lastPosTime; qint64 lastPressTime; QPointF lastPos; diff --git a/src/quick/items/qquickgridview.cpp b/src/quick/items/qquickgridview.cpp index 7da9801218..da48fd869d 100644 --- a/src/quick/items/qquickgridview.cpp +++ b/src/quick/items/qquickgridview.cpp @@ -182,6 +182,8 @@ public: bool addVisibleItems(qreal fillFrom, qreal fillTo, qreal bufferFrom, qreal bufferTo, bool doBuffer) Q_DECL_OVERRIDE; bool removeNonVisibleItems(qreal bufferFrom, qreal bufferTo) Q_DECL_OVERRIDE; + void removeItem(FxViewItem *item); + FxViewItem *newViewItem(int index, QQuickItem *item) Q_DECL_OVERRIDE; void initializeViewItem(FxViewItem *item) Q_DECL_OVERRIDE; void repositionItemAt(FxViewItem *item, int index, qreal sizeBuffer) Q_DECL_OVERRIDE; @@ -567,6 +569,17 @@ bool QQuickGridViewPrivate::addVisibleItems(qreal fillFrom, qreal fillTo, qreal return changed; } +void QQuickGridViewPrivate::removeItem(FxViewItem *item) +{ + if (item->transitionScheduledOrRunning()) { + qCDebug(lcItemViewDelegateLifecycle) << "\tnot releasing animating item:" << item->index << item->item->objectName(); + item->releaseAfterTransition = true; + releasePendingTransition.append(item); + } else { + releaseItem(item); + } +} + bool QQuickGridViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal bufferTo) { FxGridItemSG *item = 0; @@ -581,13 +594,7 @@ bool QQuickGridViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal buffer if (item->index != -1) visibleIndex++; visibleItems.removeFirst(); - if (item->transitionScheduledOrRunning()) { - qCDebug(lcItemViewDelegateLifecycle) << "\tnot releasing animating item:" << item->index << item->item->objectName(); - item->releaseAfterTransition = true; - releasePendingTransition.append(item); - } else { - releaseItem(item); - } + removeItem(item); changed = true; } while (visibleItems.count() > 1 @@ -597,13 +604,7 @@ bool QQuickGridViewPrivate::removeNonVisibleItems(qreal bufferFrom, qreal buffer break; qCDebug(lcItemViewDelegateLifecycle) << "refill: remove last" << visibleIndex+visibleItems.count()-1; visibleItems.removeLast(); - if (item->transitionScheduledOrRunning()) { - qCDebug(lcItemViewDelegateLifecycle) << "\tnot releasing animating item:" << item->index << item->item->objectName(); - item->releaseAfterTransition = true; - releasePendingTransition.append(item); - } else { - releaseItem(item); - } + removeItem(item); changed = true; } @@ -1524,7 +1525,7 @@ void QQuickGridView::setHighlightFollowsCurrentItem(bool autoHighlight) existing applications. When explicitly set, it will cease to be bound to the interactive property. - \sa \l {Flickable::}{interactive} + \sa {Flickable::}{interactive} */ /*! @@ -2406,11 +2407,12 @@ bool QQuickGridViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch int i = count - 1; int from = tempPos - buffer - displayMarginBeginning; - while (i >= 0) { - if (rowPos > from && insertionIdx < visibleIndex) { - // item won't be visible, just note the size for repositioning - insertResult->countChangeBeforeVisible++; - } else { + if (rowPos > from && insertionIdx < visibleIndex) { + // items won't be visible, just note the size for repositioning + insertResult->countChangeBeforeVisible += count; + insertResult->sizeChangesBeforeVisiblePos += ((count + columns - 1) / columns) * rowSize(); + } else { + while (i >= 0) { // item is before first visible e.g. in cache buffer FxViewItem *item = 0; if (change.isMove() && (item = currentChanges.removedItems.take(change.moveKey(modelIndex + i)))) @@ -2426,19 +2428,40 @@ bool QQuickGridViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch insertResult->changedFirstItem = true; if (!change.isMove()) { addedItems->append(item); - item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true); + if (transitioner) + item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true); + else + item->moveTo(QPointF(colPos, rowPos), true); } insertResult->sizeChangesBeforeVisiblePos += rowSize(); + + if (--colNum < 0 ) { + colNum = columns - 1; + rowPos -= rowSize(); + } + colPos = colNum * colSize(); + index++; + i--; } + } - if (--colNum < 0 ) { - colNum = columns - 1; - rowPos -= rowSize(); + // There may be gaps in the index sequence of visibleItems because + // of the index shift/update done before the insertion just above. + // Find if there is any... + int firstOkIdx = -1; + for (int i = 0; i <= insertionIdx && i < visibleItems.count() - 1; i++) { + if (visibleItems.at(i)->index + 1 != visibleItems.at(i + 1)->index) { + firstOkIdx = i + 1; + break; } - colPos = colNum * colSize(); - index++; - i--; } + // ... and remove all the items before that one + for (int i = 0; i < firstOkIdx; i++) { + FxViewItem *nvItem = visibleItems.takeFirst(); + addedItems->removeOne(nvItem); + removeItem(nvItem); + } + } else { int i = 0; int to = buffer+displayMarginEnd+tempPos+size()-1; @@ -2463,7 +2486,10 @@ bool QQuickGridViewPrivate::applyInsertionChange(const QQmlChangeSet::Change &ch movingIntoView->append(MovedItem(item, change.moveKey(item->index))); } else { addedItems->append(item); - item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true); + if (transitioner) + item->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true); + else + item->moveTo(QPointF(colPos, rowPos), true); } insertResult->sizeChangesAfterVisiblePos += rowSize(); diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp index 866a83c42a..8117baa2fe 100644 --- a/src/quick/items/qquickimagebase.cpp +++ b/src/quick/items/qquickimagebase.cpp @@ -226,7 +226,7 @@ void QQuickImageBase::load() // will be used, as usual. bool setDevicePixelRatio = false; if (!d->sourcesize.isValid()) { - if (loadUrl.scheme() == QStringLiteral("image")) { + if (loadUrl.scheme() == QLatin1String("image")) { setDevicePixelRatio = true; } else { QString stringUrl = loadUrl.path(QUrl::PrettyDecoded); diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 5be1c86fb4..b2c039660e 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -2074,6 +2074,10 @@ void QQuickItemPrivate::updateSubFocusItem(QQuickItem *scope, bool focus) \value ItemRotationHasChanged The item's rotation has changed. ItemChangeData::realValue contains the new rotation. + + \value ItemDevicePixelRatioHasChanged The device pixel ratio of the screen + the item is on has changed. ItemChangedData::realValue contains the new + device pixel ratio. */ /*! @@ -2477,6 +2481,7 @@ QQuickItem *QQuickItemPrivate::prevTabChildItem(const QQuickItem *item, int star QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, bool forward) { Q_ASSERT(item); + qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: item:" << item << ", forward:" << forward; if (!item->window()) return item; @@ -2487,19 +2492,25 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo bool all = QGuiApplication::styleHints()->tabFocusBehavior() == Qt::TabFocusAllControls; QQuickItem *from = 0; + bool isTabFence = item->d_func()->isTabFence; if (forward) { - from = item->parentItem(); + if (!isTabFence) + from = item->parentItem(); } else { if (!item->childItems().isEmpty()) from = item->d_func()->childItems.constFirst(); - else + else if (!isTabFence) from = item->parentItem(); } bool skip = false; QQuickItem * startItem = item; QQuickItem * firstFromItem = from; QQuickItem *current = item; + qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: startItem:" << startItem; + qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: firstFromItem:" << firstFromItem; do { + qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: current:" << current; + qCDebug(DBG_FOCUS) << "QQuickItemPrivate::nextPrevItemInTabFocusChain: from:" << from; skip = false; QQuickItem *last = current; @@ -2513,7 +2524,7 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo else lastChild = prevTabChildItem(current, -1); } - bool isTabFence = current->d_func()->isTabFence; + isTabFence = current->d_func()->isTabFence; if (isTabFence && !hasChildren) return current; @@ -2568,9 +2579,14 @@ QQuickItem* QQuickItemPrivate::nextPrevItemInTabFocusChain(QQuickItem *item, boo return startItem; } } - if (!firstFromItem) { //start from root - startItem = current; - firstFromItem = from; + if (!firstFromItem) { + if (startItem->d_func()->isTabFence) { + if (current == startItem) + firstFromItem = from; + } else { //start from root + startItem = current; + firstFromItem = from; + } } } while (skip || !current->activeFocusOnTab() || !current->isEnabled() || !current->isVisible() || !(all || QQuickItemPrivate::canAcceptTabFocus(current))); @@ -4563,9 +4579,9 @@ QQuickItem *QQuickItem::childAt(qreal x, qreal y) const // Map coordinates to the child element's coordinate space QPointF point = mapToItem(child, QPointF(x, y)); if (child->isVisible() && point.x() >= 0 - && child->width() >= point.x() + && child->width() > point.x() && point.y() >= 0 - && child->height() >= point.y()) + && child->height() > point.y()) return child; } return 0; @@ -5968,6 +5984,8 @@ void QQuickItemPrivate::itemChange(QQuickItem::ItemChange change, const QQuickIt } break; case QQuickItem::ItemAntialiasingHasChanged: + // fall through + case QQuickItem::ItemDevicePixelRatioHasChanged: q->itemChange(change, data); break; } @@ -6906,7 +6924,7 @@ void QQuickItem::setAcceptedMouseButtons(Qt::MouseButtons buttons) } /*! - Returns whether mouse events of this item's children should be filtered + Returns whether mouse and touch events of this item's children should be filtered through this item. \sa setFiltersChildMouseEvents(), childMouseEventFilter() @@ -6918,7 +6936,7 @@ bool QQuickItem::filtersChildMouseEvents() const } /*! - Sets whether mouse events of this item's children should be filtered + Sets whether mouse and touch events of this item's children should be filtered through this item. If \a filter is true, childMouseEventFilter() will be called when @@ -7256,7 +7274,7 @@ void QQuickItem::setKeepTouchGrab(bool keep) } /*! - \qmlmethod object QtQuick::Item::contains(point point) + \qmlmethod bool QtQuick::Item::contains(point point) Returns true if this item contains \a point, which is in local coordinates; returns false otherwise. diff --git a/src/quick/items/qquickitem.h b/src/quick/items/qquickitem.h index 8795c71b38..b33f3d8b6a 100644 --- a/src/quick/items/qquickitem.h +++ b/src/quick/items/qquickitem.h @@ -172,7 +172,8 @@ public: ItemOpacityHasChanged, // value.realValue ItemActiveFocusHasChanged, // value.boolValue ItemRotationHasChanged, // value.realValue - ItemAntialiasingHasChanged // value.boolValue + ItemAntialiasingHasChanged, // value.boolValue + ItemDevicePixelRatioHasChanged // value.realValue }; union ItemChangeData { diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 7009a8e328..188b347a20 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -2484,8 +2484,10 @@ void QQuickItemViewPrivate::updateUnrequestedIndexes() void QQuickItemViewPrivate::updateUnrequestedPositions() { - for (QHash<QQuickItem*,int>::const_iterator it = unrequestedItems.cbegin(), cend = unrequestedItems.cend(); it != cend; ++it) - repositionPackageItemAt(it.key(), it.value()); + for (QHash<QQuickItem*,int>::const_iterator it = unrequestedItems.cbegin(), cend = unrequestedItems.cend(); it != cend; ++it) { + if (it.value() >= 0) + repositionPackageItemAt(it.key(), it.value()); + } } void QQuickItemViewPrivate::updateVisibleIndex() diff --git a/src/quick/items/qquicklistview.cpp b/src/quick/items/qquicklistview.cpp index e42873f459..f843b09592 100644 --- a/src/quick/items/qquicklistview.cpp +++ b/src/quick/items/qquicklistview.cpp @@ -2195,7 +2195,7 @@ void QQuickListView::setOrientation(QQuickListView::Orientation orientation) existing applications. When explicitly set, it will cease to be bound to the interactive property. - \sa \l {Flickable::}{interactive} + \sa {Flickable::}{interactive} */ diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp index 0f7f1961a1..f3254cf8d7 100644 --- a/src/quick/items/qquicktext.cpp +++ b/src/quick/items/qquicktext.cpp @@ -1465,7 +1465,8 @@ void QQuickText::itemChange(ItemChange change, const ItemChangeData &value) { Q_D(QQuickText); Q_UNUSED(value); - if (change == ItemAntialiasingHasChanged) { + switch (change) { + case ItemAntialiasingHasChanged: if (!antialiasing()) d->font.setStyleStrategy(QFont::NoAntialias); else @@ -1473,6 +1474,22 @@ void QQuickText::itemChange(ItemChange change, const ItemChangeData &value) d->implicitWidthValid = false; d->implicitHeightValid = false; d->updateLayout(); + break; + + case ItemDevicePixelRatioHasChanged: + if (d->renderType == NativeRendering) { + // Native rendering optimizes for a given pixel grid, so its results must not be scaled. + // Text layout code respects the current device pixel ratio automatically, we only need + // to rerun layout after the ratio changed. + // Changes of implicit size should be minimal; they are hard to avoid. + d->implicitWidthValid = false; + d->implicitHeightValid = false; + d->updateLayout(); + } + break; + + default: + break; } QQuickItem::itemChange(change, value); } diff --git a/src/quick/items/qquicktextcontrol.cpp b/src/quick/items/qquicktextcontrol.cpp index ab460034bb..127b51948a 100644 --- a/src/quick/items/qquicktextcontrol.cpp +++ b/src/quick/items/qquicktextcontrol.cpp @@ -44,6 +44,7 @@ #include <qcoreapplication.h> #include <qfont.h> +#include <qfontmetrics.h> #include <qevent.h> #include <qdebug.h> #include <qdrag.h> @@ -965,6 +966,14 @@ process: { QString text = e->text(); if (!text.isEmpty() && (text.at(0).isPrint() || text.at(0) == QLatin1Char('\t'))) { + if (overwriteMode + // no need to call deleteChar() if we have a selection, insertText + // does it already + && !cursor.hasSelection() + && !cursor.atBlockEnd()) { + cursor.deleteChar(); + } + cursor.insertText(text); selectionChanged(); } else { @@ -1007,6 +1016,12 @@ QRectF QQuickTextControlPrivate::rectForPosition(int position) const if (line.isValid()) { qreal x = line.cursorToX(relativePos); qreal w = 0; + if (overwriteMode) { + if (relativePos < line.textLength() - line.textStart()) + w = line.cursorToX(relativePos + 1) - x; + else + w = QFontMetrics(block.layout()->font()).width(QLatin1Char(' ')); // in sync with QTextLine::draw() + } r = QRectF(layoutPos.x() + x, layoutPos.y() + line.y(), textCursorWidth + w, line.height()); } else { r = QRectF(layoutPos.x(), layoutPos.y(), textCursorWidth, 10); // #### correct height @@ -1483,6 +1498,21 @@ bool QQuickTextControl::hasImState() const return d->hasImState; } +bool QQuickTextControl::overwriteMode() const +{ + Q_D(const QQuickTextControl); + return d->overwriteMode; +} + +void QQuickTextControl::setOverwriteMode(bool overwrite) +{ + Q_D(QQuickTextControl); + if (d->overwriteMode == overwrite) + return; + d->overwriteMode = overwrite; + emit overwriteModeChanged(overwrite); +} + bool QQuickTextControl::cursorVisible() const { Q_D(const QQuickTextControl); diff --git a/src/quick/items/qquicktextcontrol_p.h b/src/quick/items/qquicktextcontrol_p.h index 23c91d555b..cee9cff064 100644 --- a/src/quick/items/qquicktextcontrol_p.h +++ b/src/quick/items/qquicktextcontrol_p.h @@ -94,6 +94,8 @@ public: #endif bool hasImState() const; + bool overwriteMode() const; + void setOverwriteMode(bool overwrite); bool cursorVisible() const; void setCursorVisible(bool visible); QRectF cursorRect(const QTextCursor &cursor) const; @@ -148,6 +150,7 @@ Q_SIGNALS: void copyAvailable(bool b); void selectionChanged(); void cursorPositionChanged(); + void overwriteModeChanged(bool overwriteMode); // control signals void updateCursorRequest(); diff --git a/src/quick/items/qquicktextedit.cpp b/src/quick/items/qquicktextedit.cpp index f6c3d2f09f..a3ceb1344c 100644 --- a/src/quick/items/qquicktextedit.cpp +++ b/src/quick/items/qquicktextedit.cpp @@ -1584,6 +1584,32 @@ bool QQuickTextEdit::event(QEvent *event) } /*! + \qmlproperty bool QtQuick::TextEdit::overwriteMode + \since 5.8 + Whether text entered by the user will overwrite existing text. + + As with many text editors, the text editor widget can be configured + to insert or overwrite existing text with new text entered by the user. + + If this property is \c true, existing text is overwritten, character-for-character + by new text; otherwise, text is inserted at the cursor position, displacing + existing text. + + By default, this property is \c false (new text does not overwrite existing text). +*/ +bool QQuickTextEdit::overwriteMode() const +{ + Q_D(const QQuickTextEdit); + return d->control->overwriteMode(); +} + +void QQuickTextEdit::setOverwriteMode(bool overwrite) +{ + Q_D(QQuickTextEdit); + d->control->setOverwriteMode(overwrite); +} + +/*! \overload Handles the given key \a event. */ @@ -2186,6 +2212,7 @@ void QQuickTextEditPrivate::init() qmlobject_connect(control, QQuickTextControl, SIGNAL(cursorRectangleChanged()), q, QQuickTextEdit, SLOT(moveCursorDelegate())); qmlobject_connect(control, QQuickTextControl, SIGNAL(linkActivated(QString)), q, QQuickTextEdit, SIGNAL(linkActivated(QString))); qmlobject_connect(control, QQuickTextControl, SIGNAL(linkHovered(QString)), q, QQuickTextEdit, SIGNAL(linkHovered(QString))); + qmlobject_connect(control, QQuickTextControl, SIGNAL(overwriteModeChanged(bool)), q, QQuickTextEdit, SIGNAL(overwriteModeChanged(bool))); qmlobject_connect(control, QQuickTextControl, SIGNAL(textChanged()), q, QQuickTextEdit, SLOT(q_textChanged())); qmlobject_connect(control, QQuickTextControl, SIGNAL(preeditTextChanged()), q, QQuickTextEdit, SIGNAL(preeditTextChanged())); #ifndef QT_NO_CLIPBOARD diff --git a/src/quick/items/qquicktextedit_p.h b/src/quick/items/qquicktextedit_p.h index f6ecb984e3..42c9064860 100644 --- a/src/quick/items/qquicktextedit_p.h +++ b/src/quick/items/qquicktextedit_p.h @@ -86,6 +86,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextEdit : public QQuickImplicitSizeItem Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged) Q_PROPERTY(QRectF cursorRectangle READ cursorRectangle NOTIFY cursorRectangleChanged) Q_PROPERTY(QQmlComponent* cursorDelegate READ cursorDelegate WRITE setCursorDelegate NOTIFY cursorDelegateChanged) + Q_PROPERTY(bool overwriteMode READ overwriteMode WRITE setOverwriteMode NOTIFY overwriteModeChanged) Q_PROPERTY(int selectionStart READ selectionStart NOTIFY selectionStartChanged) Q_PROPERTY(int selectionEnd READ selectionEnd NOTIFY selectionEndChanged) Q_PROPERTY(QString selectedText READ selectedText NOTIFY selectedTextChanged) @@ -199,6 +200,9 @@ public: QQmlComponent* cursorDelegate() const; void setCursorDelegate(QQmlComponent*); + bool overwriteMode() const; + void setOverwriteMode(bool overwrite); + int selectionStart() const; int selectionEnd() const; @@ -313,6 +317,7 @@ Q_SIGNALS: void readOnlyChanged(bool isReadOnly); void cursorVisibleChanged(bool isCursorVisible); void cursorDelegateChanged(); + void overwriteModeChanged(bool overwriteMode); void activeFocusOnPressChanged(bool activeFocusOnPressed); void persistentSelectionChanged(bool isPersistentSelection); void textMarginChanged(qreal textMargin); diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index 7a86e1a323..9664326af5 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -813,7 +813,14 @@ QRectF QQuickTextInput::cursorRectangle() const return QRectF(); qreal x = l.cursorToX(c) - d->hscroll + leftPadding(); qreal y = l.y() - d->vscroll + topPadding(); - return QRectF(x, y, 1, l.height()); + qreal w = 1; + if (d->overwriteMode) { + if (c < text().length()) + w = l.cursorToX(c + 1) - x; + else + w = QFontMetrics(font()).width(QLatin1Char(' ')); // in sync with QTextLine::draw() + } + return QRectF(x, y, w, l.height()); } /*! @@ -1263,7 +1270,14 @@ QRectF QQuickTextInput::positionToRectangle(int pos) const return QRectF(); qreal x = l.cursorToX(pos) - d->hscroll; qreal y = l.y() - d->vscroll; - return QRectF(x, y, 1, l.height()); + qreal w = 1; + if (d->overwriteMode) { + if (pos < text().length()) + w = l.cursorToX(pos + 1) - x; + else + w = QFontMetrics(font()).width(QLatin1Char(' ')); // in sync with QTextLine::draw() + } + return QRectF(x, y, w, l.height()); } /*! @@ -1345,6 +1359,36 @@ int QQuickTextInputPrivate::positionAt(qreal x, qreal y, QTextLine::CursorPositi return line.isValid() ? line.xToCursor(x, position) : 0; } +/*! + \qmlproperty bool QtQuick::TextInput::overwriteMode + \since 5.8 + + Whether text entered by the user will overwrite existing text. + + As with many text editors, the text editor widget can be configured + to insert or overwrite existing text with new text entered by the user. + + If this property is \c true, existing text is overwritten, character-for-character + by new text; otherwise, text is inserted at the cursor position, displacing + existing text. + + By default, this property is \c false (new text does not overwrite existing text). +*/ +bool QQuickTextInput::overwriteMode() const +{ + Q_D(const QQuickTextInput); + return d->overwriteMode; +} + +void QQuickTextInput::setOverwriteMode(bool overwrite) +{ + Q_D(QQuickTextInput); + if (d->overwriteMode == overwrite) + return; + d->overwriteMode = overwrite; + emit overwriteModeChanged(overwrite); +} + void QQuickTextInput::keyPressEvent(QKeyEvent* ev) { Q_D(QQuickTextInput); @@ -4409,6 +4453,14 @@ void QQuickTextInputPrivate::processKeyEvent(QKeyEvent* event) if (unknown && !m_readOnly) { QString t = event->text(); if (!t.isEmpty() && t.at(0).isPrint()) { + if (overwriteMode + // no need to call del() if we have a selection, insert + // does it already + && !hasSelectedText() + && !(m_cursor == q_func()->text().length())) { + del(); + } + insert(t); event->accept(); return; diff --git a/src/quick/items/qquicktextinput_p.h b/src/quick/items/qquicktextinput_p.h index 06ca1acb0d..d2dee2c284 100644 --- a/src/quick/items/qquicktextinput_p.h +++ b/src/quick/items/qquicktextinput_p.h @@ -79,6 +79,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickTextInput : public QQuickImplicitSizeItem Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged) Q_PROPERTY(QRectF cursorRectangle READ cursorRectangle NOTIFY cursorRectangleChanged) Q_PROPERTY(QQmlComponent *cursorDelegate READ cursorDelegate WRITE setCursorDelegate NOTIFY cursorDelegateChanged) + Q_PROPERTY(bool overwriteMode READ overwriteMode WRITE setOverwriteMode NOTIFY overwriteModeChanged) Q_PROPERTY(int selectionStart READ selectionStart NOTIFY selectionStartChanged) Q_PROPERTY(int selectionEnd READ selectionEnd NOTIFY selectionEndChanged) Q_PROPERTY(QString selectedText READ selectedText NOTIFY selectedTextChanged) @@ -245,6 +246,9 @@ public: QQmlComponent* cursorDelegate() const; void setCursorDelegate(QQmlComponent*); + bool overwriteMode() const; + void setOverwriteMode(bool overwrite); + bool focusOnPress() const; void setFocusOnPress(bool); @@ -325,6 +329,7 @@ Q_SIGNALS: void readOnlyChanged(bool isReadOnly); void cursorVisibleChanged(bool isCursorVisible); void cursorDelegateChanged(); + void overwriteModeChanged(bool overwriteMode); void maximumLengthChanged(int maximumLength); void validatorChanged(); void inputMaskChanged(const QString &inputMask); diff --git a/src/quick/items/qquicktextinput_p_p.h b/src/quick/items/qquicktextinput_p_p.h index 24cbc7f74b..d5a138945d 100644 --- a/src/quick/items/qquicktextinput_p_p.h +++ b/src/quick/items/qquicktextinput_p_p.h @@ -158,6 +158,7 @@ public: , m_passwordEchoEditing(false) , inLayout(false) , requireImplicitWidth(false) + , overwriteMode(false) { } @@ -299,6 +300,7 @@ public: bool m_passwordEchoEditing : 1; bool inLayout:1; bool requireImplicitWidth:1; + bool overwriteMode:1; static inline QQuickTextInputPrivate *get(QQuickTextInput *t) { return t->d_func(); diff --git a/src/quick/items/qquicktextnodeengine.cpp b/src/quick/items/qquicktextnodeengine.cpp index 34b9d6efa2..7b600adf53 100644 --- a/src/quick/items/qquicktextnodeengine.cpp +++ b/src/quick/items/qquicktextnodeengine.cpp @@ -731,10 +731,13 @@ void QQuickTextNodeEngine::mergeProcessedNodes(QList<BinaryTreeNode *> *regularN QVector<QPointF> glyphPositions = glyphRun.positions(); glyphPositions.reserve(count); + QRectF glyphBoundingRect = glyphRun.boundingRect(); + for (int j = 1; j < nodes.size(); ++j) { BinaryTreeNode *otherNode = nodes.at(j); glyphIndexes += otherNode->glyphRun.glyphIndexes(); primaryNode->ranges += otherNode->ranges; + glyphBoundingRect = glyphBoundingRect.united(otherNode->glyphRun.boundingRect()); QVector<QPointF> otherPositions = otherNode->glyphRun.positions(); for (int k = 0; k < otherPositions.size(); ++k) @@ -746,6 +749,7 @@ void QQuickTextNodeEngine::mergeProcessedNodes(QList<BinaryTreeNode *> *regularN glyphRun.setGlyphIndexes(glyphIndexes); glyphRun.setPositions(glyphPositions); + glyphRun.setBoundingRect(glyphBoundingRect); } } } @@ -828,14 +832,15 @@ void QQuickTextNodeEngine::addToSceneGraph(QQuickTextNode *parentNode, for (int i = 0; i < node->ranges.size(); ++i) { const QPair<int, int> &range = node->ranges.at(i); - int rangeLength = range.second - range.first; + int rangeLength = range.second - range.first + 1; if (previousNode != 0) { for (int j = 0; j < previousNode->ranges.size(); ++j) { const QPair<int, int> &otherRange = previousNode->ranges.at(j); + if (range.first < otherRange.second && range.second > otherRange.first) { int start = qMax(range.first, otherRange.first); int end = qMin(range.second, otherRange.second); - rangeLength -= end - start; + rangeLength -= end - start + 1; if (rangeLength == 0) break; } @@ -849,7 +854,7 @@ void QQuickTextNodeEngine::addToSceneGraph(QQuickTextNode *parentNode, if (range.first < otherRange.second && range.second > otherRange.first) { int start = qMax(range.first, otherRange.first); int end = qMin(range.second, otherRange.second); - rangeLength -= end - start; + rangeLength -= end - start + 1; if (rangeLength == 0) break; } diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 635f1da77e..b6d685fdf0 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -294,10 +294,43 @@ void QQuickWindow::update() QQuickRenderControlPrivate::get(d->renderControl)->update(); } +static void updatePixelRatioHelper(QQuickItem *item, float pixelRatio) +{ + if (item->flags() & QQuickItem::ItemHasContents) { + QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item); + itemPrivate->itemChange(QQuickItem::ItemDevicePixelRatioHasChanged, pixelRatio); + } + + QList <QQuickItem *> items = item->childItems(); + for (int i = 0; i < items.size(); ++i) + updatePixelRatioHelper(items.at(i), pixelRatio); +} + +void QQuickWindow::physicalDpiChanged() +{ + Q_D(QQuickWindow); + const qreal newPixelRatio = screen()->devicePixelRatio(); + if (qFuzzyCompare(newPixelRatio, d->devicePixelRatio)) + return; + d->devicePixelRatio = newPixelRatio; + if (d->contentItem) + updatePixelRatioHelper(d->contentItem, newPixelRatio); +} + void QQuickWindow::handleScreenChanged(QScreen *screen) { Q_D(QQuickWindow); - Q_UNUSED(screen) + if (screen) { + physicalDpiChanged(); + // When physical DPI changes on the same screen, either the resolution or the device pixel + // ratio changed. We must check what it is. Device pixel ratio does not have its own + // ...Changed() signal. + d->physicalDpiChangedConnection = connect(screen, SIGNAL(physicalDotsPerInchChanged(qreal)), + this, SLOT(physicalDpiChanged())); + } else { + disconnect(d->physicalDpiChangedConnection); + } + d->forcePolish(); } @@ -416,6 +449,7 @@ QQuickWindowPrivate::QQuickWindowPrivate() , touchMouseId(-1) , touchMousePressTimestamp(0) , dirtyItemList(0) + , devicePixelRatio(0) , context(0) , renderer(0) , windowManager(0) @@ -470,6 +504,9 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control) Q_ASSERT(windowManager || renderControl); + if (QScreen *screen = q->screen()) + devicePixelRatio = screen->devicePixelRatio(); + QSGContext *sg; if (renderControl) { QQuickRenderControlPrivate *renderControlPriv = QQuickRenderControlPrivate::get(renderControl); @@ -2114,7 +2151,7 @@ bool QQuickWindowPrivate::deliverTouchPoints(QQuickItem *item, QTouchEvent *even return (acceptedNewPoints->count() == newPoints.count() && updatedPoints->isEmpty()); } -// touchEventForItemBounds has no means to generate a touch event that contains +// touchEventForItem has no means to generate a touch event that contains // only the points that are relevant for this item. Thus the need for // matchingPoints to already be that set of interesting points. // They are all pre-transformed, too. @@ -2176,7 +2213,7 @@ bool QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QTouchEv return touchEventAccepted; } -QTouchEvent *QQuickWindowPrivate::touchEventForItemBounds(QQuickItem *target, const QTouchEvent &originalEvent) +QTouchEvent *QQuickWindowPrivate::touchEventForItem(QQuickItem *target, const QTouchEvent &originalEvent, bool alwaysCheckBounds) { const QList<QTouchEvent::TouchPoint> &touchPoints = originalEvent.touchPoints(); QList<QTouchEvent::TouchPoint> pointsInBounds; @@ -2184,7 +2221,10 @@ QTouchEvent *QQuickWindowPrivate::touchEventForItemBounds(QQuickItem *target, co if (originalEvent.touchPointStates() != Qt::TouchPointStationary) { for (int i = 0; i < touchPoints.count(); ++i) { const QTouchEvent::TouchPoint &tp = touchPoints.at(i); - if (tp.state() == Qt::TouchPointPressed) { + // Touch presses are relevant to the target item only if they occur inside its bounds. + // Touch updates and releases are relevant if they occur inside, or if we want to + // finish the sequence because the press occurred inside. + if (tp.state() == Qt::TouchPointPressed || alwaysCheckBounds) { QPointF p = target->mapFromScene(tp.scenePos()); if (target->contains(p)) pointsInBounds.append(tp); @@ -2413,7 +2453,7 @@ bool QQuickWindowPrivate::sendFilteredTouchEvent(QQuickItem *target, QQuickItem QQuickItemPrivate *targetPrivate = QQuickItemPrivate::get(target); if (targetPrivate->filtersChildMouseEvents && !hasFiltered->contains(target)) { hasFiltered->insert(target); - QScopedPointer<QTouchEvent> targetEvent(touchEventForItemBounds(target, *event)); + QScopedPointer<QTouchEvent> targetEvent(touchEventForItem(target, *event)); if (!targetEvent->touchPoints().isEmpty()) { if (target->childMouseEventFilter(item, targetEvent.data())) { qCDebug(DBG_TOUCH) << " - first chance intercepted on childMouseEventFilter by " << target; @@ -2513,6 +2553,15 @@ bool QQuickWindowPrivate::dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent return overThreshold; } +bool QQuickWindowPrivate::dragOverThreshold(qreal d, Qt::Axis axis, const QTouchEvent::TouchPoint *tp, int startDragThreshold) +{ + QStyleHints *styleHints = qApp->styleHints(); + bool overThreshold = qAbs(d) > (startDragThreshold >= 0 ? startDragThreshold : styleHints->startDragDistance()); + qreal velocity = axis == Qt::XAxis ? tp->velocity().x() : tp->velocity().y(); + overThreshold |= qAbs(velocity) > styleHints->startDragVelocity(); + return overThreshold; +} + /*! \qmlproperty list<Object> Window::data \default @@ -3872,6 +3921,14 @@ void QQuickWindow::resetOpenGLState() */ /*! + \qmlattachedproperty Window Window::window + \since 5.7 + + This attached property holds the item's window. + The Window attached property can be attached to any Item. +*/ + +/*! \qmlattachedproperty int Window::width \qmlattachedproperty int Window::height \since 5.5 diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h index 262828ad1d..e04a4a1ce2 100644 --- a/src/quick/items/qquickwindow.h +++ b/src/quick/items/qquickwindow.h @@ -202,6 +202,7 @@ protected: private Q_SLOTS: void maybeUpdate(); void cleanupSceneGraph(); + void physicalDpiChanged(); void handleScreenChanged(QScreen *screen); void setTransientParent_helper(QQuickWindow *window); void runJobsAfterSwap(); diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index 652320c1c9..1486e20e1e 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -163,8 +163,8 @@ public: void flushDelayedTouchEvent(); bool deliverHoverEvent(QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, bool &accepted); bool deliverMatchingPointsToItem(QQuickItem *item, QTouchEvent *event, QSet<int> *acceptedNewPoints, const QSet<int> &matchingNewPoints, const QList<QTouchEvent::TouchPoint> &matchingPoints, QSet<QQuickItem*> *filtered); - QTouchEvent *touchEventForItemBounds(QQuickItem *target, const QTouchEvent &originalEvent); - QTouchEvent *touchEventWithPoints(const QTouchEvent &event, const QList<QTouchEvent::TouchPoint> &newPoints); + static QTouchEvent *touchEventForItem(QQuickItem *target, const QTouchEvent &originalEvent, bool alwaysCheckBounds = false); + static QTouchEvent *touchEventWithPoints(const QTouchEvent &event, const QList<QTouchEvent::TouchPoint> &newPoints); bool sendFilteredTouchEvent(QQuickItem *target, QQuickItem *item, QTouchEvent *event, QSet<QQuickItem*> *filtered); bool sendHoverEvent(QEvent::Type, QQuickItem *, const QPointF &scenePos, const QPointF &lastScenePos, Qt::KeyboardModifiers modifiers, bool accepted); @@ -211,6 +211,9 @@ public: QVector<QQuickItem *> itemsToPolish; + qreal devicePixelRatio; + QMetaObject::Connection physicalDpiChangedConnection; + void updateDirtyNodes(); void cleanupNodes(); void cleanupNodesOnShutdown(); @@ -262,6 +265,7 @@ public: static bool defaultAlphaBuffer; static bool dragOverThreshold(qreal d, Qt::Axis axis, QMouseEvent *event, int startDragThreshold = -1); + static bool dragOverThreshold(qreal d, Qt::Axis axis, const QTouchEvent::TouchPoint *tp, int startDragThreshold = -1); // data property static void data_append(QQmlListProperty<QObject> *, QObject *); diff --git a/src/quick/items/qquickwindowattached.cpp b/src/quick/items/qquickwindowattached.cpp index e1cd3c82f2..c6380e2b9a 100644 --- a/src/quick/items/qquickwindowattached.cpp +++ b/src/quick/items/qquickwindowattached.cpp @@ -51,9 +51,9 @@ QQuickWindowAttached::QQuickWindowAttached(QObject* attachee) { m_attachee = qobject_cast<QQuickItem*>(attachee); if (m_attachee && m_attachee->window()) // It might not be in a window yet - windowChanged(m_attachee->window()); + windowChange(m_attachee->window()); if (m_attachee) - connect(m_attachee, &QQuickItem::windowChanged, this, &QQuickWindowAttached::windowChanged); + connect(m_attachee, &QQuickItem::windowChanged, this, &QQuickWindowAttached::windowChange); } QWindow::Visibility QQuickWindowAttached::visibility() const @@ -86,7 +86,12 @@ int QQuickWindowAttached::height() const return (m_window ? m_window->height() : 0); } -void QQuickWindowAttached::windowChanged(QQuickWindow *window) +QQuickWindow *QQuickWindowAttached::window() const +{ + return m_window; +} + +void QQuickWindowAttached::windowChange(QQuickWindow *window) { if (window != m_window) { QQuickWindow* oldWindow = m_window; @@ -95,21 +100,23 @@ void QQuickWindowAttached::windowChanged(QQuickWindow *window) if (oldWindow) oldWindow->disconnect(this); - if (!window) - return; // No values to get, therefore nothing to emit + emit windowChanged(); - if (!oldWindow || window->visibility() != oldWindow->visibility()) + if (!oldWindow || !window || window->visibility() != oldWindow->visibility()) emit visibilityChanged(); - if (!oldWindow || window->isActive() != oldWindow->isActive()) + if (!oldWindow || !window || window->isActive() != oldWindow->isActive()) emit activeChanged(); - if (!oldWindow || window->activeFocusItem() != oldWindow->activeFocusItem()) + if (!oldWindow || !window || window->activeFocusItem() != oldWindow->activeFocusItem()) emit activeFocusItemChanged(); emit contentItemChanged(); - if (!oldWindow || window->width() != oldWindow->width()) + if (!oldWindow || !window || window->width() != oldWindow->width()) emit widthChanged(); - if (!oldWindow || window->height() != oldWindow->height()) + if (!oldWindow || !window || window->height() != oldWindow->height()) emit heightChanged(); + if (!window) + return; + // QQuickWindowQmlImpl::visibilityChanged also exists, and window might even // be QQuickWindowQmlImpl, but that's not what we are connecting to. // So this is actual window state rather than a buffered or as-requested one. diff --git a/src/quick/items/qquickwindowattached_p.h b/src/quick/items/qquickwindowattached_p.h index 5e4b2c1721..3212508fd8 100644 --- a/src/quick/items/qquickwindowattached_p.h +++ b/src/quick/items/qquickwindowattached_p.h @@ -69,6 +69,7 @@ class Q_AUTOTEST_EXPORT QQuickWindowAttached : public QObject Q_PROPERTY(QQuickItem* contentItem READ contentItem NOTIFY contentItemChanged) Q_PROPERTY(int width READ width NOTIFY widthChanged) Q_PROPERTY(int height READ height NOTIFY heightChanged) + Q_PROPERTY(QQuickWindow *window READ window NOTIFY windowChanged) public: QQuickWindowAttached(QObject* attachee); @@ -79,6 +80,7 @@ public: QQuickItem* contentItem() const; int width() const; int height() const; + QQuickWindow *window() const; Q_SIGNALS: @@ -88,9 +90,10 @@ Q_SIGNALS: void contentItemChanged(); void widthChanged(); void heightChanged(); + void windowChanged(); protected Q_SLOTS: - void windowChanged(QQuickWindow*); + void windowChange(QQuickWindow*); private: QQuickWindow* m_window; diff --git a/src/quick/quick.pro b/src/quick/quick.pro index 4ff2d76a09..90ba867ea8 100644 --- a/src/quick/quick.pro +++ b/src/quick/quick.pro @@ -1,7 +1,12 @@ TARGET = QtQuick QT = core-private gui-private qml-private -QT_PRIVATE = network +!no_network { + QT_PRIVATE = network +} +no_network { + DEFINES += QT_NO_NETWORK +} DEFINES += QT_NO_URL_CAST_FROM_STRING QT_NO_INTEGER_EVENT_COORDINATES win32-msvc*:DEFINES *= _CRT_SECURE_NO_WARNINGS @@ -24,12 +29,10 @@ ANDROID_BUNDLED_FILES += \ qml \ lib/libQt5QuickParticles.so -load(qt_module) - include(util/util.pri) include(scenegraph/scenegraph.pri) include(items/items.pri) -include(designer/designer.pri) +!wince:include(designer/designer.pri) contains(QT_CONFIG, accessibility) { include(accessible/accessible.pri) } @@ -43,3 +46,5 @@ SOURCES += qtquick2.cpp # To make #include "qquickcontext2d_jsclass.cpp" work INCLUDEPATH += $$PWD + +load(qt_module) diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index a85a9ab3eb..bb5476c3e2 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -2698,7 +2698,9 @@ void Renderer::render() if (m_alphaBatches.size()) std::sort(&m_alphaBatches.first(), &m_alphaBatches.last() + 1, qsg_sort_batch_increasing_order); - m_zRange = 1.0 / (m_nextRenderOrder); + m_zRange = m_nextRenderOrder != 0 + ? 1.0 / (m_nextRenderOrder) + : 0; } if (Q_UNLIKELY(debug_render())) timeSorting = timer.restart(); diff --git a/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp b/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp index 1112eca27b..97d7e69407 100644 --- a/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp +++ b/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp @@ -274,7 +274,7 @@ int main(int argc, char **argv) for (int i=0; i<args.length(); ++i) { const QString &a = args.at(i); - if (a == QStringLiteral("--file") && i < args.length() - 1) { + if (a == QLatin1String("--file") && i < args.length() - 1) { qDebug() << "Reading file: " << args.at(i); QFile file(args.at(++i)); if (!file.open(QFile::ReadOnly)) { @@ -282,10 +282,10 @@ int main(int argc, char **argv) return 1; } content = file.readAll(); - } else if (a == QStringLiteral("--selftest")) { + } else if (a == QLatin1String("--selftest")) { qDebug() << "doing a selftest"; content = QByteArray(selftest); - } else if (a == QStringLiteral("--help") || a == QStringLiteral("-h")) { + } else if (a == QLatin1String("--help") || a == QLatin1String("-h")) { qDebug() << "usage:" << endl << " --file [name] A vertex shader file to rewrite" << endl; } diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp index 6572ceb2ce..2ba16e7328 100644 --- a/src/quick/scenegraph/qsgcontext.cpp +++ b/src/quick/scenegraph/qsgcontext.cpp @@ -136,9 +136,9 @@ public: bool distanceFieldAntialiasingDecided; }; -static bool qsg_useConsistentTiming() +bool qsg_useConsistentTiming() { - static int use = -1; + int use = -1; if (use < 0) { use = !qEnvironmentVariableIsEmpty("QSG_FIXED_ANIMATION_STEP") && qgetenv("QSG_FIXED_ANIMATION_STEP") != "no" ? 1 : 0; diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp index b5f149eff7..cd0f77799b 100644 --- a/src/quick/scenegraph/qsgrenderloop.cpp +++ b/src/quick/scenegraph/qsgrenderloop.cpp @@ -67,7 +67,7 @@ QT_BEGIN_NAMESPACE - +extern bool qsg_useConsistentTiming(); extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha); /*! @@ -267,6 +267,10 @@ void QSGRenderLoop::handleContextCreationFailure(QQuickWindow *window, QSGGuiThreadRenderLoop::QSGGuiThreadRenderLoop() : gl(0) { + if (qsg_useConsistentTiming()) { + QUnifiedTimer::instance(true)->setConsistentTiming(true); + qCDebug(QSG_LOG_INFO, "using fixed animation steps"); + } sg = QSGContext::createDefaultContext(); rc = sg->createRenderContext(); } diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp index 9d6e7f3b2a..57468e5799 100644 --- a/src/quick/scenegraph/util/qsgatlastexture.cpp +++ b/src/quick/scenegraph/util/qsgatlastexture.cpp @@ -141,9 +141,9 @@ Atlas::Atlas(const QSize &size) QString *deviceName = static_cast<QString *>(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("AndroidDeviceName")); static bool wrongfullyReportsBgra8888Support = deviceName != 0 - && (deviceName->compare(QStringLiteral("samsung SM-T211"), Qt::CaseInsensitive) == 0 - || deviceName->compare(QStringLiteral("samsung SM-T210"), Qt::CaseInsensitive) == 0 - || deviceName->compare(QStringLiteral("samsung SM-T215"), Qt::CaseInsensitive) == 0); + && (deviceName->compare(QLatin1String("samsung SM-T211"), Qt::CaseInsensitive) == 0 + || deviceName->compare(QLatin1String("samsung SM-T210"), Qt::CaseInsensitive) == 0 + || deviceName->compare(QLatin1String("samsung SM-T215"), Qt::CaseInsensitive) == 0); #else static bool wrongfullyReportsBgra8888Support = false; // The Raspberry Pi (both 1 and 2) GPU refuses framebuffers with BGRA color attachments. diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp index 169f3ebe59..74390334c4 100644 --- a/src/quick/scenegraph/util/qsgtexture.cpp +++ b/src/quick/scenegraph/util/qsgtexture.cpp @@ -720,9 +720,9 @@ void QSGPlainTexture::bind() QString *deviceName = static_cast<QString *>(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("AndroidDeviceName")); static bool wrongfullyReportsBgra8888Support = deviceName != 0 - && (deviceName->compare(QStringLiteral("samsung SM-T211"), Qt::CaseInsensitive) == 0 - || deviceName->compare(QStringLiteral("samsung SM-T210"), Qt::CaseInsensitive) == 0 - || deviceName->compare(QStringLiteral("samsung SM-T215"), Qt::CaseInsensitive) == 0); + && (deviceName->compare(QLatin1String("samsung SM-T211"), Qt::CaseInsensitive) == 0 + || deviceName->compare(QLatin1String("samsung SM-T210"), Qt::CaseInsensitive) == 0 + || deviceName->compare(QLatin1String("samsung SM-T215"), Qt::CaseInsensitive) == 0); #else static bool wrongfullyReportsBgra8888Support = false; #endif diff --git a/src/quick/util/qquickanimator.cpp b/src/quick/util/qquickanimator.cpp index f0d4caf7ab..abae6321b0 100644 --- a/src/quick/util/qquickanimator.cpp +++ b/src/quick/util/qquickanimator.cpp @@ -217,7 +217,8 @@ qreal QQuickAnimator::from() const void QQuickAnimatorPrivate::apply(QQuickAnimatorJob *job, const QString &propertyName, QQuickStateActions &actions, - QQmlProperties &modified) + QQmlProperties &modified, + QObject *defaultTarget) { if (actions.size()) { @@ -249,14 +250,20 @@ void QQuickAnimatorPrivate::apply(QQuickAnimatorJob *job, // the item when a transition is cancelled. action.fromValue = action.toValue; } - } else { + } + + if (modified.isEmpty()) { job->setTarget(target); job->setFrom(from); job->setTo(to); } - if (!job->target() && defaultProperty.object()) - job->setTarget(qobject_cast<QQuickItem *>(defaultProperty.object())); + if (!job->target()) { + if (defaultProperty.object()) + job->setTarget(qobject_cast<QQuickItem *>(defaultProperty.object())); + else + job->setTarget(qobject_cast<QQuickItem *>(defaultTarget)); + } job->setDuration(duration); job->setLoopCount(loopCount); @@ -266,7 +273,7 @@ void QQuickAnimatorPrivate::apply(QQuickAnimatorJob *job, QAbstractAnimationJob *QQuickAnimator::transition(QQuickStateActions &actions, QQmlProperties &modified, TransitionDirection direction, - QObject *) + QObject *defaultTarget) { Q_D(QQuickAnimator); @@ -283,7 +290,7 @@ QAbstractAnimationJob *QQuickAnimator::transition(QQuickStateActions &actions, if (!job) return 0; - d->apply(job, propertyName(), actions, modified); + d->apply(job, propertyName(), actions, modified, defaultTarget); if (!job->target()) { delete job; diff --git a/src/quick/util/qquickanimator_p_p.h b/src/quick/util/qquickanimator_p_p.h index 7a61462762..b176119c70 100644 --- a/src/quick/util/qquickanimator_p_p.h +++ b/src/quick/util/qquickanimator_p_p.h @@ -82,7 +82,7 @@ public: uint isFromDefined : 1; uint isToDefined : 1; - void apply(QQuickAnimatorJob *job, const QString &propertyName, QQuickStateActions &actions, QQmlProperties &modified); + void apply(QQuickAnimatorJob *job, const QString &propertyName, QQuickStateActions &actions, QQmlProperties &modified, QObject *defaultTarget); }; class QQuickRotationAnimatorPrivate : public QQuickAnimatorPrivate diff --git a/src/quick/util/qquickapplication.cpp b/src/quick/util/qquickapplication.cpp index a4e2f0eb0e..5c26b23ff7 100644 --- a/src/quick/util/qquickapplication.cpp +++ b/src/quick/util/qquickapplication.cpp @@ -90,4 +90,9 @@ Qt::ApplicationState QQuickApplication::state() const return QGuiApplication::applicationState(); } +QFont QQuickApplication::font() const +{ + return QGuiApplication::font(); +} + QT_END_NAMESPACE diff --git a/src/quick/util/qquickapplication_p.h b/src/quick/util/qquickapplication_p.h index 971c9a203a..091cb094ed 100644 --- a/src/quick/util/qquickapplication_p.h +++ b/src/quick/util/qquickapplication_p.h @@ -52,6 +52,7 @@ // #include <QtCore/QObject> +#include <QtGui/QFont> #include <qqml.h> #include <QtQml/private/qqmlglobal_p.h> #include <private/qtquickglobal_p.h> @@ -66,6 +67,7 @@ class Q_AUTOTEST_EXPORT QQuickApplication : public QQmlApplication Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection NOTIFY layoutDirectionChanged) Q_PROPERTY(bool supportsMultipleWindows READ supportsMultipleWindows CONSTANT) Q_PROPERTY(Qt::ApplicationState state READ state NOTIFY stateChanged) + Q_PROPERTY(QFont font READ font CONSTANT) public: explicit QQuickApplication(QObject *parent = 0); @@ -74,6 +76,7 @@ public: Qt::LayoutDirection layoutDirection() const; bool supportsMultipleWindows() const; Qt::ApplicationState state() const; + QFont font() const; Q_SIGNALS: void activeChanged(); diff --git a/src/quick/util/qquickfontloader.cpp b/src/quick/util/qquickfontloader.cpp index 64fd458ef0..b7367f3934 100644 --- a/src/quick/util/qquickfontloader.cpp +++ b/src/quick/util/qquickfontloader.cpp @@ -45,14 +45,18 @@ #include <QStringList> #include <QUrl> #include <QDebug> -#include <QNetworkRequest> -#include <QNetworkReply> + #include <QFontDatabase> #include <private/qobject_p.h> #include <qqmlinfo.h> #include <qqmlfile.h> +#ifndef QT_NO_NETWORK +#include <QNetworkRequest> +#include <QNetworkReply> +#endif + #include <QtCore/QCoreApplication> QT_BEGIN_NAMESPACE @@ -66,28 +70,37 @@ Q_OBJECT public: explicit QQuickFontObject(int _id = -1); +#ifndef QT_NO_NETWORK void download(const QUrl &url, QNetworkAccessManager *manager); Q_SIGNALS: void fontDownloaded(const QString&, QQuickFontLoader::Status); +private: + int redirectCount; + QNetworkReply *reply; + private Q_SLOTS: void replyFinished(); +#endif // QT_NO_NETWORK public: int id; -private: - QNetworkReply *reply; - int redirectCount; - Q_DISABLE_COPY(QQuickFontObject) }; QQuickFontObject::QQuickFontObject(int _id) - : QObject(0), id(_id), reply(0), redirectCount(0) {} + : QObject(0) +#ifndef QT_NO_NETWORK + ,redirectCount(0), reply(0) +#endif + ,id(_id) +{ +} +#ifndef QT_NO_NETWORK void QQuickFontObject::download(const QUrl &url, QNetworkAccessManager *manager) { QNetworkRequest req(url); @@ -128,7 +141,7 @@ void QQuickFontObject::replyFinished() reply = 0; } } - +#endif // QT_NO_NETWORK class QQuickFontLoaderPrivate : public QObjectPrivate { @@ -255,6 +268,7 @@ void QQuickFontLoader::setSource(const QUrl &url) } } else { if (!fontLoaderFonts()->map.contains(d->url)) { +#ifndef QT_NO_NETWORK QQuickFontObject *fo = new QQuickFontObject; fontLoaderFonts()->map[d->url] = fo; fo->download(d->url, qmlEngine(this)->networkAccessManager()); @@ -262,13 +276,20 @@ void QQuickFontLoader::setSource(const QUrl &url) emit statusChanged(); QObject::connect(fo, SIGNAL(fontDownloaded(QString,QQuickFontLoader::Status)), this, SLOT(updateFontInfo(QString,QQuickFontLoader::Status))); +#else +// Silently fail if compiled with no_network +#endif } else { QQuickFontObject *fo = fontLoaderFonts()->map[d->url]; if (fo->id == -1) { +#ifndef QT_NO_NETWORK d->status = Loading; emit statusChanged(); QObject::connect(fo, SIGNAL(fontDownloaded(QString,QQuickFontLoader::Status)), this, SLOT(updateFontInfo(QString,QQuickFontLoader::Status))); +#else +// Silently fail if compiled with no_network +#endif } else updateFontInfo(QFontDatabase::applicationFontFamilies(fo->id).at(0), Ready); diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp index d669a7feda..23b2887fac 100644 --- a/src/quick/util/qquickpixmapcache.cpp +++ b/src/quick/util/qquickpixmapcache.cpp @@ -38,7 +38,6 @@ ****************************************************************************/ #include "qquickpixmapcache_p.h" -#include <qqmlnetworkaccessmanagerfactory.h> #include <qquickimageprovider.h> #include <qqmlengine.h> @@ -55,7 +54,6 @@ #include <QCoreApplication> #include <QImageReader> #include <QHash> -#include <QNetworkReply> #include <QPixmapCache> #include <QFile> #include <QThread> @@ -66,10 +64,15 @@ #include <QWaitCondition> #include <QtCore/qdebug.h> #include <private/qobject_p.h> -#include <QSslError> #include <QQmlFile> #include <QMetaMethod> +#ifndef QT_NO_NETWORK +#include <qqmlnetworkaccessmanagerfactory.h> +#include <QNetworkReply> +#include <QSslError> +#endif + #include <private/qquickprofiler_p.h> #define IMAGEREQUEST_MAX_NETWORK_REQUEST_COUNT 8 @@ -203,7 +206,9 @@ private: friend class QQuickPixmapReaderThreadObject; void processJobs(); void processJob(QQuickPixmapReply *, const QUrl &, const QString &, AutoTransform, QQuickImageProvider::ImageType, QQuickImageProvider *); +#ifndef QT_NO_NETWORK void networkRequestDone(QNetworkReply *); +#endif void asyncResponseFinished(QQuickImageResponse *); QList<QQuickPixmapReply*> jobs; @@ -215,10 +220,11 @@ private: QQuickPixmapReaderThreadObject *threadObject; QWaitCondition waitCondition; +#ifndef QT_NO_NETWORK QNetworkAccessManager *networkAccessManager(); QNetworkAccessManager *accessManager; - QHash<QNetworkReply*,QQuickPixmapReply*> networkJobs; +#endif QHash<QQuickImageResponse*,QQuickPixmapReply*> asyncResponses; static int replyDownloadProgress; @@ -343,6 +349,7 @@ QQuickPixmapReply::Event::~Event() delete textureFactory; } +#ifndef QT_NO_NETWORK QNetworkAccessManager *QQuickPixmapReader::networkAccessManager() { if (!accessManager) { @@ -351,6 +358,7 @@ QNetworkAccessManager *QQuickPixmapReader::networkAccessManager() } return accessManager; } +#endif static void maybeRemoveAlpha(QImage *image) { @@ -421,7 +429,10 @@ static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *e } QQuickPixmapReader::QQuickPixmapReader(QQmlEngine *eng) -: QThread(eng), engine(eng), threadObject(0), accessManager(0) +: QThread(eng), engine(eng), threadObject(0) +#ifndef QT_NO_NETWORK +, accessManager(0) +#endif { eventLoopQuitHack = new QObject; eventLoopQuitHack->moveToThread(this); @@ -443,6 +454,7 @@ QQuickPixmapReader::~QQuickPixmapReader() delete reply; } jobs.clear(); +#ifndef QT_NO_NETWORK QList<QQuickPixmapReply*> activeJobs = networkJobs.values() + asyncResponses.values(); foreach (QQuickPixmapReply *reply, activeJobs ) { if (reply->loading) { @@ -450,6 +462,7 @@ QQuickPixmapReader::~QQuickPixmapReader() reply->data = 0; } } +#endif if (threadObject) threadObject->processJobs(); mutex.unlock(); @@ -457,6 +470,7 @@ QQuickPixmapReader::~QQuickPixmapReader() wait(); } +#ifndef QT_NO_NETWORK void QQuickPixmapReader::networkRequestDone(QNetworkReply *reply) { QQuickPixmapReply *job = networkJobs.take(reply); @@ -506,6 +520,7 @@ void QQuickPixmapReader::networkRequestDone(QNetworkReply *reply) // kick off event loop again incase we have dropped below max request count threadObject->processJobs(); } +#endif // QT_NO_NETWORK void QQuickPixmapReader::asyncResponseFinished(QQuickImageResponse *response) { @@ -557,8 +572,10 @@ bool QQuickPixmapReaderThreadObject::event(QEvent *e) void QQuickPixmapReaderThreadObject::networkRequestDone() { +#ifndef QT_NO_NETWORK QNetworkReply *reply = static_cast<QNetworkReply *>(sender()); reader->networkRequestDone(reply); +#endif } void QQuickPixmapReaderThreadObject::asyncResponseFinished() @@ -577,6 +594,7 @@ void QQuickPixmapReader::processJobs() // Clean cancelled jobs if (!cancelled.isEmpty()) { +#ifndef QT_NO_NETWORK for (int i = 0; i < cancelled.count(); ++i) { QQuickPixmapReply *job = cancelled.at(i); QNetworkReply *reply = networkJobs.key(job, 0); @@ -599,6 +617,7 @@ void QQuickPixmapReader::processJobs() job->deleteLater(); } cancelled.clear(); +#endif } if (!jobs.isEmpty()) { @@ -619,7 +638,11 @@ void QQuickPixmapReader::processJobs() usableJob = true; } else { localFile = QQmlFile::urlToLocalFileOrQrc(url); - usableJob = !localFile.isEmpty() || networkJobs.count() < IMAGEREQUEST_MAX_NETWORK_REQUEST_COUNT; + usableJob = !localFile.isEmpty() +#ifndef QT_NO_NETWORK + || networkJobs.count() < IMAGEREQUEST_MAX_NETWORK_REQUEST_COUNT +#endif + ; } @@ -744,6 +767,7 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u runningJob->postReply(errorCode, errorStr, readSize, QQuickTextureFactory::textureFactoryForImage(image)); mutex.unlock(); } else { +#ifndef QT_NO_NETWORK // Network resource QNetworkRequest req(url); req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true); @@ -753,6 +777,9 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u QMetaObject::connect(reply, replyFinished, threadObject, threadNetworkRequestDone); networkJobs.insert(reply, runningJob); +#else +// Silently fail if compiled with no_network +#endif } } } @@ -809,11 +836,13 @@ void QQuickPixmapReader::cancel(QQuickPixmapReply *reply) void QQuickPixmapReader::run() { if (replyDownloadProgress == -1) { +#ifndef QT_NO_NETWORK replyDownloadProgress = QMetaMethod::fromSignal(&QNetworkReply::downloadProgress).methodIndex(); replyFinished = QMetaMethod::fromSignal(&QNetworkReply::finished).methodIndex(); - downloadProgress = QMetaMethod::fromSignal(&QQuickPixmapReply::downloadProgress).methodIndex(); const QMetaObject *ir = &QQuickPixmapReaderThreadObject::staticMetaObject; threadNetworkRequestDone = ir->indexOfSlot("networkRequestDone()"); +#endif + downloadProgress = QMetaMethod::fromSignal(&QQuickPixmapReply::downloadProgress).methodIndex(); } mutex.lock(); @@ -1194,8 +1223,6 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q *ok = true; return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, autoTransform, appliedTransform); } - errorString = QQuickPixmap::tr("Invalid image data: %1").arg(url.toString()); - } else { errorString = QQuickPixmap::tr("Cannot open: %1").arg(url.toString()); } diff --git a/src/quick/util/qquickstate_p.h b/src/quick/util/qquickstate_p.h index 5c33d4b6b5..7d22ca9f8c 100644 --- a/src/quick/util/qquickstate_p.h +++ b/src/quick/util/qquickstate_p.h @@ -64,7 +64,7 @@ class QQuickStateActionEvent; class QQmlBinding; class QQmlExpression; -class QQuickStateAction +class Q_QUICK_PRIVATE_EXPORT QQuickStateAction { public: QQuickStateAction(); diff --git a/src/quickwidgets/quickwidgets.pro b/src/quickwidgets/quickwidgets.pro index ab388ff9d3..87409e31c5 100644 --- a/src/quickwidgets/quickwidgets.pro +++ b/src/quickwidgets/quickwidgets.pro @@ -4,9 +4,6 @@ QT = core-private gui-private qml-private quick-private widgets-private DEFINES += QT_NO_URL_CAST_FROM_STRING QT_NO_INTEGER_EVENT_COORDINATES - -load(qt_module) - HEADERS += \ qquickwidget.h \ qquickwidget_p.h \ @@ -15,5 +12,4 @@ HEADERS += \ SOURCES += \ qquickwidget.cpp - - +load(qt_module) |