From 8141d64527c5e7a1723e2caeeebb0cde4e591207 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sat, 12 Mar 2016 11:34:48 +0100 Subject: qgrayraster: fix UBs involving << with a negative LHS Left-shifts of negative values are undefined in C++. In particular, they don't behave arithmetically. Reported by UBSan: qgrayraster.c:510:19: runtime error: left shift of negative value -1/-42 qgrayraster.c:537:26: runtime error: left shift of negative value -1/-4/-128 qgrayraster.c:538:26: runtime error: left shift of negative value -1/-4/-128 qgrayraster.c:641:28: runtime error: left shift of negative value -1/-42 qgrayraster.c:676:44: runtime error: left shift of negative value -1/-4/-5/-14/-129 qgrayraster.c:807:19: runtime error: left shift of negative value -1/-42 qgrayraster.c:1101:9: runtime error: left shift of negative value -32/-46/-224/-8160 qgrayraster.c:1102:9: runtime error: left shift of negative value -32/-2626 qgrayraster.c:1454:36: runtime error: left shift of negative value -32/-96/-224/-466/-2626/-8160 qgrayraster.c:1535:30: runtime error: left shift of negative value -32/-46/-224/-2626/-8160 Fix by using ordinary multiplication instead, because negative left-hand-side values don't look like they are an error. Change-Id: I2e96de51adb4a030de8a49869ddd98a31dab31b3 Reviewed-by: Allan Sandfeld Jensen --- src/gui/painting/qgrayraster.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/painting/qgrayraster.c b/src/gui/painting/qgrayraster.c index b536028fe3..5ce1895541 100644 --- a/src/gui/painting/qgrayraster.c +++ b/src/gui/painting/qgrayraster.c @@ -202,13 +202,13 @@ #define ONE_PIXEL ( 1L << PIXEL_BITS ) #define PIXEL_MASK ( -1L << PIXEL_BITS ) #define TRUNC( x ) ( (TCoord)( (x) >> PIXEL_BITS ) ) -#define SUBPIXELS( x ) ( (TPos)(x) << PIXEL_BITS ) +#define SUBPIXELS( x ) ( (TPos)(x) * ( 1 << PIXEL_BITS ) ) #define FLOOR( x ) ( (x) & -ONE_PIXEL ) #define CEILING( x ) ( ( (x) + ONE_PIXEL - 1 ) & -ONE_PIXEL ) #define ROUND( x ) ( ( (x) + ONE_PIXEL / 2 ) & -ONE_PIXEL ) #if PIXEL_BITS >= 6 -#define UPSCALE( x ) ( (x) << ( PIXEL_BITS - 6 ) ) +#define UPSCALE( x ) ( (x) * ( 1 << ( PIXEL_BITS - 6 ) ) ) #define DOWNSCALE( x ) ( (x) >> ( PIXEL_BITS - 6 ) ) #else #define UPSCALE( x ) ( (x) >> ( 6 - PIXEL_BITS ) ) -- cgit v1.2.3 From 8a33077853e851e2795476cd502444c2d8535f9a Mon Sep 17 00:00:00 2001 From: David Faure Date: Thu, 28 Jul 2016 12:25:59 +0200 Subject: QUrl: fix resolved() for data URLs They look relative because the path doesn't start with a '/' but they have a scheme so they shouldn't be combined as if it was one absolute and one relative URL. [ChangeLog][QtCore][QUrl] QUrl::resolved() no longer treats a URL with a scheme as a relative URL if it matches this URL's scheme. This special casing was incompatible with RFC 3986 and broke resolving data: URLs, for instance. Change-Id: I3758d3a2141cea7c6d13514243eb8dee5d510dd0 Reviewed-by: Thiago Macieira --- src/corelib/io/qurl.cpp | 3 +-- tests/auto/corelib/io/qurl/tst_qurl.cpp | 16 +++++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index 2672de24f2..1fe529d48d 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -3167,8 +3167,7 @@ QUrl QUrl::resolved(const QUrl &relative) const if (!relative.d) return *this; QUrl t; - // be non strict and allow scheme in relative url - if (!relative.d->scheme.isEmpty() && relative.d->scheme != d->scheme) { + if (!relative.d->scheme.isEmpty()) { t = relative; t.detach(); } else { diff --git a/tests/auto/corelib/io/qurl/tst_qurl.cpp b/tests/auto/corelib/io/qurl/tst_qurl.cpp index eb29646053..8f99047df3 100644 --- a/tests/auto/corelib/io/qurl/tst_qurl.cpp +++ b/tests/auto/corelib/io/qurl/tst_qurl.cpp @@ -903,13 +903,11 @@ void tst_QUrl::resolving_data() // Some parsers allow the scheme name to be present in a relative URI // reference if it is the same as the base URI scheme. This is - // considered to be a loophole in prior specifications of partial URI - // [RFC1630]. Its use should be avoided, but is allowed for backward - // compatibility. - // For strict parsers : -// QTest::newRow("http:g [for strict parsers]") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("http:g") << QString::fromLatin1("http:g"); - // For backward compatibility : - QTest::newRow("http:g [for backward compatibility]") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("http:g") << QString::fromLatin1("http://a/b/c/g"); + // considered to be a loophole in prior specifications of partial URI [RFC1630], + //QTest::newRow("http:g [for backward compatibility]") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("http:g") << QString::fromLatin1("http://a/b/c/g"); + // However we don't do that anymore, as per RFC3986, in order for the data:subpage testcase below to work. + QTest::newRow("http:g") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("http:g") << QString::fromLatin1("http:g"); + QTest::newRow("data:subpage") << QString::fromLatin1("data:text/plain, main page") << QString::fromLatin1("data:text/plain, subpage") << QString::fromLatin1("data:text/plain, subpage"); // Resolve relative with relative QTest::newRow("../a (1)") << QString::fromLatin1("b") << QString::fromLatin1("../a") << QString::fromLatin1("a"); @@ -921,6 +919,10 @@ void tst_QUrl::resolving_data() QTest::newRow("../a (6)") << QString::fromLatin1("/b/a") << QString::fromLatin1("../a") << QString::fromLatin1("/a"); QTest::newRow("../a (7)") << QString::fromLatin1("/b/c/a") << QString::fromLatin1("../a") << QString::fromLatin1("/b/a"); QTest::newRow("../a (8)") << QString::fromLatin1("/b") << QString::fromLatin1("/a") << QString::fromLatin1("/a"); + + // More tests from KDE + QTest::newRow("brackets") << QString::fromLatin1("http://www.calorieking.com/personal/diary/") << QString::fromLatin1("/personal/diary/rpc.php?C=jsrs1&F=getDiaryDay&P0=[2006-3-8]&U=1141858921458") << QString::fromLatin1("http://www.calorieking.com/personal/diary/rpc.php?C=jsrs1&F=getDiaryDay&P0=[2006-3-8]&U=1141858921458"); + QTest::newRow("javascript")<< QString::fromLatin1("http://www.youtube.com/?v=JvOSnRD5aNk") << QString::fromLatin1("javascript:window.location+\"__flashplugin_unique__\"") << QString::fromLatin1("javascript:window.location+%22__flashplugin_unique__%22"); } void tst_QUrl::resolving() -- cgit v1.2.3 From f0685992a3412b059a0952ac591f40856ffffb6f Mon Sep 17 00:00:00 2001 From: Konstantin Shegunov Date: Sun, 24 Jul 2016 22:14:49 +0300 Subject: Docs changed to reflect that valueName is required with value parsing When the option expects a value the valueName parameter of the constructor isn't optional; it must be set. This requirement is made explicit in the documentation. Task-number: QTBUG-54855 Change-Id: I190884aff2fa8e96bc5c5e82cdfed85be761d6e3 Reviewed-by: Thiago Macieira Reviewed-by: David Faure --- src/corelib/tools/qcommandlineoption.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corelib/tools/qcommandlineoption.cpp b/src/corelib/tools/qcommandlineoption.cpp index 8c0ba8cb2b..93d20577c3 100644 --- a/src/corelib/tools/qcommandlineoption.cpp +++ b/src/corelib/tools/qcommandlineoption.cpp @@ -144,7 +144,7 @@ QCommandLineOption::QCommandLineOption(const QStringList &names) The description is set to \a description. It is customary to add a "." at the end of the description. - In addition, the \a valueName can be set if the option expects a value. + In addition, the \a valueName needs to be set if the option expects a value. The default value for the option is set to \a defaultValue. In Qt versions before 5.4, this constructor was \c explicit. In Qt 5.4 @@ -180,7 +180,7 @@ QCommandLineOption::QCommandLineOption(const QString &name, const QString &descr The description is set to \a description. It is customary to add a "." at the end of the description. - In addition, the \a valueName can be set if the option expects a value. + In addition, the \a valueName needs to be set if the option expects a value. The default value for the option is set to \a defaultValue. In Qt versions before 5.4, this constructor was \c explicit. In Qt 5.4 -- cgit v1.2.3 From 068ce0b10c700df35ce10dee71e76d24a23694f5 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sat, 12 Mar 2016 11:34:48 +0100 Subject: QRasterizer: fix UBs involving << with a negative LHS Left-shifts of negative values are undefined in C++. In particular, they don't behave arithmetically. Reported by UBSan: qrasterizer.cpp:609:48: runtime error: left shift of negative value -640/-2240 qrasterizer.cpp:982:38: runtime error: left shift of negative value -2 Fix by using ordinary multiplication instead, because negative left-hand-side values don't look like they are an error. No errors were actually reported for a.y << 10, but I changed it nonetheless, since all a missing error means is that the test data didn't excercise this code path with negative Y values. Change-Id: I1fa9deca263f12206a3f7eab6ad875fc3242269d Reviewed-by: Allan Sandfeld Jensen --- src/gui/painting/qrasterizer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/painting/qrasterizer.cpp b/src/gui/painting/qrasterizer.cpp index 34d72bf493..9411a20000 100644 --- a/src/gui/painting/qrasterizer.cpp +++ b/src/gui/painting/qrasterizer.cpp @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE typedef int Q16Dot16; #define Q16Dot16ToFloat(i) ((i)/65536.) #define FloatToQ16Dot16(i) (int)((i) * 65536.) -#define IntToQ16Dot16(i) ((i) << 16) +#define IntToQ16Dot16(i) ((i) * (1 << 16)) #define Q16Dot16ToInt(i) ((i) >> 16) #define Q16Dot16Factor 65536 @@ -606,7 +606,7 @@ void QScanConverter::mergeLine(QT_FT_Vector a, QT_FT_Vector b) int iBottom = qMin(m_bottom, int((b.y - 32 - rounding) >> 6)); if (iTop <= iBottom) { - Q16Dot16 aFP = Q16Dot16Factor/2 + (a.x << 10) - rounding; + Q16Dot16 aFP = Q16Dot16Factor/2 + (a.x * (1 << 10)) - rounding; if (b.x == a.x) { Line line = { qBound(m_leftFP, aFP, m_rightFP), 0, iTop, iBottom, winding }; @@ -618,7 +618,7 @@ void QScanConverter::mergeLine(QT_FT_Vector a, QT_FT_Vector b) Q16Dot16 xFP = aFP + Q16Dot16Multiply(slopeFP, IntToQ16Dot16(iTop) - + Q16Dot16Factor/2 - (a.y << 10)); + + Q16Dot16Factor/2 - (a.y * (1 << 10))); if (clip(xFP, iTop, iBottom, slopeFP, m_leftFP, winding)) return; -- cgit v1.2.3 From 8740a87841689c97dc92f7600b33c260e4bf7f2c Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sat, 30 Jul 2016 22:20:26 +0300 Subject: QAbstractItemView: Fix UB (invalid downcast) Just use QWidgetPrivate::get() instead. Fixes UBSan error: qabstractitemview.cpp:3814:61: runtime error: downcast of address 0x2b859001aa70 which does not point to an object of type 'QAbstractItemView' 0x2b859001aa70: note: object is of type 'QWidget' Change-Id: I0460fd8a0681e122d440755ebf07018d273b93f8 Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/widgets/itemviews/qabstractitemview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp index f31f2f5256..cb40eae9a2 100644 --- a/src/widgets/itemviews/qabstractitemview.cpp +++ b/src/widgets/itemviews/qabstractitemview.cpp @@ -3821,7 +3821,7 @@ void QAbstractItemView::doAutoScroll() int horizontalValue = horizontalScroll->value(); QPoint pos = d->viewport->mapFromGlobal(QCursor::pos()); - QRect area = static_cast(d->viewport)->d_func()->clipRect(); // access QWidget private by bending C++ rules + QRect area = QWidgetPrivate::get(d->viewport)->clipRect(); // do the scrolling if we are in the scroll margins if (pos.y() - area.top() < margin) -- cgit v1.2.3 From b37539442f58fc7c0ba54380f07b132a15a037e8 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sat, 30 Jul 2016 09:27:37 +0300 Subject: QColor: Fix UB (left shift of negative number) If hex2int(const char*) is called with invalid input, it is expected to return a negative value. However, it didn't check the return value of h2i() before attempting a left-shift on it, leading to UB when the first digit was already invalid. UBSan agrees: qcolor_p.cpp:55:23: runtime error: left shift of negative value -1 This is particularly worrisome as the function can be called with unsanitized input. Fix by checking each value for non-negativity, returning -1 early when errors are detected. Also port to QtMiscUtils::fromHex() and add some docs. Change-Id: I33dbc157ffb4fbfba27113a0a008eef35c1055f7 Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/gui/painting/qcolor_p.cpp | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/gui/painting/qcolor_p.cpp b/src/gui/painting/qcolor_p.cpp index 4ebe74ce4f..b63c34aab7 100644 --- a/src/gui/painting/qcolor_p.cpp +++ b/src/gui/painting/qcolor_p.cpp @@ -34,31 +34,37 @@ #include "qglobal.h" #include "qrgb.h" #include "qstringlist.h" +#include "private/qtools_p.h" #include QT_BEGIN_NAMESPACE -static inline int h2i(char hex) -{ - if (hex >= '0' && hex <= '9') - return hex - '0'; - if (hex >= 'a' && hex <= 'f') - return hex - 'a' + 10; - if (hex >= 'A' && hex <= 'F') - return hex - 'A' + 10; - return -1; -} - +/*! + \internal + If s[0..1] is a valid hex number, returns its integer value, + otherwise returns -1. + */ static inline int hex2int(const char *s) { - return (h2i(s[0]) << 4) | h2i(s[1]); + const int hi = QtMiscUtils::fromHex(s[0]); + if (hi < 0) + return -1; + const int lo = QtMiscUtils::fromHex(s[1]); + if (lo < 0) + return -1; + return (hi << 4) | lo; } +/*! + \internal + If s is a valid hex digit, returns its integer value, + multiplied by 0x11, otherwise returns -1. + */ static inline int hex2int(char s) { - int h = h2i(s); - return (h << 4) | h; + const int h = QtMiscUtils::fromHex(s); + return h < 0 ? h : (h << 4) | h; } bool qt_get_hex_rgb(const char *name, QRgb *rgb) -- cgit v1.2.3 From 4ac28eda8edaff06ee7cb310108bfb9d9f1984ff Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sun, 31 Jul 2016 07:40:41 +0300 Subject: QTreeWidget: Fix UB (member call) Before actually deleting QTreeWidgetItems from QTree{Model,Widget{,Item}} dtors, their 'view' members need to be set to nullptr, lest they attempt to delist themselves from the list of top-level items. For the QTreeModel::headerItem, this was forgottten. Found by UBSan: qtreewidget.cpp:1488:70: runtime error: member call on address 0x7ffd843dd470 which does not point to an object of type 'QAbstractItemView' 0x7ffd843dd470: note: object is of type 'QWidget' #0 0x2b83d5b48323 in QTreeWidgetItem::~QTreeWidgetItem() src/widgets/itemviews/qtreewidget.cpp:1488 #1 0x2b83d5b48860 in QTreeWidgetItem::~QTreeWidgetItem() src/widgets/itemviews/qtreewidget.cpp:1535 #2 0x2b83d5b41659 in QTreeModel::~QTreeModel() src/widgets/itemviews/qtreewidget.cpp:143 #3 0x2b83d5b41bc0 in QTreeModel::~QTreeModel() src/widgets/itemviews/qtreewidget.cpp:146 #4 0x2b83df220747 in QObjectPrivate::deleteChildren() src/corelib/kernel/qobject.cpp:2010 #5 0x2b83d4603dd0 in QWidget::~QWidget() src/widgets/kernel/qwidget.cpp:1675 #6 0x2b83d4d76066 in QFrame::~QFrame() src/widgets/widgets/qframe.cpp:256 #7 0x2b83d5270442 in QAbstractScrollArea::~QAbstractScrollArea() src/widgets/widgets/qabstractscrollarea.cpp:575 #8 0x2b83d5733eb9 in QAbstractItemView::~QAbstractItemView() src/widgets/itemviews/qabstractitemview.cpp:617 #9 0x2b83d598b216 in QTreeView::~QTreeView() src/widgets/itemviews/qtreeview.cpp:206 #10 0x2b83d5b218b6 in QTreeWidget::~QTreeWidget() src/widgets/itemviews/qtreewidget.cpp:2549 #11 0x4eef42 in tst_QTreeWidgetItemIterator::updateIfModifiedFromWidget() tests/auto/widgets/itemviews/qtreewidgetitemiterator/tst_qtreewidgetitemiterator.cpp:1089 Change-Id: I57c277adee8c99eb07b274d6d8ea1f6fbf3575be Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/widgets/itemviews/qtreewidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/widgets/itemviews/qtreewidget.cpp b/src/widgets/itemviews/qtreewidget.cpp index f33dd6af17..e0f6a3d5d1 100644 --- a/src/widgets/itemviews/qtreewidget.cpp +++ b/src/widgets/itemviews/qtreewidget.cpp @@ -140,6 +140,7 @@ QTreeModel::QTreeModel(QTreeModelPrivate &dd, QTreeWidget *parent) QTreeModel::~QTreeModel() { clear(); + headerItem->view = Q_NULLPTR; delete headerItem; rootItem->view = 0; delete rootItem; -- cgit v1.2.3 From b55221cf50dde1c71d0a63380f63475f90c79a0b Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sun, 31 Jul 2016 09:04:07 +0300 Subject: Fix UB (invalid enum value) in tst_QTreeView As reported by UBSan: tst_qtreeview.cpp:663:5: runtime error: load of value 4294967295, which is not a valid value for type 'DragDropMode' Instead of abusing -1 to indicate to not set the dragDropMode, use a separate boolean field in tha data. Change-Id: I13e7539c858f3b2462d57d660062ef3cb7aec61b Reviewed-by: Olivier Goffart (Woboq GmbH) --- .../widgets/itemviews/qtreeview/tst_qtreeview.cpp | 62 +++++++++++----------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp index ea85c8e057..bd6939b977 100644 --- a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp +++ b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp @@ -669,33 +669,34 @@ void tst_QTreeView::dragDropModeFromDragEnabledAndAcceptDrops_data() QTest::addColumn("dragEnabled"); QTest::addColumn("acceptDrops"); QTest::addColumn("dragDropMode"); - QTest::addColumn("setBehavior"); - - QTest::newRow("NoDragDrop -1") << false << false << QAbstractItemView::NoDragDrop << QAbstractItemView::DragDropMode(-1); - QTest::newRow("NoDragDrop 0") << false << false << QAbstractItemView::NoDragDrop << QAbstractItemView::NoDragDrop; - QTest::newRow("NoDragDrop 1") << false << false << QAbstractItemView::NoDragDrop << QAbstractItemView::DragOnly; - QTest::newRow("NoDragDrop 2") << false << false << QAbstractItemView::NoDragDrop << QAbstractItemView::DropOnly; - QTest::newRow("NoDragDrop 3") << false << false << QAbstractItemView::NoDragDrop << QAbstractItemView::DragDrop; - QTest::newRow("NoDragDrop 4") << false << false << QAbstractItemView::NoDragDrop << QAbstractItemView::InternalMove; - QTest::newRow("DragOnly -1") << true << false << QAbstractItemView::DragOnly << QAbstractItemView::DragDropMode(-1); - QTest::newRow("DragOnly 0") << true << false << QAbstractItemView::DragOnly << QAbstractItemView::NoDragDrop; - QTest::newRow("DragOnly 1") << true << false << QAbstractItemView::DragOnly << QAbstractItemView::DragOnly; - QTest::newRow("DragOnly 2") << true << false << QAbstractItemView::DragOnly << QAbstractItemView::DropOnly; - QTest::newRow("DragOnly 3") << true << false << QAbstractItemView::DragOnly << QAbstractItemView::DragDrop; - QTest::newRow("DragOnly 4") << true << false << QAbstractItemView::DragOnly << QAbstractItemView::InternalMove; - QTest::newRow("DropOnly -1") << false << true << QAbstractItemView::DropOnly << QAbstractItemView::DragDropMode(-1); - QTest::newRow("DropOnly 0") << false << true << QAbstractItemView::DropOnly << QAbstractItemView::NoDragDrop; - QTest::newRow("DropOnly 1") << false << true << QAbstractItemView::DropOnly << QAbstractItemView::DragOnly; - QTest::newRow("DropOnly 2") << false << true << QAbstractItemView::DropOnly << QAbstractItemView::DropOnly; - QTest::newRow("DropOnly 3") << false << true << QAbstractItemView::DropOnly << QAbstractItemView::DragDrop; - QTest::newRow("DropOnly 4") << false << true << QAbstractItemView::DropOnly << QAbstractItemView::InternalMove; - QTest::newRow("DragDrop -1") << true << true << QAbstractItemView::DragDrop << QAbstractItemView::DragDropMode(-1); - QTest::newRow("DragDrop 0") << true << true << QAbstractItemView::DragDrop << QAbstractItemView::DragDropMode(-1); - QTest::newRow("DragDrop 1") << true << true << QAbstractItemView::DragDrop << QAbstractItemView::NoDragDrop; - QTest::newRow("DragDrop 2") << true << true << QAbstractItemView::DragDrop << QAbstractItemView::DragOnly; - QTest::newRow("DragDrop 3") << true << true << QAbstractItemView::DragDrop << QAbstractItemView::DropOnly; - QTest::newRow("DragDrop 4") << true << true << QAbstractItemView::DragDrop << QAbstractItemView::DragDrop; - QTest::newRow("DragDrop 5") << true << true << QAbstractItemView::InternalMove << QAbstractItemView::InternalMove; + QTest::addColumn("setBehavior"); + QTest::addColumn("behavior"); + + QTest::newRow("NoDragDrop -1") << false << false << QAbstractItemView::NoDragDrop << false << QAbstractItemView::DragDropMode(); + QTest::newRow("NoDragDrop 0") << false << false << QAbstractItemView::NoDragDrop << true << QAbstractItemView::NoDragDrop; + QTest::newRow("NoDragDrop 1") << false << false << QAbstractItemView::NoDragDrop << true << QAbstractItemView::DragOnly; + QTest::newRow("NoDragDrop 2") << false << false << QAbstractItemView::NoDragDrop << true << QAbstractItemView::DropOnly; + QTest::newRow("NoDragDrop 3") << false << false << QAbstractItemView::NoDragDrop << true << QAbstractItemView::DragDrop; + QTest::newRow("NoDragDrop 4") << false << false << QAbstractItemView::NoDragDrop << true << QAbstractItemView::InternalMove; + QTest::newRow("DragOnly -1") << true << false << QAbstractItemView::DragOnly << false << QAbstractItemView::DragDropMode(); + QTest::newRow("DragOnly 0") << true << false << QAbstractItemView::DragOnly << true << QAbstractItemView::NoDragDrop; + QTest::newRow("DragOnly 1") << true << false << QAbstractItemView::DragOnly << true << QAbstractItemView::DragOnly; + QTest::newRow("DragOnly 2") << true << false << QAbstractItemView::DragOnly << true << QAbstractItemView::DropOnly; + QTest::newRow("DragOnly 3") << true << false << QAbstractItemView::DragOnly << true << QAbstractItemView::DragDrop; + QTest::newRow("DragOnly 4") << true << false << QAbstractItemView::DragOnly << true << QAbstractItemView::InternalMove; + QTest::newRow("DropOnly -1") << false << true << QAbstractItemView::DropOnly << false << QAbstractItemView::DragDropMode(); + QTest::newRow("DropOnly 0") << false << true << QAbstractItemView::DropOnly << true << QAbstractItemView::NoDragDrop; + QTest::newRow("DropOnly 1") << false << true << QAbstractItemView::DropOnly << true << QAbstractItemView::DragOnly; + QTest::newRow("DropOnly 2") << false << true << QAbstractItemView::DropOnly << true << QAbstractItemView::DropOnly; + QTest::newRow("DropOnly 3") << false << true << QAbstractItemView::DropOnly << true << QAbstractItemView::DragDrop; + QTest::newRow("DropOnly 4") << false << true << QAbstractItemView::DropOnly << true << QAbstractItemView::InternalMove; + QTest::newRow("DragDrop -1") << true << true << QAbstractItemView::DragDrop << false << QAbstractItemView::DragDropMode(); + QTest::newRow("DragDrop 0") << true << true << QAbstractItemView::DragDrop << false << QAbstractItemView::DragDropMode(); + QTest::newRow("DragDrop 1") << true << true << QAbstractItemView::DragDrop << true << QAbstractItemView::NoDragDrop; + QTest::newRow("DragDrop 2") << true << true << QAbstractItemView::DragDrop << true << QAbstractItemView::DragOnly; + QTest::newRow("DragDrop 3") << true << true << QAbstractItemView::DragDrop << true << QAbstractItemView::DropOnly; + QTest::newRow("DragDrop 4") << true << true << QAbstractItemView::DragDrop << true << QAbstractItemView::DragDrop; + QTest::newRow("DragDrop 5") << true << true << QAbstractItemView::InternalMove << true << QAbstractItemView::InternalMove; } void tst_QTreeView::dragDropModeFromDragEnabledAndAcceptDrops() @@ -703,13 +704,14 @@ void tst_QTreeView::dragDropModeFromDragEnabledAndAcceptDrops() QFETCH(bool, acceptDrops); QFETCH(bool, dragEnabled); QFETCH(QAbstractItemView::DragDropMode, dragDropMode); - QFETCH(QAbstractItemView::DragDropMode, setBehavior); + QFETCH(bool, setBehavior); + QFETCH(QAbstractItemView::DragDropMode, behavior); QTreeView view; QCOMPARE(view.dragDropMode(), QAbstractItemView::NoDragDrop); - if (setBehavior != QAbstractItemView::DragDropMode(-1)) - view.setDragDropMode(setBehavior); + if (setBehavior) + view.setDragDropMode(behavior); view.setAcceptDrops(acceptDrops); view.setDragEnabled(dragEnabled); -- cgit v1.2.3 From 3f1048cca783749c7da9a9f8b3a61959ed35a0de Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Thu, 28 Jul 2016 13:41:43 +0200 Subject: Android: Fix CJK text with Android 7.0 In Android 7, some fonts are packed in .ttc files. We fix this simply by including them when populating the font database. Freetype supports this and in fact, QBasicFontDatabase::populateFontDatabase() also adds *.ttc. [ChangeLog][Android] Fixed CJK font resolution on Android 7. Task-number: QTBUG-53511 Change-Id: Iebe51b0e6ba2d6987693306cd9a12013ce886b58 Reviewed-by: BogDan Vatra --- src/plugins/platforms/android/qandroidplatformfontdatabase.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp b/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp index 5725f5793e..86d50f487b 100644 --- a/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp +++ b/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp @@ -54,7 +54,8 @@ void QAndroidPlatformFontDatabase::populateFontDatabase() QStringList nameFilters; nameFilters << QLatin1String("*.ttf") - << QLatin1String("*.otf"); + << QLatin1String("*.otf") + << QLatin1String("*.ttc"); foreach (const QFileInfo &fi, dir.entryInfoList(nameFilters, QDir::Files)) { const QByteArray file = QFile::encodeName(fi.absoluteFilePath()); -- cgit v1.2.3 From 6f423555eba55ccdf7287071e10576bc1b687fd2 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 1 Aug 2016 13:39:53 +0200 Subject: REG: Fix unwanted cache flush in Freetype engine The Freetype cache was almost completely disabled by 134c6db8587a8ce156d4fa31ffa62605821851b2 because after that change, the lockedAlphaMapForGlyph() function would no longer cut off early for empty glyphs like spaces, but rather go through all alpha map functions before it realized that there was nothing to render. This would in turn invalidate the cache for every empty glyph, causing all glyphs to be rerendered for every isolated word. This change adds back a cut off. This is only needed in the lockedAlphaMapForGlyph() function, since the superclass implementation of the other alpha map functions already contains a cut off for width/height == 0. [ChangeLog][Qt Gui][Text] Fixed a performance regression in Freetype engine that was introduced in Qt 5.5. Change-Id: I381285939909e99cc5fb5f3497fecf9fa871f29a Task-number: QTBUG-49452 Reviewed-by: Simon Hausmann --- src/gui/text/qfontengine_ft.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp index 4de41dfa99..7c878da27f 100644 --- a/src/gui/text/qfontengine_ft.cpp +++ b/src/gui/text/qfontengine_ft.cpp @@ -1716,7 +1716,7 @@ glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixe static inline QImage alphaMapFromGlyphData(QFontEngineFT::Glyph *glyph, QFontEngine::GlyphFormat glyphFormat) { - if (glyph == Q_NULLPTR) + if (glyph == Q_NULLPTR || glyph->height == 0 || glyph->width == 0) return QImage(); QImage::Format format = QImage::Format_Invalid; @@ -1764,11 +1764,15 @@ QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixe currentlyLockedAlphaMap = alphaMapFromGlyphData(glyph, neededFormat); + const bool glyphHasGeometry = glyph != Q_NULLPTR && glyph->height != 0 && glyph->width != 0; if (!cacheEnabled && glyph != &emptyGlyph) { currentlyLockedAlphaMap = currentlyLockedAlphaMap.copy(); delete glyph; } + if (!glyphHasGeometry) + return Q_NULLPTR; + if (currentlyLockedAlphaMap.isNull()) return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t, offset); -- cgit v1.2.3 From 49c892328223dfa2502b462d8e5e8e181f4f6cd5 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Mon, 25 Jul 2016 13:24:59 +0200 Subject: QSortFilterProxyModel: Don't forward the hint from source's layoutChanged signal We can't forward a VerticalSortHint or HorizontalSortHint hint, because we might be filtering extra items. The documentation of QAbstractItemModel::LayoutChangeHint states: Note that VerticalSortHint and HorizontalSortHint carry the meaning that items are being moved within the same parent, not moved to a different parent in the model, and not filtered out or in. And some of the views rely on this assumption (QQmlDelegateModel for example) What happens in the test is the following: - 'model' emit the dataChanged signal when its data is changed. - 'proxi1' QSortFilterProxyModelPrivate::_q_sourceDataChanged does not forward the dataChanged signal imediatly, it will instead first re-sort the model and call layoutAboutToBeChanged / layouChanged with the VerticalSortHint - 'proxy2' would forward the layoutAboutToBeChanged with the hint, but in QSortFilterProxyModelPrivate::_q_sourceLayoutChanged, it will redo the mapping which will cause the changed data to be filtered. So proxy2 can't forward the VerticalSortHint as it removed rows in the process. Change-Id: I20b6983e9d18bf7509fe6144c74f37d24e4a18c2 Reviewed-by: Tobias Koenig Reviewed-by: David Faure --- src/corelib/itemmodels/qsortfilterproxymodel.cpp | 6 ++- .../tst_qsortfilterproxymodel.cpp | 52 ++++++++++++++++++++++ 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/corelib/itemmodels/qsortfilterproxymodel.cpp b/src/corelib/itemmodels/qsortfilterproxymodel.cpp index 0771fd0e30..f264ad015d 100644 --- a/src/corelib/itemmodels/qsortfilterproxymodel.cpp +++ b/src/corelib/itemmodels/qsortfilterproxymodel.cpp @@ -1322,6 +1322,7 @@ void QSortFilterProxyModelPrivate::_q_sourceReset() void QSortFilterProxyModelPrivate::_q_sourceLayoutAboutToBeChanged(const QList &sourceParents, QAbstractItemModel::LayoutChangeHint hint) { Q_Q(QSortFilterProxyModel); + Q_UNUSED(hint); // We can't forward Hint because we might filter additional rows or columns saved_persistent_indexes.clear(); QList parents; @@ -1340,7 +1341,7 @@ void QSortFilterProxyModelPrivate::_q_sourceLayoutAboutToBeChanged(const QListlayoutAboutToBeChanged(parents, hint); + emit q->layoutAboutToBeChanged(parents); if (persistent.indexes.isEmpty()) return; @@ -1350,6 +1351,7 @@ void QSortFilterProxyModelPrivate::_q_sourceLayoutAboutToBeChanged(const QList &sourceParents, QAbstractItemModel::LayoutChangeHint hint) { Q_Q(QSortFilterProxyModel); + Q_UNUSED(hint); // We can't forward Hint because we might filter additional rows or columns // Optimize: We only actually have to clear the mapping related to the contents of // sourceParents, not everything. @@ -1379,7 +1381,7 @@ void QSortFilterProxyModelPrivate::_q_sourceLayoutChanged(const QListlayoutChanged(parents, hint); + emit q->layoutChanged(parents); } void QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeInserted( diff --git a/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp b/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp index 0302ae5cbf..5928ee8688 100644 --- a/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp +++ b/tests/auto/corelib/itemmodels/qsortfilterproxymodel/tst_qsortfilterproxymodel.cpp @@ -148,6 +148,7 @@ private slots: void noMapAfterSourceDelete(); void forwardDropApi(); void canDropMimeData(); + void filterHint(); protected: void buildHierarchy(const QStringList &data, QAbstractItemModel *model); @@ -3804,6 +3805,12 @@ void tst_QSortFilterProxyModel::moveSourceRows() QCOMPARE(filterBeforeParents.size(), 1); QCOMPARE(filterAfterParents.size(), 1); + QCOMPARE( + filterBeforeParentLayoutSpy.first().at(1).value(), + QAbstractItemModel::NoLayoutChangeHint); + QCOMPARE(filterAfterParentLayoutSpy.first().at(1).value(), + QAbstractItemModel::NoLayoutChangeHint); + QCOMPARE(filterBothBeforeParentLayoutSpy.size(), 0); QCOMPARE(filterBothAfterParentLayoutSpy.size(), 0); } @@ -4124,5 +4131,50 @@ void tst_QSortFilterProxyModel::resortingDoesNotBreakTreeModels() QCOMPARE(proxy.rowCount(pi1), 1); } +void tst_QSortFilterProxyModel::filterHint() +{ + // test that a filtering model does not emit layoutChanged with a hint + QStringListModel model(QStringList() << "one" + << "two" + << "three" + << "four" + << "five" + << "six"); + QSortFilterProxyModel proxy1; + proxy1.setSourceModel(&model); + proxy1.setSortRole(Qt::DisplayRole); + proxy1.setDynamicSortFilter(true); + proxy1.sort(0); + + QSortFilterProxyModel proxy2; + proxy2.setSourceModel(&proxy1); + proxy2.setFilterRole(Qt::DisplayRole); + proxy2.setFilterRegExp("^[^ ]*$"); + proxy2.setDynamicSortFilter(true); + + QSignalSpy proxy1BeforeSpy(&proxy1, &QSortFilterProxyModel::layoutAboutToBeChanged); + QSignalSpy proxy1AfterSpy(&proxy1, &QSortFilterProxyModel::layoutChanged); + QSignalSpy proxy2BeforeSpy(&proxy2, &QSortFilterProxyModel::layoutAboutToBeChanged); + QSignalSpy proxy2AfterSpy(&proxy2, &QSortFilterProxyModel::layoutChanged); + + model.setData(model.index(2), QStringLiteral("modified three"), Qt::DisplayRole); + + // The first proxy was re-sorted as one item as changed. + QCOMPARE(proxy1BeforeSpy.size(), 1); + QCOMPARE(proxy1BeforeSpy.first().at(1).value(), + QAbstractItemModel::VerticalSortHint); + QCOMPARE(proxy1AfterSpy.size(), 1); + QCOMPARE(proxy1AfterSpy.first().at(1).value(), + QAbstractItemModel::VerticalSortHint); + + // But the second proxy must not have the VerticalSortHint since an item was filtered + QCOMPARE(proxy2BeforeSpy.size(), 1); + QCOMPARE(proxy2BeforeSpy.first().at(1).value(), + QAbstractItemModel::NoLayoutChangeHint); + QCOMPARE(proxy2AfterSpy.size(), 1); + QCOMPARE(proxy2AfterSpy.first().at(1).value(), + QAbstractItemModel::NoLayoutChangeHint); +} + QTEST_MAIN(tst_QSortFilterProxyModel) #include "tst_qsortfilterproxymodel.moc" -- cgit v1.2.3 From d38f86e50b01c6dd60f5a97355031e08d6a47d18 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sat, 30 Jul 2016 09:36:04 +0300 Subject: QColor: remove 158 avoidable relocations Instead of storing a pointer to a string, store the string in the RGBData struct. It's not as efficient as in other such cases, because one string is particularly long, but it's still more than acceptable. Text size increases slightly, but data size decreases a lot (can't say by how much, exactly, as I'm on a UBSan build). Change-Id: I1df2985fd1ebfccd84b48315d8d319dd9e25c8e7 Reviewed-by: Gunnar Sletta --- src/gui/painting/qcolor_p.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/painting/qcolor_p.cpp b/src/gui/painting/qcolor_p.cpp index b63c34aab7..2b9ef6030e 100644 --- a/src/gui/painting/qcolor_p.cpp +++ b/src/gui/painting/qcolor_p.cpp @@ -130,7 +130,7 @@ bool qt_get_hex_rgb(const QChar *str, int len, QRgb *rgb) #define rgb(r,g,b) (0xff000000 | (r << 16) | (g << 8) | b) static const struct RGBData { - const char *name; + const char name[21]; uint value; } rgbTbl[] = { { "aliceblue", rgb(240, 248, 255) }, -- cgit v1.2.3 From a81be85b63f8caf817bb7c4a840ff3a3aaf49a83 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Mon, 1 Aug 2016 10:05:28 +0300 Subject: QDataWidgetMapper: Fix UB (member call) As found by UBSan: qdatawidgetmapper.cpp:212:59: runtime error: member call on address 0x2b6cc8095be0 which does not point to an object of type 'QFocusHelper' 0x2b6cc8095be0: note: object is of type 'QLineEdit' Just make QDataWidgetMapperPrivate a friend of QWidget. Change-Id: I33d8d430c3a03b7173358d0f96dc7f850d11697c Reviewed-by: Olivier Goffart (Woboq GmbH) Reviewed-by: Friedemann Kleint --- src/widgets/itemviews/qdatawidgetmapper.cpp | 18 ++---------------- src/widgets/kernel/qwidget.h | 1 + 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/src/widgets/itemviews/qdatawidgetmapper.cpp b/src/widgets/itemviews/qdatawidgetmapper.cpp index ee7b3613a2..058a570437 100644 --- a/src/widgets/itemviews/qdatawidgetmapper.cpp +++ b/src/widgets/itemviews/qdatawidgetmapper.cpp @@ -199,20 +199,6 @@ void QDataWidgetMapperPrivate::_q_commitData(QWidget *w) commit(widgetMap.at(idx)); } -class QFocusHelper: public QWidget -{ -public: - bool focusNextPrevChild(bool next) Q_DECL_OVERRIDE - { - return QWidget::focusNextPrevChild(next); - } - - static inline void focusNextPrevChild(QWidget *w, bool next) - { - static_cast(w)->focusNextPrevChild(next); - } -}; - void QDataWidgetMapperPrivate::_q_closeEditor(QWidget *w, QAbstractItemDelegate::EndEditHint hint) { int idx = findWidget(w); @@ -224,10 +210,10 @@ void QDataWidgetMapperPrivate::_q_closeEditor(QWidget *w, QAbstractItemDelegate: populate(widgetMap[idx]); break; } case QAbstractItemDelegate::EditNextItem: - QFocusHelper::focusNextPrevChild(w, true); + w->focusNextChild(); break; case QAbstractItemDelegate::EditPreviousItem: - QFocusHelper::focusNextPrevChild(w, false); + w->focusPreviousChild(); break; case QAbstractItemDelegate::SubmitModelCache: case QAbstractItemDelegate::NoHint: diff --git a/src/widgets/kernel/qwidget.h b/src/widgets/kernel/qwidget.h index 2af1550ad1..c8e08a5bc4 100644 --- a/src/widgets/kernel/qwidget.h +++ b/src/widgets/kernel/qwidget.h @@ -668,6 +668,7 @@ protected: void destroy(bool destroyWindow = true, bool destroySubWindows = true); + friend class QDataWidgetMapperPrivate; // for access to focusNextPrevChild virtual bool focusNextPrevChild(bool next); inline bool focusNextChild() { return focusNextPrevChild(true); } inline bool focusPreviousChild() { return focusNextPrevChild(false); } -- cgit v1.2.3 From 08f38d22149f062006316997a04fee57c33bc577 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 28 Jul 2016 19:51:53 +0300 Subject: tst_QAbstractItemView: Fix UB (invalid downcast, member call) As reported by UBSan: tst_qabstractitemview.cpp:336:23: runtime error: member call on address 0x7ffe6fe96e10 which does not point to an object of type 'TestView' 0x7ffe6fe96e10: note: object is of type 'QListView' tst_qabstractitemview.cpp:337:5: runtime error: member call on address 0x7ffe6fe96e10 which does not point to an object of type 'TestView' 0x7ffe6fe96e10: note: object is of type 'QListView' tst_qabstractitemview.cpp:338:23: runtime error: member call on address 0x7ffe6fe96e10 which does not point to an object of type 'TestView' 0x7ffe6fe96e10: note: object is of type 'QListView' [etc ...] Fix by making the test a friend of QAbstractItemView instead. Change-Id: I1a08977042296eb34e9dbdb5c0595662dbd2e5ef Reviewed-by: Friedemann Kleint Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/widgets/itemviews/qabstractitemview.h | 3 + .../qabstractitemview/tst_qabstractitemview.cpp | 254 ++++++--------------- 2 files changed, 79 insertions(+), 178 deletions(-) diff --git a/src/widgets/itemviews/qabstractitemview.h b/src/widgets/itemviews/qabstractitemview.h index ff1848b149..82bc7cb9ae 100644 --- a/src/widgets/itemviews/qabstractitemview.h +++ b/src/widgets/itemviews/qabstractitemview.h @@ -39,6 +39,8 @@ #include #include +class tst_QAbstractItemView; + QT_BEGIN_NAMESPACE @@ -359,6 +361,7 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_scrollerStateChanged()) #endif + friend class ::tst_QAbstractItemView; friend class QTreeViewPrivate; // needed to compile with MSVC friend class QListModeViewBase; friend class QListViewPrivate; diff --git a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp index 6cbf51efd9..a62147b707 100644 --- a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp +++ b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp @@ -81,108 +81,6 @@ static inline void moveCursorAway(const QWidget *topLevel) #endif } -class TestView : public QAbstractItemView -{ - Q_OBJECT -public: - inline void tst_dataChanged(const QModelIndex &tl, const QModelIndex &br) - { dataChanged(tl, br); } - inline void tst_setHorizontalStepsPerItem(int steps) - { setHorizontalStepsPerItem(steps); } - inline int tst_horizontalStepsPerItem() const - { return horizontalStepsPerItem(); } - inline void tst_setVerticalStepsPerItem(int steps) - { setVerticalStepsPerItem(steps); } - inline int tst_verticalStepsPerItem() const - { return verticalStepsPerItem(); } - - inline void tst_rowsInserted(const QModelIndex &parent, int start, int end) - { rowsInserted(parent, start, end); } - inline void tst_rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) - { rowsAboutToBeRemoved(parent, start, end); } - inline void tst_selectionChanged(const QItemSelection &selected, - const QItemSelection &deselected) - { selectionChanged(selected, deselected); } - inline void tst_currentChanged(const QModelIndex ¤t, const QModelIndex &previous) - { currentChanged(current, previous); } - inline void tst_updateEditorData() - { updateEditorData(); } - inline void tst_updateEditorGeometries() - { updateEditorGeometries(); } - inline void tst_updateGeometries() - { updateGeometries(); } - inline void tst_verticalScrollbarAction(int action) - { verticalScrollbarAction(action); } - inline void tst_horizontalScrollbarAction(int action) - { horizontalScrollbarAction(action); } - inline void tst_verticalScrollbarValueChanged(int value) - { verticalScrollbarValueChanged(value); } - inline void tst_horizontalScrollbarValueChanged(int value) - { horizontalScrollbarValueChanged(value); } - inline void tst_closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint) - { closeEditor(editor, hint); } - inline void tst_commitData(QWidget *editor) - { commitData(editor); } - inline void tst_editorDestroyed(QObject *editor) - { editorDestroyed(editor); } - enum tst_CursorAction { - MoveUp = QAbstractItemView::MoveUp, - MoveDown = QAbstractItemView::MoveDown, - MoveLeft = QAbstractItemView::MoveLeft, - MoveRight = QAbstractItemView::MoveRight, - MoveHome = QAbstractItemView::MoveHome, - MoveEnd = QAbstractItemView::MoveEnd, - MovePageUp = QAbstractItemView::MovePageUp, - MovePageDown = QAbstractItemView::MovePageDown, - MoveNext = QAbstractItemView::MoveNext, - MovePrevious = QAbstractItemView::MovePrevious - }; - inline QModelIndex tst_moveCursor(tst_CursorAction cursorAction, - Qt::KeyboardModifiers modifiers) - { return moveCursor(QAbstractItemView::CursorAction(cursorAction), modifiers); } - inline int tst_horizontalOffset() const - { return horizontalOffset(); } - inline int tst_verticalOffset() const - { return verticalOffset(); } - inline bool tst_isIndexHidden(const QModelIndex &index) const - { return isIndexHidden(index); } - inline void tst_setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command) - { setSelection(rect, command); } - inline QRegion tst_visualRegionForSelection(const QItemSelection &selection) const - { return visualRegionForSelection(selection); } - inline QModelIndexList tst_selectedIndexes() const - { return selectedIndexes(); } - inline bool tst_edit(const QModelIndex &index, EditTrigger trigger, QEvent *event) - { return edit(index, trigger, event); } - inline QItemSelectionModel::SelectionFlags tst_selectionCommand(const QModelIndex &index, - const QEvent *event = 0) const - { return selectionCommand(index, event); } -#ifndef QT_NO_DRAGANDDROP - inline void tst_startDrag(Qt::DropActions supportedActions) - { startDrag(supportedActions); } -#endif - inline QStyleOptionViewItem tst_viewOptions() const - { return viewOptions(); } - enum tst_State { - NoState = QAbstractItemView::NoState, - DraggingState = QAbstractItemView::DraggingState, - DragSelectingState = QAbstractItemView::DragSelectingState, - EditingState = QAbstractItemView::EditingState, - ExpandingState = QAbstractItemView::ExpandingState, - CollapsingState = QAbstractItemView::CollapsingState - }; - inline tst_State tst_state() const - { return (tst_State)state(); } - inline void tst_setState(tst_State state) - { setState(QAbstractItemView::State(state)); } - inline void tst_startAutoScroll() - { startAutoScroll(); } - inline void tst_stopAutoScroll() - { stopAutoScroll(); } - inline void tst_doAutoScroll() - { doAutoScroll(); } -}; - class GeometriesTestView : public QTableView { Q_OBJECT @@ -198,7 +96,7 @@ class tst_QAbstractItemView : public QObject Q_OBJECT public: - void basic_tests(TestView *view); + void basic_tests(QAbstractItemView *view); private slots: void initTestCase(); @@ -282,7 +180,7 @@ public: void tst_QAbstractItemView::getSetCheck() { QListView view; - TestView *obj1 = reinterpret_cast(&view); + QAbstractItemView *obj1 = &view; // QAbstractItemDelegate * QAbstractItemView::itemDelegate() // void QAbstractItemView::setItemDelegate(QAbstractItemDelegate *) MyAbstractItemDelegate *var1 = new MyAbstractItemDelegate; @@ -333,18 +231,18 @@ void tst_QAbstractItemView::getSetCheck() // State QAbstractItemView::state() // void QAbstractItemView::setState(State) - obj1->tst_setState(TestView::tst_State(TestView::NoState)); - QCOMPARE(TestView::tst_State(TestView::NoState), obj1->tst_state()); - obj1->tst_setState(TestView::tst_State(TestView::DraggingState)); - QCOMPARE(TestView::tst_State(TestView::DraggingState), obj1->tst_state()); - obj1->tst_setState(TestView::tst_State(TestView::DragSelectingState)); - QCOMPARE(TestView::tst_State(TestView::DragSelectingState), obj1->tst_state()); - obj1->tst_setState(TestView::tst_State(TestView::EditingState)); - QCOMPARE(TestView::tst_State(TestView::EditingState), obj1->tst_state()); - obj1->tst_setState(TestView::tst_State(TestView::ExpandingState)); - QCOMPARE(TestView::tst_State(TestView::ExpandingState), obj1->tst_state()); - obj1->tst_setState(TestView::tst_State(TestView::CollapsingState)); - QCOMPARE(TestView::tst_State(TestView::CollapsingState), obj1->tst_state()); + obj1->setState(QAbstractItemView::NoState); + QCOMPARE(QAbstractItemView::NoState, obj1->state()); + obj1->setState(QAbstractItemView::DraggingState); + QCOMPARE(QAbstractItemView::DraggingState, obj1->state()); + obj1->setState(QAbstractItemView::DragSelectingState); + QCOMPARE(QAbstractItemView::DragSelectingState, obj1->state()); + obj1->setState(QAbstractItemView::EditingState); + QCOMPARE(QAbstractItemView::EditingState, obj1->state()); + obj1->setState(QAbstractItemView::ExpandingState); + QCOMPARE(QAbstractItemView::ExpandingState, obj1->state()); + obj1->setState(QAbstractItemView::CollapsingState); + QCOMPARE(QAbstractItemView::CollapsingState, obj1->state()); // QWidget QAbstractScrollArea::viewport() // void setViewport(QWidget*) @@ -405,7 +303,7 @@ void tst_QAbstractItemView::emptyModels() QVERIFY(!view->selectionModel()); //QVERIFY(view->itemDelegate() != 0); - basic_tests(reinterpret_cast(view.data())); + basic_tests(view.data()); } void tst_QAbstractItemView::setModel_data() @@ -442,10 +340,10 @@ void tst_QAbstractItemView::setModel() QStandardItemModel model(20,20); view->setModel(0); view->setModel(&model); - basic_tests(reinterpret_cast(view.data())); + basic_tests(view.data()); } -void tst_QAbstractItemView::basic_tests(TestView *view) +void tst_QAbstractItemView::basic_tests(QAbstractItemView *view) { // setSelectionModel // Will assert as it should @@ -570,73 +468,73 @@ void tst_QAbstractItemView::basic_tests(TestView *view) view->setCurrentIndex(QModelIndex()); // protected methods - view->tst_dataChanged(QModelIndex(), QModelIndex()); - view->tst_rowsInserted(QModelIndex(), -1, -1); - view->tst_rowsAboutToBeRemoved(QModelIndex(), -1, -1); - view->tst_selectionChanged(QItemSelection(), QItemSelection()); + view->dataChanged(QModelIndex(), QModelIndex()); + view->rowsInserted(QModelIndex(), -1, -1); + view->rowsAboutToBeRemoved(QModelIndex(), -1, -1); + view->selectionChanged(QItemSelection(), QItemSelection()); if (view->model()){ - view->tst_currentChanged(QModelIndex(), QModelIndex()); - view->tst_currentChanged(QModelIndex(), view->model()->index(0,0)); + view->currentChanged(QModelIndex(), QModelIndex()); + view->currentChanged(QModelIndex(), view->model()->index(0,0)); } - view->tst_updateEditorData(); - view->tst_updateEditorGeometries(); - view->tst_updateGeometries(); - view->tst_verticalScrollbarAction(QAbstractSlider::SliderSingleStepAdd); - view->tst_horizontalScrollbarAction(QAbstractSlider::SliderSingleStepAdd); - view->tst_verticalScrollbarValueChanged(10); - view->tst_horizontalScrollbarValueChanged(10); - view->tst_closeEditor(0, QAbstractItemDelegate::NoHint); - view->tst_commitData(0); - view->tst_editorDestroyed(0); - - view->tst_setHorizontalStepsPerItem(2); - view->tst_horizontalStepsPerItem(); - view->tst_setVerticalStepsPerItem(2); - view->tst_verticalStepsPerItem(); + view->updateEditorData(); + view->updateEditorGeometries(); + view->updateGeometries(); + view->verticalScrollbarAction(QAbstractSlider::SliderSingleStepAdd); + view->horizontalScrollbarAction(QAbstractSlider::SliderSingleStepAdd); + view->verticalScrollbarValueChanged(10); + view->horizontalScrollbarValueChanged(10); + view->closeEditor(0, QAbstractItemDelegate::NoHint); + view->commitData(0); + view->editorDestroyed(0); + + view->setHorizontalStepsPerItem(2); + view->horizontalStepsPerItem(); + view->setVerticalStepsPerItem(2); + view->verticalStepsPerItem(); // Will assert as it should // view->setIndexWidget(QModelIndex(), 0); - view->tst_moveCursor(TestView::MoveUp, Qt::NoModifier); - view->tst_horizontalOffset(); - view->tst_verticalOffset(); + view->moveCursor(QAbstractItemView::MoveUp, Qt::NoModifier); + view->horizontalOffset(); + view->verticalOffset(); -// view->tst_isIndexHidden(QModelIndex()); // will (correctly) assert +// view->isIndexHidden(QModelIndex()); // will (correctly) assert if(view->model()) - view->tst_isIndexHidden(view->model()->index(0,0)); + view->isIndexHidden(view->model()->index(0,0)); - view->tst_setSelection(QRect(0, 0, 10, 10), QItemSelectionModel::ClearAndSelect); - view->tst_setSelection(QRect(-1, -1, -1, -1), QItemSelectionModel::ClearAndSelect); - view->tst_visualRegionForSelection(QItemSelection()); - view->tst_selectedIndexes(); + view->setSelection(QRect(0, 0, 10, 10), QItemSelectionModel::ClearAndSelect); + view->setSelection(QRect(-1, -1, -1, -1), QItemSelectionModel::ClearAndSelect); + view->visualRegionForSelection(QItemSelection()); + view->selectedIndexes(); - view->tst_edit(QModelIndex(), QAbstractItemView::NoEditTriggers, 0); + view->edit(QModelIndex(), QAbstractItemView::NoEditTriggers, 0); - view->tst_selectionCommand(QModelIndex(), 0); + view->selectionCommand(QModelIndex(), 0); #ifndef QT_NO_DRAGANDDROP if (!view->model()) - view->tst_startDrag(Qt::CopyAction); - - view->tst_viewOptions(); - - view->tst_setState(TestView::NoState); - QVERIFY(view->tst_state()==TestView::NoState); - view->tst_setState(TestView::DraggingState); - QVERIFY(view->tst_state()==TestView::DraggingState); - view->tst_setState(TestView::DragSelectingState); - QVERIFY(view->tst_state()==TestView::DragSelectingState); - view->tst_setState(TestView::EditingState); - QVERIFY(view->tst_state()==TestView::EditingState); - view->tst_setState(TestView::ExpandingState); - QVERIFY(view->tst_state()==TestView::ExpandingState); - view->tst_setState(TestView::CollapsingState); - QVERIFY(view->tst_state()==TestView::CollapsingState); + view->startDrag(Qt::CopyAction); + + view->viewOptions(); + + view->setState(QAbstractItemView::NoState); + QVERIFY(view->state()==QAbstractItemView::NoState); + view->setState(QAbstractItemView::DraggingState); + QVERIFY(view->state()==QAbstractItemView::DraggingState); + view->setState(QAbstractItemView::DragSelectingState); + QVERIFY(view->state()==QAbstractItemView::DragSelectingState); + view->setState(QAbstractItemView::EditingState); + QVERIFY(view->state()==QAbstractItemView::EditingState); + view->setState(QAbstractItemView::ExpandingState); + QVERIFY(view->state()==QAbstractItemView::ExpandingState); + view->setState(QAbstractItemView::CollapsingState); + QVERIFY(view->state()==QAbstractItemView::CollapsingState); #endif - view->tst_startAutoScroll(); - view->tst_stopAutoScroll(); - view->tst_doAutoScroll(); + view->startAutoScroll(); + view->stopAutoScroll(); + view->doAutoScroll(); // testing mouseFoo and key functions // QTest::mousePress(view, Qt::LeftButton, Qt::NoModifier, QPoint(0,0)); @@ -771,11 +669,11 @@ void tst_QAbstractItemView::selectAll() QTableView view; view.setModel(&model); - TestView *tst_view = (TestView*)&view; + QAbstractItemView *tst_view = &view; - QCOMPARE(tst_view->tst_selectedIndexes().count(), 0); + QCOMPARE(tst_view->selectedIndexes().count(), 0); view.selectAll(); - QCOMPARE(tst_view->tst_selectedIndexes().count(), 4*4); + QCOMPARE(tst_view->selectedIndexes().count(), 4*4); } void tst_QAbstractItemView::ctrlA() @@ -784,11 +682,11 @@ void tst_QAbstractItemView::ctrlA() QTableView view; view.setModel(&model); - TestView *tst_view = (TestView*)&view; + QAbstractItemView *tst_view = &view; - QCOMPARE(tst_view->tst_selectedIndexes().count(), 0); + QCOMPARE(tst_view->selectedIndexes().count(), 0); QTest::keyClick(&view, Qt::Key_A, Qt::ControlModifier); - QCOMPARE(tst_view->tst_selectedIndexes().count(), 4*4); + QCOMPARE(tst_view->selectedIndexes().count(), 4*4); } void tst_QAbstractItemView::persistentEditorFocus() @@ -1604,9 +1502,9 @@ void tst_QAbstractItemView::testDelegateDestroyEditor() MyAbstractItemDelegate delegate; table.setItemDelegate(&delegate); table.edit(table.model()->index(1, 1)); - TestView *tv = reinterpret_cast(&table); + QAbstractItemView *tv = &table; QVERIFY(!delegate.calledVirtualDtor); - tv->tst_closeEditor(delegate.openedEditor, QAbstractItemDelegate::NoHint); + tv->closeEditor(delegate.openedEditor, QAbstractItemDelegate::NoHint); QVERIFY(delegate.calledVirtualDtor); } -- cgit v1.2.3 From 5dc83974f7e6f72d715c4c940ca57741a550aa1c Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 28 Jul 2016 19:51:53 +0300 Subject: tst_QTreeView: Fix UB (invalid downcast, member call) As reported by UBSan: tst_qtreeview.cpp:2187:36: runtime error: downcast of address 0x7ffc15749f20 which does not point to an object of type 'PublicView' 0x7ffc15749f20: note: object is of type 'QTreeView' Fix by making the test a friend of QTreeView (and, for Clang, of QAbstractItemView) instead. Change-Id: I5b748696ab441a91058f4d45a18bd5ed75a6e560 Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/widgets/itemviews/qabstractitemview.h | 2 + src/widgets/itemviews/qtreeview.h | 3 + .../widgets/itemviews/qtreeview/tst_qtreeview.cpp | 97 ++++++---------------- 3 files changed, 32 insertions(+), 70 deletions(-) diff --git a/src/widgets/itemviews/qabstractitemview.h b/src/widgets/itemviews/qabstractitemview.h index 82bc7cb9ae..8d712280d3 100644 --- a/src/widgets/itemviews/qabstractitemview.h +++ b/src/widgets/itemviews/qabstractitemview.h @@ -40,6 +40,7 @@ #include class tst_QAbstractItemView; +class tst_QTreeView; QT_BEGIN_NAMESPACE @@ -362,6 +363,7 @@ private: #endif friend class ::tst_QAbstractItemView; + friend class ::tst_QTreeView; friend class QTreeViewPrivate; // needed to compile with MSVC friend class QListModeViewBase; friend class QListViewPrivate; diff --git a/src/widgets/itemviews/qtreeview.h b/src/widgets/itemviews/qtreeview.h index 546cc488cb..9257bb66fa 100644 --- a/src/widgets/itemviews/qtreeview.h +++ b/src/widgets/itemviews/qtreeview.h @@ -36,6 +36,8 @@ #include +class tst_QTreeView; + QT_BEGIN_NAMESPACE @@ -213,6 +215,7 @@ protected: void currentChanged(const QModelIndex ¤t, const QModelIndex &previous) Q_DECL_OVERRIDE; private: + friend class ::tst_QTreeView; friend class QAccessibleTable; friend class QAccessibleTree; friend class QAccessibleTableCell; diff --git a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp index bd6939b977..0f497500cd 100644 --- a/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp +++ b/tests/auto/widgets/itemviews/qtreeview/tst_qtreeview.cpp @@ -36,7 +36,7 @@ #include #include #include -#include +#include #ifndef QT_NO_DRAGANDDROP Q_DECLARE_METATYPE(QAbstractItemView::DragDropMode) @@ -62,49 +62,6 @@ static void initStandardTreeModel(QStandardItemModel *model) model->insertRow(2, item); } -class tst_QTreeView; -struct PublicView : public QTreeView -{ - friend class tst_QTreeView; - inline void executeDelayedItemsLayout() - { QTreeView::executeDelayedItemsLayout(); } - - enum PublicCursorAction { - MoveUp = QAbstractItemView::MoveUp, - MoveDown = QAbstractItemView::MoveDown, - MoveLeft = QAbstractItemView::MoveLeft, - MoveRight = QAbstractItemView::MoveRight, - MoveHome = QAbstractItemView::MoveHome, - MoveEnd = QAbstractItemView::MoveEnd, - MovePageUp = QAbstractItemView::MovePageUp, - MovePageDown = QAbstractItemView::MovePageDown, - MoveNext = QAbstractItemView::MoveNext, - MovePrevious = QAbstractItemView::MovePrevious - }; - - // enum PublicCursorAction and moveCursor() are protected in QTreeView. - inline QModelIndex doMoveCursor(PublicCursorAction ca, Qt::KeyboardModifiers kbm) - { return QTreeView::moveCursor((CursorAction)ca, kbm); } - - inline void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command) - { - QTreeView::setSelection(rect, command); - } - inline int state() - { - return QTreeView::state(); - } - - inline int rowHeight(QModelIndex idx) { return QTreeView::rowHeight(idx); } - inline int indexRowSizeHint(const QModelIndex &index) const { return QTreeView::indexRowSizeHint(index); } - - inline QModelIndexList selectedIndexes() const { return QTreeView::selectedIndexes(); } - - inline QStyleOptionViewItem viewOptions() const { return QTreeView::viewOptions(); } - inline int sizeHintForColumn(int column) const { return QTreeView::sizeHintForColumn(column); } - QAbstractItemViewPrivate* aiv_priv() { return static_cast(d_ptr.data()); } -}; - // Make a widget frameless to prevent size constraints of title bars // from interfering (Windows). static inline void setFrameless(QWidget *w) @@ -1783,7 +1740,7 @@ void tst_QTreeView::moveCursor() QFETCH(bool, scrollPerPixel); QtTestModel model(8, 6); - PublicView view; + QTreeView view; view.setUniformRowHeights(uniformRowHeights); view.setModel(&model); view.setRowHidden(0, QModelIndex(), true); @@ -1802,7 +1759,7 @@ void tst_QTreeView::moveCursor() QCOMPARE(view.currentIndex(), expected); //then pressing down should go to the next line - QModelIndex actual = view.doMoveCursor(PublicView::MoveDown, Qt::NoModifier); + QModelIndex actual = view.moveCursor(QTreeView::MoveDown, Qt::NoModifier); expected = model.index(2, 1, QModelIndex()); QCOMPARE(actual, expected); @@ -1811,7 +1768,7 @@ void tst_QTreeView::moveCursor() // PageUp was broken with uniform row heights turned on view.setCurrentIndex(model.index(1, 0)); - actual = view.doMoveCursor(PublicView::MovePageUp, Qt::NoModifier); + actual = view.moveCursor(QTreeView::MovePageUp, Qt::NoModifier); expected = model.index(0, 0, QModelIndex()); QCOMPARE(actual, expected); @@ -1910,7 +1867,7 @@ void tst_QTreeView::setSelection() QtTestModel model(10, 5); model.levels = 1; model.setDecorationsEnabled(true); - PublicView view; + QTreeView view; view.resize(400, 300); view.show(); view.setRootIsDecorated(false); @@ -2097,7 +2054,7 @@ void tst_QTreeView::rowsAboutToBeRemoved() } } - PublicView view; + QTreeView view; view.setModel(&model); view.show(); QModelIndex index = model.index(0,0, QModelIndex()); @@ -2111,7 +2068,7 @@ void tst_QTreeView::rowsAboutToBeRemoved() QSignalSpy spy1(&model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int))); model.removeRows(1,1); - QCOMPARE(view.state(), 0); + QCOMPARE(int(view.state()), 0); // Should not be 5 (or any other number for that sake :) QCOMPARE(spy1.count(), 1); @@ -2214,7 +2171,7 @@ void tst_QTreeView::rowsAboutToBeRemoved_move() view.resize(600,800); view.show(); view.doItemsLayout(); - static_cast(&view)->executeDelayedItemsLayout(); + static_cast(&view)->executeDelayedItemsLayout(); parent = indexThatWantsToLiveButWillDieDieITellYou.parent(); QCOMPARE(view.isExpanded(indexThatWantsToLiveButWillDieDieITellYou), true); QCOMPARE(parent.isValid(), true); @@ -2320,7 +2277,7 @@ void tst_QTreeView::spanningItems() { QtTestModel model; model.rows = model.cols = 10; - PublicView view; + QTreeView view; view.setModel(&model); view.show(); @@ -2459,7 +2416,7 @@ void tst_QTreeView::selectionWithHiddenItems() void tst_QTreeView::selectAll() { QStandardItemModel model(4,4); - PublicView view2; + QTreeView view2; view2.setModel(&model); view2.setSelectionMode(QAbstractItemView::ExtendedSelection); view2.selectAll(); // Should work with an empty model @@ -2468,13 +2425,13 @@ void tst_QTreeView::selectAll() for (int i = 0; i < model.rowCount(); ++i) model.setData(model.index(i,0), QString("row %1").arg(i)); - PublicView view; + QTreeView view; view.setModel(&model); int selectedCount = view.selectedIndexes().count(); view.selectAll(); QCOMPARE(view.selectedIndexes().count(), selectedCount); - PublicView view3; + QTreeView view3; view3.setModel(&model); view3.setSelectionMode(QAbstractItemView::NoSelection); view3.selectAll(); @@ -2836,7 +2793,7 @@ void tst_QTreeView::evilModel() { QFETCH(bool, visible); // init - PublicView view; + QTreeView view; EvilModel model; view.setModel(&model); view.setVisible(visible); @@ -2894,7 +2851,7 @@ void tst_QTreeView::evilModel() view.setSelection(rect, QItemSelectionModel::Select); model.change(); - view.doMoveCursor(PublicView::MoveDown, Qt::NoModifier); + view.moveCursor(QTreeView::MoveDown, Qt::NoModifier); model.change(); view.resizeColumnToContents(1); @@ -3005,7 +2962,7 @@ void tst_QTreeView::evilModel() void tst_QTreeView::indexRowSizeHint() { QStandardItemModel model(10, 1); - PublicView view; + QTreeView view; view.setModel(&model); @@ -3051,7 +3008,7 @@ void tst_QTreeView::renderToPixmap_data() void tst_QTreeView::renderToPixmap() { QFETCH(int, row); - PublicView view; + QTreeView view; QStandardItemModel model; model.appendRow(new QStandardItem("Spanning")); @@ -3067,7 +3024,7 @@ void tst_QTreeView::renderToPixmap() // We select the index at row=1 for coverage. QItemSelection sel(model.index(row,0), model.index(row,1)); QRect rect; - view.aiv_priv()->renderToPixmap(sel.indexes(), &rect); + view.d_func()->renderToPixmap(sel.indexes(), &rect); } #endif } @@ -3129,7 +3086,7 @@ void tst_QTreeView::styleOptionViewItem() bool allCollapsed; }; - PublicView view; + QTreeView view; QStandardItemModel model; view.setModel(&model); MyDelegate delegate; @@ -3185,7 +3142,7 @@ void tst_QTreeView::styleOptionViewItem() delegate.count = 0; QItemSelection sel(model.index(0,0), model.index(0,modelColumns-1)); QRect rect; - view.aiv_priv()->renderToPixmap(sel.indexes(), &rect); + view.d_func()->renderToPixmap(sel.indexes(), &rect); if (delegate.count != visibleColumns) { qDebug() << rect << view.rect() << view.isVisible(); } @@ -3213,7 +3170,7 @@ void tst_QTreeView::styleOptionViewItem() delegate.count = 0; QItemSelection sel(model.index(0,0), model.index(0,modelColumns-1)); QRect rect; - view.aiv_priv()->renderToPixmap(sel.indexes(), &rect); + view.d_func()->renderToPixmap(sel.indexes(), &rect); if (delegate.count != visibleColumns) { qDebug() << rect << view.rect() << view.isVisible(); } @@ -4168,7 +4125,7 @@ void tst_QTreeView::taskQTBUG_13567_removeLastItemRegression() // Note: define QT_BUILD_INTERNAL to run this test void tst_QTreeView::taskQTBUG_25333_adjustViewOptionsForIndex() { - PublicView view; + QTreeView view; QStandardItemModel model; QStandardItem *item1 = new QStandardItem("Item1"); QStandardItem *item2 = new QStandardItem("Item2"); @@ -4194,9 +4151,9 @@ void tst_QTreeView::taskQTBUG_25333_adjustViewOptionsForIndex() { QStyleOptionViewItem option; - view.aiv_priv()->adjustViewOptionsForIndex(&option, model.indexFromItem(item1)); + view.d_func()->adjustViewOptionsForIndex(&option, model.indexFromItem(item1)); - view.aiv_priv()->adjustViewOptionsForIndex(&option, model.indexFromItem(item3)); + view.d_func()->adjustViewOptionsForIndex(&option, model.indexFromItem(item3)); } #endif @@ -4302,7 +4259,7 @@ void tst_QTreeView::quickExpandCollapse() //this unit tests makes sure the state after the animation is restored correctly //after starting a 2nd animation while the first one was still on-going //this tests that the stateBeforeAnimation is not set to AnimatingState - PublicView tree; + QTreeView tree; tree.setAnimated(true); QStandardItemModel model; QStandardItem *root = new QStandardItem("root"); @@ -4316,13 +4273,13 @@ void tst_QTreeView::quickExpandCollapse() tree.show(); QTest::qWaitForWindowExposed(&tree); - int initialState = tree.state(); + const QAbstractItemView::State initialState = tree.state(); tree.expand(rootIndex); - QCOMPARE(tree.state(), (int)PublicView::AnimatingState); + QCOMPARE(tree.state(), QTreeView::AnimatingState); tree.collapse(rootIndex); - QCOMPARE(tree.state(), (int)PublicView::AnimatingState); + QCOMPARE(tree.state(), QTreeView::AnimatingState); QTest::qWait(500); //the animation lasts for 250ms max so 500 should be enough -- cgit v1.2.3 From 100970687fc17dd9fa9692e6f746a93baae752a2 Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Thu, 16 Jun 2016 09:27:57 +0200 Subject: Doc: Fix broken external link to livecoding vfx video Change-Id: Idf4ea5f175b3ad41292e5ba8e4538311b00c6d2f Reviewed-by: Leena Miettinen --- doc/global/externalsites/qt-webpages.qdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/global/externalsites/qt-webpages.qdoc b/doc/global/externalsites/qt-webpages.qdoc index 706fcc3a97..5eea92c601 100644 --- a/doc/global/externalsites/qt-webpages.qdoc +++ b/doc/global/externalsites/qt-webpages.qdoc @@ -70,7 +70,7 @@ \title Qt Quarterly: Another Look at Events */ /*! - \externalpage http://qt-project.org/videos/watch/livecoding-video-effects-with-qt5 + \externalpage https://www.youtube.com/watch?v=P4kv-AoAJ-Q \title Livecoding video effects with Qt5 */ /*! -- cgit v1.2.3 From b92a63f7073b35a31f66af280bd50ddff1d15b50 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Wed, 27 Jul 2016 08:34:54 +0200 Subject: Fix typo in QMessageBox documentation Change-Id: I879817bf0209db331a9b1ef206bad7aa5b8a678f Reviewed-by: Friedemann Kleint --- src/widgets/dialogs/qmessagebox.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/dialogs/qmessagebox.cpp b/src/widgets/dialogs/qmessagebox.cpp index dbbf6cdc71..f32f7b0417 100644 --- a/src/widgets/dialogs/qmessagebox.cpp +++ b/src/widgets/dialogs/qmessagebox.cpp @@ -697,7 +697,7 @@ void QMessageBoxPrivate::_q_clicked(QPlatformDialogHelper::StandardButton button If the \l{QMessageBox::StandardButtons} {standard buttons} are not flexible enough for your message box, you can use the addButton() - overload that takes a text and a ButtonRoleto to add custom + overload that takes a text and a ButtonRole to add custom buttons. The ButtonRole is used by QMessageBox to determine the ordering of the buttons on screen (which varies according to the platform). You can test the value of clickedButton() after calling -- cgit v1.2.3 From 879fd5bb5ce94d9d98b966448029c030832eb582 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Tue, 14 Jun 2016 12:34:53 +0200 Subject: QTzTimeZonePrivate: skip redundant check, tidy up Various transition functions checked on m_tranTimes.size() > 0 inside a block which was conditioned on this already; simplify the code by knowing this is true already. Tidied up an initializer at the same time. Change-Id: I3e933a69e1b71b94bfd4451e4d761844da669d33 Reviewed-by: Thiago Macieira --- src/corelib/tools/qtimezoneprivate_tz.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/corelib/tools/qtimezoneprivate_tz.cpp b/src/corelib/tools/qtimezoneprivate_tz.cpp index 29544a5c37..c13c9a5223 100644 --- a/src/corelib/tools/qtimezoneprivate_tz.cpp +++ b/src/corelib/tools/qtimezoneprivate_tz.cpp @@ -896,13 +896,12 @@ QTimeZonePrivate::Data QTzTimeZonePrivate::data(qint64 forMSecsSinceEpoch) const if (m_tranTimes.size() > 0 && m_tranTimes.last().atMSecsSinceEpoch < forMSecsSinceEpoch && !m_posixRule.isEmpty() && forMSecsSinceEpoch >= 0) { const int year = QDateTime::fromMSecsSinceEpoch(forMSecsSinceEpoch, Qt::UTC).date().year(); - const int lastMSecs = (m_tranTimes.size() > 0) ? m_tranTimes.last().atMSecsSinceEpoch : 0; - QVector posixTrans = calculatePosixTransitions(m_posixRule, year - 1, - year + 1, lastMSecs); + QVector posixTrans = + calculatePosixTransitions(m_posixRule, year - 1, year + 1, + m_tranTimes.last().atMSecsSinceEpoch); for (int i = posixTrans.size() - 1; i >= 0; --i) { if (posixTrans.at(i).atMSecsSinceEpoch <= forMSecsSinceEpoch) { - QTimeZonePrivate::Data data; - data = posixTrans.at(i); + QTimeZonePrivate::Data data = posixTrans.at(i); data.atMSecsSinceEpoch = forMSecsSinceEpoch; return data; } @@ -940,9 +939,9 @@ QTimeZonePrivate::Data QTzTimeZonePrivate::nextTransition(qint64 afterMSecsSince if (m_tranTimes.size() > 0 && m_tranTimes.last().atMSecsSinceEpoch < afterMSecsSinceEpoch && !m_posixRule.isEmpty() && afterMSecsSinceEpoch >= 0) { const int year = QDateTime::fromMSecsSinceEpoch(afterMSecsSinceEpoch, Qt::UTC).date().year(); - const int lastMSecs = (m_tranTimes.size() > 0) ? m_tranTimes.last().atMSecsSinceEpoch : 0; - QVector posixTrans = calculatePosixTransitions(m_posixRule, year - 1, - year + 1, lastMSecs); + QVector posixTrans = + calculatePosixTransitions(m_posixRule, year - 1, year + 1, + m_tranTimes.last().atMSecsSinceEpoch); for (int i = 0; i < posixTrans.size(); ++i) { if (posixTrans.at(i).atMSecsSinceEpoch > afterMSecsSinceEpoch) return posixTrans.at(i); @@ -966,9 +965,9 @@ QTimeZonePrivate::Data QTzTimeZonePrivate::previousTransition(qint64 beforeMSecs if (m_tranTimes.size() > 0 && m_tranTimes.last().atMSecsSinceEpoch < beforeMSecsSinceEpoch && !m_posixRule.isEmpty() && beforeMSecsSinceEpoch > 0) { const int year = QDateTime::fromMSecsSinceEpoch(beforeMSecsSinceEpoch, Qt::UTC).date().year(); - const int lastMSecs = (m_tranTimes.size() > 0) ? m_tranTimes.last().atMSecsSinceEpoch : 0; - QVector posixTrans = calculatePosixTransitions(m_posixRule, year - 1, - year + 1, lastMSecs); + QVector posixTrans = + calculatePosixTransitions(m_posixRule, year - 1, year + 1, + m_tranTimes.last().atMSecsSinceEpoch); for (int i = posixTrans.size() - 1; i >= 0; --i) { if (posixTrans.at(i).atMSecsSinceEpoch < beforeMSecsSinceEpoch) return posixTrans.at(i); -- cgit v1.2.3 From f38a957789598241d919d14ff776d956df850d08 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 18 May 2016 11:24:52 +0200 Subject: Register sub-families as separate fonts If A is B, but not all B is A, we should not register A as an alias for B. It is better to register it as a separate font-family so when explicitly requested only faces from the sub-family are considered. Task-number: QTBUG-53459 Change-Id: Ie9f5db3ba3fa69a0edb5b1965cce25e4885a00fc Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../fontconfig/qfontconfigdatabase.cpp | 33 ++++++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp index 652a9f4add..c779c70d4d 100644 --- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp +++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp @@ -365,6 +365,7 @@ static const char *getFcFamilyForStyleHint(const QFont::StyleHint style) static void populateFromPattern(FcPattern *pattern) { QString familyName; + QString familyNameLang; FcChar8 *value = 0; int weight_value; int slant_value; @@ -382,6 +383,9 @@ static void populateFromPattern(FcPattern *pattern) familyName = QString::fromUtf8((const char *)value); + if (FcPatternGetString(pattern, FC_FAMILYLANG, 0, &value) == FcResultMatch) + familyNameLang = QString::fromUtf8((const char *)value); + slant_value = FC_SLANT_ROMAN; weight_value = FC_WEIGHT_REGULAR; spacing_value = FC_PROPORTIONAL; @@ -471,8 +475,31 @@ static void populateFromPattern(FcPattern *pattern) QPlatformFontDatabase::registerFont(familyName,styleName,QLatin1String((const char *)foundry_value),weight,style,stretch,antialias,scalable,pixel_size,fixedPitch,writingSystems,fontFile); // qDebug() << familyName << (const char *)foundry_value << weight << style << &writingSystems << scalable << true << pixel_size; - for (int k = 1; FcPatternGetString(pattern, FC_FAMILY, k, &value) == FcResultMatch; ++k) - QPlatformFontDatabase::registerAliasToFontFamily(familyName, QString::fromUtf8((const char *)value)); + for (int k = 1; FcPatternGetString(pattern, FC_FAMILY, k, &value) == FcResultMatch; ++k) { + const QString altFamilyName = QString::fromUtf8((const char *)value); + // Extra family names can be aliases or subfamilies. + // If it is a subfamily, register it as a separate font, so only members of the subfamily are + // matched when the subfamily is requested. + QString altStyleName; + if (FcPatternGetString(pattern, FC_STYLE, k, &value) == FcResultMatch) + altStyleName = QString::fromUtf8((const char *)value); + else + altStyleName = styleName; + + QString altFamilyNameLang; + if (FcPatternGetString(pattern, FC_FAMILYLANG, k, &value) == FcResultMatch) + altFamilyNameLang = QString::fromUtf8((const char *)value); + else + altFamilyNameLang = familyNameLang; + + if (familyNameLang == altFamilyNameLang && altStyleName != styleName) { + const QString altStyleName = QString::fromUtf8((const char *)value); + FontFile *altFontFile = new FontFile(*fontFile); + QPlatformFontDatabase::registerFont(altFamilyName, altStyleName, QLatin1String((const char *)foundry_value),weight,style,stretch,antialias,scalable,pixel_size,fixedPitch,writingSystems,altFontFile); + } else { + QPlatformFontDatabase::registerAliasToFontFamily(familyName, altFamilyName); + } + } } @@ -488,7 +515,7 @@ void QFontconfigDatabase::populateFontDatabase() FC_FAMILY, FC_STYLE, FC_WEIGHT, FC_SLANT, FC_SPACING, FC_FILE, FC_INDEX, FC_LANG, FC_CHARSET, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE, - FC_WIDTH, + FC_WIDTH, FC_FAMILYLANG, #if FC_VERSION >= 20297 FC_CAPABILITY, #endif -- cgit v1.2.3 From 9b1db44c2a94a8d4d56c85e97c391c5bdf762a95 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 22 Jul 2016 09:21:42 +0200 Subject: Polish charactermap example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Use Qt 5 connection syntax. - Introduce helper function to calculate the square size, remove the existing 24 pixel limitation since that makes it impossible to render 20pt fonts. - Add filter chooser for font filters. - Add menu and info dialog showing DPI and default fonts. - Streamline code Change-Id: I0cd4d0475b5a7ed3c475de7a413abebbe688dfe2 Reviewed-by: Topi Reiniö --- .../widgets/charactermap/characterwidget.cpp | 17 +-- .../widgets/widgets/charactermap/characterwidget.h | 2 + .../widgets/widgets/charactermap/mainwindow.cpp | 121 +++++++++++++++++---- examples/widgets/widgets/charactermap/mainwindow.h | 6 +- 4 files changed, 117 insertions(+), 29 deletions(-) diff --git a/examples/widgets/widgets/charactermap/characterwidget.cpp b/examples/widgets/widgets/charactermap/characterwidget.cpp index 1b8cb226f7..47aff4f5be 100644 --- a/examples/widgets/widgets/charactermap/characterwidget.cpp +++ b/examples/widgets/widgets/charactermap/characterwidget.cpp @@ -44,11 +44,9 @@ //! [0] CharacterWidget::CharacterWidget(QWidget *parent) - : QWidget(parent) + : QWidget(parent), columns(16), lastKey(-1) { - squareSize = 24; - columns = 16; - lastKey = -1; + calculateSquareSize(); setMouseTracking(true); } //! [0] @@ -57,7 +55,7 @@ CharacterWidget::CharacterWidget(QWidget *parent) void CharacterWidget::updateFont(const QFont &font) { displayFont.setFamily(font.family()); - squareSize = qMax(24, QFontMetrics(displayFont).xHeight() * 3); + calculateSquareSize(); adjustSize(); update(); } @@ -67,7 +65,7 @@ void CharacterWidget::updateFont(const QFont &font) void CharacterWidget::updateSize(const QString &fontSize) { displayFont.setPointSize(fontSize.toInt()); - squareSize = qMax(24, QFontMetrics(displayFont).xHeight() * 3); + calculateSquareSize(); adjustSize(); update(); } @@ -79,7 +77,7 @@ void CharacterWidget::updateStyle(const QString &fontStyle) const QFont::StyleStrategy oldStrategy = displayFont.styleStrategy(); displayFont = fontDatabase.font(displayFont.family(), fontStyle, displayFont.pointSize()); displayFont.setStyleStrategy(oldStrategy); - squareSize = qMax(24, QFontMetrics(displayFont).xHeight() * 3); + calculateSquareSize(); adjustSize(); update(); } @@ -94,6 +92,11 @@ void CharacterWidget::updateFontMerging(bool enable) update(); } +void CharacterWidget::calculateSquareSize() +{ + squareSize = qMax(16, 4 + QFontMetrics(displayFont, this).height()); +} + //! [3] QSize CharacterWidget::sizeHint() const { diff --git a/examples/widgets/widgets/charactermap/characterwidget.h b/examples/widgets/widgets/charactermap/characterwidget.h index d1c0f28bc4..e195c177d0 100644 --- a/examples/widgets/widgets/charactermap/characterwidget.h +++ b/examples/widgets/widgets/charactermap/characterwidget.h @@ -76,6 +76,8 @@ protected: void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE; private: + void calculateSquareSize(); + QFont displayFont; int columns; int lastKey; diff --git a/examples/widgets/widgets/charactermap/mainwindow.cpp b/examples/widgets/widgets/charactermap/mainwindow.cpp index 14784e7d65..a49e74769e 100644 --- a/examples/widgets/widgets/charactermap/mainwindow.cpp +++ b/examples/widgets/widgets/charactermap/mainwindow.cpp @@ -44,10 +44,30 @@ #include "mainwindow.h" //! [0] + +Q_DECLARE_METATYPE(QFontComboBox::FontFilter) + MainWindow::MainWindow() { + QMenu *fileMenu = menuBar()->addMenu(tr("File")); + fileMenu->addAction(tr("Quit"), this, &QWidget::close); + QMenu *helpMenu = menuBar()->addMenu(tr("&Help")); + helpMenu->addAction(tr("Show Font Info"), this, &MainWindow::showInfo); + helpMenu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt); + QWidget *centralWidget = new QWidget; + QLabel *filterLabel = new QLabel(tr("Filter:")); + filterCombo = new QComboBox; + filterCombo->addItem(tr("All"), QVariant::fromValue(QFontComboBox::AllFonts)); + filterCombo->addItem(tr("Scalable"), QVariant::fromValue(QFontComboBox::ScalableFonts)); + filterCombo->addItem(tr("Monospaced"), QVariant::fromValue(QFontComboBox::MonospacedFonts)); + filterCombo->addItem(tr("Proportional"), QVariant::fromValue(QFontComboBox::ProportionalFonts)); + filterCombo->setCurrentIndex(0); + typedef void (QComboBox::*QComboBoxIntSignal)(int); + connect(filterCombo, static_cast(&QComboBox::currentIndexChanged), + this, &MainWindow::filterChanged); + QLabel *fontLabel = new QLabel(tr("Font:")); fontCombo = new QFontComboBox; QLabel *sizeLabel = new QLabel(tr("Size:")); @@ -70,38 +90,39 @@ MainWindow::MainWindow() //! [2] lineEdit = new QLineEdit; + lineEdit->setClearButtonEnabled(true); #ifndef QT_NO_CLIPBOARD QPushButton *clipboardButton = new QPushButton(tr("&To clipboard")); //! [2] -//! [3] - clipboard = QApplication::clipboard(); -//! [3] #endif //! [4] - connect(fontCombo, SIGNAL(currentFontChanged(QFont)), - this, SLOT(findStyles(QFont))); - connect(fontCombo, SIGNAL(currentFontChanged(QFont)), - this, SLOT(findSizes(QFont))); - connect(fontCombo, SIGNAL(currentFontChanged(QFont)), - characterWidget, SLOT(updateFont(QFont))); - connect(sizeCombo, SIGNAL(currentIndexChanged(QString)), - characterWidget, SLOT(updateSize(QString))); - connect(styleCombo, SIGNAL(currentIndexChanged(QString)), - characterWidget, SLOT(updateStyle(QString))); + connect(fontCombo, &QFontComboBox::currentFontChanged, + this, &MainWindow::findStyles); + connect(fontCombo, &QFontComboBox::currentFontChanged, + this, &MainWindow::findSizes); + connect(fontCombo, &QFontComboBox::currentFontChanged, + characterWidget, &CharacterWidget::updateFont); + typedef void (QComboBox::*QComboBoxStringSignal)(const QString &); + connect(sizeCombo, static_cast(&QComboBox::currentIndexChanged), + characterWidget, &CharacterWidget::updateSize); + connect(styleCombo, static_cast(&QComboBox::currentIndexChanged), + characterWidget, &CharacterWidget::updateStyle); //! [4] //! [5] - connect(characterWidget, SIGNAL(characterSelected(QString)), - this, SLOT(insertCharacter(QString))); + connect(characterWidget, &CharacterWidget::characterSelected, + this, &MainWindow::insertCharacter); #ifndef QT_NO_CLIPBOARD - connect(clipboardButton, SIGNAL(clicked()), this, SLOT(updateClipboard())); + connect(clipboardButton, &QAbstractButton::clicked, this, &MainWindow::updateClipboard); #endif //! [5] - connect(fontMerging, SIGNAL(toggled(bool)), characterWidget, SLOT(updateFontMerging(bool))); + connect(fontMerging, &QAbstractButton::toggled, characterWidget, &CharacterWidget::updateFontMerging); //! [6] QHBoxLayout *controlsLayout = new QHBoxLayout; + controlsLayout->addWidget(filterLabel); + controlsLayout->addWidget(filterCombo, 1); controlsLayout->addWidget(fontLabel); controlsLayout->addWidget(fontCombo, 1); controlsLayout->addWidget(sizeLabel); @@ -153,6 +174,14 @@ void MainWindow::findStyles(const QFont &font) } //! [8] +void MainWindow::filterChanged(int f) +{ + const QFontComboBox::FontFilter filter = + filterCombo->itemData(f).value(); + fontCombo->setFontFilters(filter); + statusBar()->showMessage(tr("%n font(s) found", 0, fontCombo->count())); +} + void MainWindow::findSizes(const QFont &font) { QFontDatabase fontDatabase; @@ -198,9 +227,63 @@ void MainWindow::insertCharacter(const QString &character) void MainWindow::updateClipboard() { //! [11] - clipboard->setText(lineEdit->text(), QClipboard::Clipboard); + QGuiApplication::clipboard()->setText(lineEdit->text(), QClipboard::Clipboard); //! [11] - clipboard->setText(lineEdit->text(), QClipboard::Selection); + QGuiApplication::clipboard()->setText(lineEdit->text(), QClipboard::Selection); } #endif + +class FontInfoDialog : public QDialog +{ +public: + explicit FontInfoDialog(QWidget *parent = Q_NULLPTR); + +private: + QString text() const; +}; + +FontInfoDialog::FontInfoDialog(QWidget *parent) : QDialog(parent) +{ + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + QVBoxLayout *mainLayout = new QVBoxLayout(this); + QPlainTextEdit *textEdit = new QPlainTextEdit(text(), this); + textEdit->setReadOnly(true); + textEdit->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); + mainLayout->addWidget(textEdit); + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close, this); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); + mainLayout->addWidget(buttonBox); +} + +QString FontInfoDialog::text() const +{ + QString text; + QTextStream str(&text); + const QFont defaultFont = QFontDatabase::systemFont(QFontDatabase::GeneralFont); + const QFont fixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); + const QFont titleFont = QFontDatabase::systemFont(QFontDatabase::TitleFont); + const QFont smallestReadableFont = QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont); + + str << "Qt " << QT_VERSION_STR << " on " << QGuiApplication::platformName() + << ", " << logicalDpiX() << "DPI"; + if (!qFuzzyCompare(devicePixelRatioF(), qreal(1))) + str << ", device pixel ratio: " << devicePixelRatioF(); + str << "\n\nDefault font : " << defaultFont.family() << ", " << defaultFont.pointSizeF() << "pt\n" + << "Fixed font : " << fixedFont.family() << ", " << fixedFont.pointSizeF() << "pt\n" + << "Title font : " << titleFont.family() << ", " << titleFont.pointSizeF() << "pt\n" + << "Smallest font: " << smallestReadableFont.family() << ", " << smallestReadableFont.pointSizeF() << "pt\n"; + + return text; +} + +void MainWindow::showInfo() +{ + const QRect screenGeometry = QApplication::desktop()->screenGeometry(this); + FontInfoDialog *dialog = new FontInfoDialog(this); + dialog->setWindowTitle(tr("Fonts")); + dialog->setAttribute(Qt::WA_DeleteOnClose); + dialog->resize(screenGeometry.width() / 4, screenGeometry.height() / 4); + dialog->show(); +} + //! [10] diff --git a/examples/widgets/widgets/charactermap/mainwindow.h b/examples/widgets/widgets/charactermap/mainwindow.h index 75e7e78fed..b24816418b 100644 --- a/examples/widgets/widgets/charactermap/mainwindow.h +++ b/examples/widgets/widgets/charactermap/mainwindow.h @@ -63,18 +63,18 @@ public: MainWindow(); public slots: + void filterChanged(int); void findStyles(const QFont &font); void findSizes(const QFont &font); void insertCharacter(const QString &character); #ifndef QT_NO_CLIPBOARD void updateClipboard(); #endif + void showInfo(); private: CharacterWidget *characterWidget; -#ifndef QT_NO_CLIPBOARD - QClipboard *clipboard; -#endif + QComboBox *filterCombo; QComboBox *styleCombo; QComboBox *sizeCombo; QFontComboBox *fontCombo; -- cgit v1.2.3 From dbb5c95f4d80644c6273b3adbe0148cdf30710d2 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 1 Aug 2016 16:15:13 +0200 Subject: Windows QPA: Handle key event sequences of surrogates Emoji characters as input by the virtual keyboard are received as a sequence of surrogates. Store state internally when a high surrogate is received and send off the sequence when the matching low surrogate is received via input method. Task-number: QTBUG-50617 Change-Id: I91e763ec3e0747d6852f7c5c2057a67b0c24e0f5 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/plugins/platforms/windows/qwindowskeymapper.cpp | 16 ++++++++++++++++ src/plugins/platforms/windows/qwindowskeymapper.h | 1 + 2 files changed, 17 insertions(+) diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index 403ac6ecfb..1e58b9b3d4 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -37,6 +37,7 @@ #include "qwindowswindow.h" #include "qwindowsinputcontext.h" +#include #include #include #include @@ -1072,6 +1073,21 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms if (PeekMessage(&wm_char, 0, charType, charType, PM_REMOVE)) { // Found a ?_CHAR uch = QChar(ushort(wm_char.wParam)); + if (uch.isHighSurrogate()) { + m_lastHighSurrogate = uch; + return true; + } else if (uch.isLowSurrogate() && !m_lastHighSurrogate.isNull()) { + if (QObject *focusObject = QGuiApplication::focusObject()) { + const QChar chars[2] = {m_lastHighSurrogate, uch}; + QInputMethodEvent event; + event.setCommitString(QString(chars, 2)); + QCoreApplication::sendEvent(focusObject, &event); + } + m_lastHighSurrogate = QChar(); + return true; + } else { + m_lastHighSurrogate = QChar(); + } if (msgType == WM_SYSKEYDOWN && uch.isLetter() && (msg.lParam & KF_ALTDOWN)) uch = uch.toLower(); // (See doc of WM_SYSCHAR) Alt-letter if (!code && !uch.row()) diff --git a/src/plugins/platforms/windows/qwindowskeymapper.h b/src/plugins/platforms/windows/qwindowskeymapper.h index 3a3170e4ae..81ae1a3297 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.h +++ b/src/plugins/platforms/windows/qwindowskeymapper.h @@ -97,6 +97,7 @@ private: void deleteLayouts(); QWindow *m_keyGrabber; + QChar m_lastHighSurrogate; static const size_t NumKeyboardLayoutItems = 256; KeyboardLayoutItem keyLayout[NumKeyboardLayoutItems]; }; -- cgit v1.2.3 From 0cec01190f64d19d7d58d7764595d6d6fab8a9d4 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Tue, 2 Aug 2016 16:29:56 +0200 Subject: Fix registered style name of sub-families An old line redefined the altStyleName variable causing sub-families to be registered with their language-name as their style-name. Change-Id: I8c21ad556f53ffd62f8ef9b326fb9431eea1d857 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp index c779c70d4d..02b7e1bd63 100644 --- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp +++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp @@ -493,7 +493,6 @@ static void populateFromPattern(FcPattern *pattern) altFamilyNameLang = familyNameLang; if (familyNameLang == altFamilyNameLang && altStyleName != styleName) { - const QString altStyleName = QString::fromUtf8((const char *)value); FontFile *altFontFile = new FontFile(*fontFile); QPlatformFontDatabase::registerFont(altFamilyName, altStyleName, QLatin1String((const char *)foundry_value),weight,style,stretch,antialias,scalable,pixel_size,fixedPitch,writingSystems,altFontFile); } else { -- cgit v1.2.3 From 2a24c3c268d443fb260d731d9f65b57726a40354 Mon Sep 17 00:00:00 2001 From: Clemens Sielaff Date: Sun, 24 Jul 2016 11:21:34 +1200 Subject: Fixed Bug in QVariant comparison when containing QStringLists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As it were, QStringLists were not handled explicitly when comparing QVariants. If both QStringLists contained only a single entry, they were treated as QStrings - if both QStringLists were empty, there were equal (correctly so) - but if one of the QStringLists had more than one entry, the compare function fell through to returning always 1. As discussed here: https://stackoverflow.com/a/38492467/3444217 Added rich comparison tests for all non-numerical, non-recursive QVariants that support them (except QModelIndex and QPersistentModelIndex) Task-number: QTBUG-54893 Change-Id: Icc5480d9ba056ee5efe83da566c5829caa1509d7 Reviewed-by: Jędrzej Nowacki --- src/corelib/kernel/qvariant.cpp | 2 + .../auto/corelib/kernel/qvariant/tst_qvariant.cpp | 55 ++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 7596699843..4f256cccda 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -3560,6 +3560,8 @@ int QVariant::compare(const QVariant &v) const return v1.toTime() < v2.toTime() ? -1 : 1; case QVariant::DateTime: return v1.toDateTime() < v2.toDateTime() ? -1 : 1; + case QVariant::StringList: + return v1.toStringList() < v2.toStringList() ? -1 : 1; } int r = v1.toString().compare(v2.toString(), Qt::CaseInsensitive); if (r == 0) { diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index 76230ccec8..509eed231d 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -279,6 +279,7 @@ private slots: void metaEnums(); void compareSanity_data(); void compareSanity(); + void compareRich(); void accessSequentialContainerKey(); @@ -4745,6 +4746,60 @@ void tst_QVariant::compareSanity() } } +static void richComparison(const QVariant& less, const QVariant& more) +{ + QVERIFY(less.type() == more.type()); + + QVERIFY(less < more); + QVERIFY(!(more < less)); + + QVERIFY(more > less); + QVERIFY(!(less > more)); + + QVERIFY(less <= more); + QVERIFY(!(more <= less)); + QVERIFY(less <= less); + + QVERIFY(more >= less); + QVERIFY(!(less >= more)); + QVERIFY(more >= more); +} + +void tst_QVariant::compareRich() +{ + richComparison(QUuid("{49d8ad2a-2ee8-4c3d-949f-1b5a3765ddf0}"), + QUuid("{f6d56824-16e9-4543-a375-add2877c2d05}")); + richComparison(QByteArray::fromRawData("a", 1), + QByteArray::fromRawData("b", 1)); + richComparison(QStringLiteral("a"), QStringLiteral("b")); + richComparison(QLatin1String("a"), QLatin1String("b")); + richComparison(QChar('a'), QChar('b')); + richComparison(QDate(2016, 7, 23), QDate(2016, 7, 24)); + richComparison(QTime(0, 0), QTime(0, 1)); + richComparison(QDateTime(QDate(2016, 7, 23), QTime(0, 0)), + QDateTime(QDate(2016, 7, 23), QTime(0, 1))); + + richComparison(QStringList(), QStringList() << QStringLiteral("a")); + richComparison(QStringList(), QStringList() << QStringLiteral("a") + << QStringLiteral("b")); + richComparison(QStringList() << QStringLiteral("a"), + QStringList() << QStringLiteral("b")); + richComparison(QStringList() << QStringLiteral("a"), + QStringList() << QStringLiteral("b") + << QStringLiteral("c")); + richComparison(QStringList() << QStringLiteral("a") + << QStringLiteral("c"), + QStringList() << QStringLiteral("b")); + richComparison(QStringList() << QStringLiteral("a") + << QStringLiteral("c"), + QStringList() << QStringLiteral("b") + << QStringLiteral("d")); + richComparison(QStringList() << QStringLiteral("a") + << QStringLiteral("c"), + QStringList() << QStringLiteral("a") + << QStringLiteral("d")); +} + void tst_QVariant::accessSequentialContainerKey() { QString nameResult; -- cgit v1.2.3 From dbfd7f304c4d91096e104ec2383d92a37502d836 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 3 Aug 2016 10:02:07 +0200 Subject: Windows QPA: Add missing parameter to qWarning() The warning printed when wrapping foreign windows is missing a parameter. Amends change f2ef587906062706e576e376e4c6481ab192f50d. Task-number: QTBUG-41186 Change-Id: Iefbd174c1acc42e87fd1a764d96452b1745aa4c0 Reviewed-by: Simon Hausmann --- src/plugins/platforms/windows/qwindowsintegration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index debe6dd131..f033e4235c 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -313,7 +313,7 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons if (window->type() == Qt::ForeignWindow) { const HWND hwnd = reinterpret_cast(window->winId()); if (!IsWindow(hwnd)) { - qWarning("Windows QPA: Invalid foreign window ID %p."); + qWarning("Windows QPA: Invalid foreign window ID %p.", hwnd); return nullptr; } QWindowsForeignWindow *result = new QWindowsForeignWindow(window, hwnd); -- cgit v1.2.3 From d5be0d30588f6ccd971f73a3c030f9c10d8a6b4e Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 7 Jul 2016 15:30:00 +0200 Subject: Polish the codecs example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Port to Qt 5 connection syntax. - Remove unneeded member variables. - Adapt to screen size. - Add a tab widget with a hex dump view to the preview dialog. - Handle conversion errors in preview dialog, add status label displaying errors and warnings about failures and invalid characters encountered. - Fix translated messages. Change-Id: I916100c903e73d0d2326523753ed7398b1c34df0 Reviewed-by: Topi Reiniö --- examples/widgets/tools/codecs/mainwindow.cpp | 137 +++++++++----------- examples/widgets/tools/codecs/mainwindow.h | 16 +-- examples/widgets/tools/codecs/previewform.cpp | 176 ++++++++++++++++++++++---- examples/widgets/tools/codecs/previewform.h | 16 ++- 4 files changed, 227 insertions(+), 118 deletions(-) diff --git a/examples/widgets/tools/codecs/mainwindow.cpp b/examples/widgets/tools/codecs/mainwindow.cpp index f25be7304e..3c8ec58881 100644 --- a/examples/widgets/tools/codecs/mainwindow.cpp +++ b/examples/widgets/tools/codecs/mainwindow.cpp @@ -45,8 +45,8 @@ MainWindow::MainWindow() { - textEdit = new QTextEdit; - textEdit->setLineWrapMode(QTextEdit::NoWrap); + textEdit = new QPlainTextEdit; + textEdit->setLineWrapMode(QPlainTextEdit::NoWrap); setCentralWidget(textEdit); findCodecs(); @@ -54,54 +54,57 @@ MainWindow::MainWindow() previewForm = new PreviewForm(this); previewForm->setCodecList(codecs); - createActions(); createMenus(); setWindowTitle(tr("Codecs")); - resize(500, 400); + + const QRect screenGeometry = QApplication::desktop()->screenGeometry(this); + resize(screenGeometry.width() / 2, screenGeometry.height() * 2 / 3); } void MainWindow::open() { - QString fileName = QFileDialog::getOpenFileName(this); - if (!fileName.isEmpty()) { - QFile file(fileName); - if (!file.open(QFile::ReadOnly)) { - QMessageBox::warning(this, tr("Codecs"), - tr("Cannot read file %1:\n%2") - .arg(fileName) - .arg(file.errorString())); - return; - } + const QString fileName = QFileDialog::getOpenFileName(this); + if (fileName.isEmpty()) + return; + QFile file(fileName); + if (!file.open(QFile::ReadOnly)) { + QMessageBox::warning(this, tr("Codecs"), + tr("Cannot read file %1:\n%2") + .arg(QDir::toNativeSeparators(fileName), + file.errorString())); + return; + } - QByteArray data = file.readAll(); + const QByteArray data = file.readAll(); - previewForm->setEncodedData(data); - if (previewForm->exec()) - textEdit->setPlainText(previewForm->decodedString()); - } + previewForm->setWindowTitle(tr("Choose Encoding for %1").arg(QFileInfo(fileName).fileName())); + previewForm->setEncodedData(data); + if (previewForm->exec()) + textEdit->setPlainText(previewForm->decodedString()); } void MainWindow::save() { - QString fileName = QFileDialog::getSaveFileName(this); - if (!fileName.isEmpty()) { - QFile file(fileName); - if (!file.open(QFile::WriteOnly | QFile::Text)) { - QMessageBox::warning(this, tr("Codecs"), - tr("Cannot write file %1:\n%2") - .arg(fileName) - .arg(file.errorString())); - return; - } - - QAction *action = qobject_cast(sender()); - QByteArray codecName = action->data().toByteArray(); - - QTextStream out(&file); - out.setCodec(codecName.constData()); - out << textEdit->toPlainText(); + const QAction *action = qobject_cast(sender()); + const QByteArray codecName = action->data().toByteArray(); + const QString title = tr("Save As (%1)").arg(QLatin1String(codecName)); + + QString fileName = QFileDialog::getSaveFileName(this, title); + if (fileName.isEmpty()) + return; + QFile file(fileName); + if (!file.open(QFile::WriteOnly | QFile::Text)) { + QMessageBox::warning(this, tr("Codecs"), + tr("Cannot write file %1:\n%2") + .arg(QDir::toNativeSeparators(fileName), + file.errorString())); + return; } + + QTextStream out(&file); + out.setCodec(codecName.constData()); + out << textEdit->toPlainText(); } void MainWindow::about() @@ -133,9 +136,9 @@ void MainWindow::findCodecs() QString sortKey = codec->name().toUpper(); int rank; - if (sortKey.startsWith("UTF-8")) { + if (sortKey.startsWith(QLatin1String("UTF-8"))) { rank = 1; - } else if (sortKey.startsWith("UTF-16")) { + } else if (sortKey.startsWith(QLatin1String("UTF-16"))) { rank = 2; } else if (iso8859RegExp.exactMatch(sortKey)) { if (iso8859RegExp.cap(1).size() == 1) @@ -145,58 +148,38 @@ void MainWindow::findCodecs() } else { rank = 5; } - sortKey.prepend(QChar('0' + rank)); + sortKey.prepend(QLatin1Char('0' + rank)); codecMap.insert(sortKey, codec); } codecs = codecMap.values(); } -void MainWindow::createActions() +void MainWindow::createMenus() { - openAct = new QAction(tr("&Open..."), this); + QMenu *fileMenu = menuBar()->addMenu(tr("&File")); + QAction *openAct = + fileMenu->addAction(tr("&Open..."), this, &MainWindow::open); openAct->setShortcuts(QKeySequence::Open); - connect(openAct, SIGNAL(triggered()), this, SLOT(open())); - - foreach (QTextCodec *codec, codecs) { - QString text = tr("%1...").arg(QString(codec->name())); - QAction *action = new QAction(text, this); - action->setData(codec->name()); - connect(action, SIGNAL(triggered()), this, SLOT(save())); + QMenu *saveAsMenu = fileMenu->addMenu(tr("&Save As")); + connect(saveAsMenu, &QMenu::aboutToShow, + this, &MainWindow::aboutToShowSaveAsMenu); + foreach (const QTextCodec *codec, codecs) { + const QByteArray name = codec->name(); + QAction *action = saveAsMenu->addAction(tr("%1...").arg(QLatin1String(name))); + action->setData(QVariant(name)); + connect(action, &QAction::triggered, this, &MainWindow::save); saveAsActs.append(action); } - exitAct = new QAction(tr("E&xit"), this); - exitAct->setShortcuts(QKeySequence::Quit); - connect(exitAct, SIGNAL(triggered()), this, SLOT(close())); - - aboutAct = new QAction(tr("&About"), this); - connect(aboutAct, SIGNAL(triggered()), this, SLOT(about())); - - aboutQtAct = new QAction(tr("About &Qt"), this); - connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt())); -} - -void MainWindow::createMenus() -{ - saveAsMenu = new QMenu(tr("&Save As"), this); - foreach (QAction *action, saveAsActs) - saveAsMenu->addAction(action); - connect(saveAsMenu, SIGNAL(aboutToShow()), - this, SLOT(aboutToShowSaveAsMenu())); - - fileMenu = new QMenu(tr("&File"), this); - fileMenu->addAction(openAct); - fileMenu->addMenu(saveAsMenu); fileMenu->addSeparator(); - fileMenu->addAction(exitAct); - - helpMenu = new QMenu(tr("&Help"), this); - helpMenu->addAction(aboutAct); - helpMenu->addAction(aboutQtAct); + QAction *exitAct = fileMenu->addAction(tr("E&xit"), this, &QWidget::close); + exitAct->setShortcuts(QKeySequence::Quit); - menuBar()->addMenu(fileMenu); menuBar()->addSeparator(); - menuBar()->addMenu(helpMenu); + + QMenu *helpMenu = menuBar()->addMenu(tr("&Help")); + helpMenu->addAction(tr("&About"), this, &MainWindow::about); + helpMenu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt); } diff --git a/examples/widgets/tools/codecs/mainwindow.h b/examples/widgets/tools/codecs/mainwindow.h index 7f1d62627e..5455daeb84 100644 --- a/examples/widgets/tools/codecs/mainwindow.h +++ b/examples/widgets/tools/codecs/mainwindow.h @@ -46,9 +46,8 @@ QT_BEGIN_NAMESPACE class QAction; -class QMenu; class QTextCodec; -class QTextEdit; +class QPlainTextEdit; QT_END_NAMESPACE class PreviewForm; @@ -67,21 +66,12 @@ private slots: private: void findCodecs(); - void createActions(); void createMenus(); - QTextEdit *textEdit; + QList saveAsActs; + QPlainTextEdit *textEdit; PreviewForm *previewForm; QList codecs; - - QMenu *fileMenu; - QMenu *helpMenu; - QMenu *saveAsMenu; - QAction *openAct; - QList saveAsActs; - QAction *exitAct; - QAction *aboutAct; - QAction *aboutQtAct; }; #endif diff --git a/examples/widgets/tools/codecs/previewform.cpp b/examples/widgets/tools/codecs/previewform.cpp index f6199a9b35..fdfb90f56c 100644 --- a/examples/widgets/tools/codecs/previewform.cpp +++ b/examples/widgets/tools/codecs/previewform.cpp @@ -42,47 +42,159 @@ #include "previewform.h" +// Helpers for creating hex dumps +static void indent(QTextStream &str, int indent) +{ + for (int i = 0; i < indent; ++i) + str << ' '; +} + +static void formatHex(QTextStream &str, const QByteArray &data) +{ + const int fieldWidth = str.fieldWidth(); + const QTextStream::FieldAlignment alignment = str.fieldAlignment(); + const int base = str.integerBase(); + const QChar padChar = str.padChar(); + str.setIntegerBase(16); + str.setPadChar(QLatin1Char('0')); + str.setFieldAlignment(QTextStream::AlignRight); + + const unsigned char *p = reinterpret_cast(data.constBegin()); + for (const unsigned char *end = p + data.size(); p < end; ++p) { + str << ' '; + str.setFieldWidth(2); + str << unsigned(*p); + str.setFieldWidth(fieldWidth); + } + str.setFieldAlignment(alignment); + str.setPadChar(padChar); + str.setIntegerBase(base); +} + +static void formatPrintableCharacters(QTextStream &str, const QByteArray &data) +{ + for (int i = 0, size = data.size(); i < size; ++i) { + const char c = data.at(i); + switch (c) { + case '\0': + str << "\\0"; + break; + case '\t': + str << "\\t"; + break; + case '\r': + str << "\\r"; + break; + case '\n': + str << "\\n"; + break; + default: + if (c >= 32 && uchar(c) < 127) + str << ' ' << c; + else + str << ".."; + break; + } + } +} + +static QString formatHexDump(const QByteArray &data) +{ + enum { lineWidth = 16 }; + QString result; + QTextStream str(&result); + str.setIntegerBase(16); + str.setPadChar(QLatin1Char('0')); + const int fieldWidth = str.fieldWidth(); + const QTextStream::FieldAlignment alignment = str.fieldAlignment(); + for (int a = 0, size = data.size(); a < size; a += lineWidth) { + str.setFieldAlignment(QTextStream::AlignRight); + str.setFieldWidth(8); + str << a; + str.setFieldWidth(fieldWidth); + str.setFieldAlignment(alignment); + + const int end = qMin(a + lineWidth, size); + const QByteArray line = data.mid(a, end - a); + + formatHex(str, line); + indent(str, 3 * (lineWidth - line.size())); + + str << ' '; + formatPrintableCharacters(str, line); + indent(str, 2 * (lineWidth - line.size())); + str << '\n'; + } + return result; +} + PreviewForm::PreviewForm(QWidget *parent) : QDialog(parent) { + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); encodingComboBox = new QComboBox; - encodingLabel = new QLabel(tr("&Encoding:")); + QLabel *encodingLabel = new QLabel(tr("&Encoding:")); encodingLabel->setBuddy(encodingComboBox); - textEdit = new QTextEdit; - textEdit->setLineWrapMode(QTextEdit::NoWrap); + textEdit = new QPlainTextEdit; + textEdit->setLineWrapMode(QPlainTextEdit::NoWrap); textEdit->setReadOnly(true); + hexDumpEdit = new QPlainTextEdit; + hexDumpEdit->setLineWrapMode(QPlainTextEdit::NoWrap); + hexDumpEdit->setReadOnly(true); + hexDumpEdit->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); - buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok - | QDialogButtonBox::Cancel); + QDialogButtonBox *buttonBox = + new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + okButton = buttonBox->button(QDialogButtonBox::Ok); - connect(encodingComboBox, SIGNAL(activated(int)), - this, SLOT(updateTextEdit())); - connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); - connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + typedef void(QComboBox::*ComboBoxIntSignal)(int); + connect(encodingComboBox, static_cast(&QComboBox::activated), + this, &PreviewForm::updateTextEdit); + connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); + connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); - QGridLayout *mainLayout = new QGridLayout; + QGridLayout *mainLayout = new QGridLayout(this); mainLayout->addWidget(encodingLabel, 0, 0); mainLayout->addWidget(encodingComboBox, 0, 1); - mainLayout->addWidget(textEdit, 1, 0, 1, 2); - mainLayout->addWidget(buttonBox, 2, 0, 1, 2); - setLayout(mainLayout); + tabWidget = new QTabWidget; + tabWidget->addTab(textEdit, tr("Preview")); + tabWidget->addTab(hexDumpEdit, tr("Hex Dump")); + mainLayout->addWidget(tabWidget, 1, 0, 1, 2); + statusLabel = new QLabel; + mainLayout->addWidget(statusLabel, 2, 0, 1, 2); + mainLayout->addWidget(buttonBox, 3, 0, 1, 2); - setWindowTitle(tr("Choose Encoding")); - resize(400, 300); + const QRect screenGeometry = QApplication::desktop()->screenGeometry(this); + resize(screenGeometry.width() * 2 / 5, screenGeometry.height() / 2); } void PreviewForm::setCodecList(const QList &list) { encodingComboBox->clear(); - foreach (QTextCodec *codec, list) - encodingComboBox->addItem(codec->name(), codec->mibEnum()); + foreach (const QTextCodec *codec, list) { + encodingComboBox->addItem(QLatin1String(codec->name()), + QVariant(codec->mibEnum())); + } +} + +void PreviewForm::reset() +{ + decodedStr.clear(); + textEdit->clear(); + hexDumpEdit->clear(); + statusLabel->clear(); + statusLabel->setStyleSheet(QString()); + okButton->setEnabled(false); + tabWidget->setCurrentIndex(0); } void PreviewForm::setEncodedData(const QByteArray &data) { + reset(); encodedData = data; + hexDumpEdit->setPlainText(formatHexDump(data)); updateTextEdit(); } @@ -90,12 +202,30 @@ void PreviewForm::updateTextEdit() { int mib = encodingComboBox->itemData( encodingComboBox->currentIndex()).toInt(); - QTextCodec *codec = QTextCodec::codecForMib(mib); + const QTextCodec *codec = QTextCodec::codecForMib(mib); + const QString name = QLatin1String(codec->name()); - QTextStream in(&encodedData); - in.setAutoDetectUnicode(false); - in.setCodec(codec); - decodedStr = in.readAll(); + QTextCodec::ConverterState state; + decodedStr = codec->toUnicode(encodedData.constData(), encodedData.size(), &state); - textEdit->setPlainText(decodedStr); + bool success = true; + if (state.remainingChars) { + success = false; + const QString message = + tr("%1: conversion error at character %2") + .arg(name).arg(encodedData.size() - state.remainingChars + 1); + statusLabel->setText(message); + statusLabel->setStyleSheet(QStringLiteral("background-color: \"red\";")); + } else if (state.invalidChars) { + statusLabel->setText(tr("%1: %n invalid characters", 0, state.invalidChars).arg(name)); + statusLabel->setStyleSheet(QStringLiteral("background-color: \"yellow\";")); + } else { + statusLabel->setText(tr("%1: %n bytes converted", 0, encodedData.size()).arg(name)); + statusLabel->setStyleSheet(QString()); + } + if (success) + textEdit->setPlainText(decodedStr); + else + textEdit->clear(); + okButton->setEnabled(success); } diff --git a/examples/widgets/tools/codecs/previewform.h b/examples/widgets/tools/codecs/previewform.h index 93bfed3275..1047a50d80 100644 --- a/examples/widgets/tools/codecs/previewform.h +++ b/examples/widgets/tools/codecs/previewform.h @@ -48,8 +48,10 @@ QT_BEGIN_NAMESPACE class QComboBox; class QDialogButtonBox; class QLabel; +class QPlainTextEdit; +class QPushButton; +class QTabWidget; class QTextCodec; -class QTextEdit; QT_END_NAMESPACE class PreviewForm : public QDialog @@ -57,7 +59,7 @@ class PreviewForm : public QDialog Q_OBJECT public: - PreviewForm(QWidget *parent = 0); + explicit PreviewForm(QWidget *parent = Q_NULLPTR); void setCodecList(const QList &list); void setEncodedData(const QByteArray &data); @@ -67,13 +69,17 @@ private slots: void updateTextEdit(); private: + void reset(); + QByteArray encodedData; QString decodedStr; + QPushButton *okButton; + QTabWidget *tabWidget; QComboBox *encodingComboBox; - QLabel *encodingLabel; - QTextEdit *textEdit; - QDialogButtonBox *buttonBox; + QPlainTextEdit *textEdit; + QPlainTextEdit *hexDumpEdit; + QLabel *statusLabel; }; #endif -- cgit v1.2.3 From d1a30be5abcc2d5e5340866434b2691275a135a6 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 5 Jul 2016 13:26:53 +0200 Subject: Polish the findfiles example to be actually useful MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Simplify the code, remove unused members - Fix the translations of plurals to use %n - Add tooltip displaying full paths in list - Add context menu allowing to copy the name and open - Display the correct slashes on Windows - Connect the returnPressed() signals of the line edits - Make the search recursive - Do not search binary files by checking the mime type Change-Id: I3663799c88931db1f58c03ea35211e7ab03737ec Reviewed-by: Topi Reiniö --- examples/widgets/dialogs/findfiles/window.cpp | 139 +++++++++++++++++++------- examples/widgets/dialogs/findfiles/window.h | 6 +- examples/widgets/doc/src/findfiles.qdoc | 38 +++++-- 3 files changed, 135 insertions(+), 48 deletions(-) diff --git a/examples/widgets/dialogs/findfiles/window.cpp b/examples/widgets/dialogs/findfiles/window.cpp index 780c398ad5..ce53dd8c83 100644 --- a/examples/widgets/dialogs/findfiles/window.cpp +++ b/examples/widgets/dialogs/findfiles/window.cpp @@ -42,51 +42,72 @@ #include "window.h" +//! [17] +enum { absoluteFileNameRole = Qt::UserRole + 1 }; +//! [17] + +//! [18] +static inline QString fileNameOfItem(const QTableWidgetItem *item) +{ + return item->data(absoluteFileNameRole).toString(); +} +//! [18] + +//! [14] +static inline void openFile(const QString &fileName) +{ + QDesktopServices::openUrl(QUrl::fromLocalFile(fileName)); +} +//! [14] + //! [0] Window::Window(QWidget *parent) : QWidget(parent) { - browseButton = new QPushButton(tr("&Browse..."), this); + QPushButton *browseButton = new QPushButton(tr("&Browse..."), this); connect(browseButton, &QAbstractButton::clicked, this, &Window::browse); findButton = new QPushButton(tr("&Find"), this); connect(findButton, &QAbstractButton::clicked, this, &Window::find); fileComboBox = createComboBox(tr("*")); + connect(fileComboBox->lineEdit(), &QLineEdit::returnPressed, + this, &Window::animateFindClick); textComboBox = createComboBox(); - directoryComboBox = createComboBox(QDir::currentPath()); + connect(textComboBox->lineEdit(), &QLineEdit::returnPressed, + this, &Window::animateFindClick); + directoryComboBox = createComboBox(QDir::toNativeSeparators(QDir::currentPath())); + connect(directoryComboBox->lineEdit(), &QLineEdit::returnPressed, + this, &Window::animateFindClick); - fileLabel = new QLabel(tr("Named:")); - textLabel = new QLabel(tr("Containing text:")); - directoryLabel = new QLabel(tr("In directory:")); filesFoundLabel = new QLabel; createFilesTable(); //! [0] //! [1] - QGridLayout *mainLayout = new QGridLayout; - mainLayout->addWidget(fileLabel, 0, 0); + QGridLayout *mainLayout = new QGridLayout(this); + mainLayout->addWidget(new QLabel(tr("Named:")), 0, 0); mainLayout->addWidget(fileComboBox, 0, 1, 1, 2); - mainLayout->addWidget(textLabel, 1, 0); + mainLayout->addWidget(new QLabel(tr("Containing text:")), 1, 0); mainLayout->addWidget(textComboBox, 1, 1, 1, 2); - mainLayout->addWidget(directoryLabel, 2, 0); + mainLayout->addWidget(new QLabel(tr("In directory:")), 2, 0); mainLayout->addWidget(directoryComboBox, 2, 1); mainLayout->addWidget(browseButton, 2, 2); mainLayout->addWidget(filesTable, 3, 0, 1, 3); mainLayout->addWidget(filesFoundLabel, 4, 0, 1, 2); mainLayout->addWidget(findButton, 4, 2); - setLayout(mainLayout); setWindowTitle(tr("Find Files")); - resize(700, 300); + const QRect screenGeometry = QApplication::desktop()->screenGeometry(this); + resize(screenGeometry.width() / 2, screenGeometry.height() / 3); } //! [1] //! [2] void Window::browse() { - QString directory = QFileDialog::getExistingDirectory(this, - tr("Find Files"), QDir::currentPath()); + QString directory = + QDir::toNativeSeparators(QFileDialog::getExistingDirectory(this, tr("Find Files"), QDir::currentPath())); if (!directory.isEmpty()) { if (directoryComboBox->findText(directory) == -1) @@ -102,14 +123,28 @@ static void updateComboBox(QComboBox *comboBox) comboBox->addItem(comboBox->currentText()); } +//! [13] + +static void findRecursion(const QString &path, const QString &pattern, QStringList *result) +{ + QDir currentDir(path); + const QString prefix = path + QLatin1Char('/'); + foreach (const QString &match, currentDir.entryList(QStringList(pattern), QDir::Files | QDir::NoSymLinks)) + result->append(prefix + match); + foreach (const QString &dir, currentDir.entryList(QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot)) + findRecursion(prefix + dir, pattern, result); +} + +//! [13] //! [3] + void Window::find() { filesTable->setRowCount(0); QString fileName = fileComboBox->currentText(); QString text = textComboBox->currentText(); - QString path = directoryComboBox->currentText(); + QString path = QDir::cleanPath(directoryComboBox->currentText()); //! [3] updateComboBox(fileComboBox); @@ -117,19 +152,21 @@ void Window::find() updateComboBox(directoryComboBox); //! [4] + currentDir = QDir(path); QStringList files; - if (fileName.isEmpty()) - fileName = "*"; - files = currentDir.entryList(QStringList(fileName), - QDir::Files | QDir::NoSymLinks); - + findRecursion(path, fileName.isEmpty() ? QStringLiteral("*") : fileName, &files); if (!text.isEmpty()) files = findFiles(files, text); showFiles(files); } //! [4] +void Window::animateFindClick() +{ + findButton->animateClick(); +} + //! [5] QStringList Window::findFiles(const QStringList &files, const QString &text) { @@ -139,21 +176,26 @@ QStringList Window::findFiles(const QStringList &files, const QString &text) progressDialog.setWindowTitle(tr("Find Files")); //! [5] //! [6] + QMimeDatabase mimeDatabase; QStringList foundFiles; for (int i = 0; i < files.size(); ++i) { progressDialog.setValue(i); - progressDialog.setLabelText(tr("Searching file number %1 of %2...") - .arg(i).arg(files.size())); - qApp->processEvents(); + progressDialog.setLabelText(tr("Searching file number %1 of %n...", 0, files.size()).arg(i)); + QCoreApplication::processEvents(); //! [6] if (progressDialog.wasCanceled()) break; //! [7] - QFile file(currentDir.absoluteFilePath(files[i])); - + const QString fileName = files.at(i); + const QMimeType mimeType = mimeDatabase.mimeTypeForFile(fileName); + if (mimeType.isValid() && !mimeType.inherits(QStringLiteral("text/plain"))) { + qWarning() << "Not searching binary file " << QDir::toNativeSeparators(fileName); + continue; + } + QFile file(fileName); if (file.open(QIODevice::ReadOnly)) { QString line; QTextStream in(&file); @@ -161,7 +203,7 @@ QStringList Window::findFiles(const QStringList &files, const QString &text) if (progressDialog.wasCanceled()) break; line = in.readLine(); - if (line.contains(text)) { + if (line.contains(text, Qt::CaseInsensitive)) { foundFiles << files[i]; break; } @@ -176,13 +218,18 @@ QStringList Window::findFiles(const QStringList &files, const QString &text) void Window::showFiles(const QStringList &files) { for (int i = 0; i < files.size(); ++i) { - QFile file(currentDir.absoluteFilePath(files[i])); - qint64 size = QFileInfo(file).size(); - - QTableWidgetItem *fileNameItem = new QTableWidgetItem(files[i]); + const QString &fileName = files.at(i); + const QString toolTip = QDir::toNativeSeparators(fileName); + const QString relativePath = QDir::toNativeSeparators(currentDir.relativeFilePath(fileName)); + const qint64 size = QFileInfo(fileName).size(); + QTableWidgetItem *fileNameItem = new QTableWidgetItem(relativePath); + fileNameItem->setData(absoluteFileNameRole, QVariant(fileName)); + fileNameItem->setToolTip(toolTip); fileNameItem->setFlags(fileNameItem->flags() ^ Qt::ItemIsEditable); QTableWidgetItem *sizeItem = new QTableWidgetItem(tr("%1 KB") .arg(int((size + 1023) / 1024))); + sizeItem->setData(absoluteFileNameRole, QVariant(fileName)); + sizeItem->setToolTip(toolTip); sizeItem->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); sizeItem->setFlags(sizeItem->flags() ^ Qt::ItemIsEditable); @@ -191,8 +238,7 @@ void Window::showFiles(const QStringList &files) filesTable->setItem(row, 0, fileNameItem); filesTable->setItem(row, 1, sizeItem); } - filesFoundLabel->setText(tr("%1 file(s) found").arg(files.size()) + - (" (Double click on a file to open it)")); + filesFoundLabel->setText(tr("%n file(s) found (Double click on a file to open it)", 0, files.size())); filesFoundLabel->setWordWrap(true); } //! [8] @@ -220,20 +266,43 @@ void Window::createFilesTable() filesTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); filesTable->verticalHeader()->hide(); filesTable->setShowGrid(false); - +//! [15] + filesTable->setContextMenuPolicy(Qt::CustomContextMenu); + connect(filesTable, &QTableWidget::customContextMenuRequested, + this, &Window::contextMenu); connect(filesTable, &QTableWidget::cellActivated, this, &Window::openFileOfItem); +//! [15] } //! [11] + //! [12] void Window::openFileOfItem(int row, int /* column */) { - QTableWidgetItem *item = filesTable->item(row, 0); - - QDesktopServices::openUrl(QUrl::fromLocalFile(currentDir.absoluteFilePath(item->text()))); + const QTableWidgetItem *item = filesTable->item(row, 0); + openFile(fileNameOfItem(item)); } //! [12] +//! [16] +void Window::contextMenu(const QPoint &pos) +{ + const QTableWidgetItem *item = filesTable->itemAt(pos); + if (!item) + return; + QMenu menu; + QAction *copyAction = menu.addAction("Copy Name"); + QAction *openAction = menu.addAction("Open"); + QAction *action = menu.exec(filesTable->mapToGlobal(pos)); + if (!action) + return; + const QString fileName = fileNameOfItem(item); + if (action == copyAction) + QGuiApplication::clipboard()->setText(QDir::toNativeSeparators(fileName)); + else if (action == openAction) + openFile(fileName); +} +//! [16] diff --git a/examples/widgets/dialogs/findfiles/window.h b/examples/widgets/dialogs/findfiles/window.h index 89dd87b83b..119c0fa100 100644 --- a/examples/widgets/dialogs/findfiles/window.h +++ b/examples/widgets/dialogs/findfiles/window.h @@ -63,7 +63,9 @@ public: private slots: void browse(); void find(); + void animateFindClick(); void openFileOfItem(int row, int column); + void contextMenu(const QPoint &pos); private: QStringList findFiles(const QStringList &files, const QString &text); @@ -74,11 +76,7 @@ private: QComboBox *fileComboBox; QComboBox *textComboBox; QComboBox *directoryComboBox; - QLabel *fileLabel; - QLabel *textLabel; - QLabel *directoryLabel; QLabel *filesFoundLabel; - QPushButton *browseButton; QPushButton *findButton; QTableWidget *filesTable; diff --git a/examples/widgets/doc/src/findfiles.qdoc b/examples/widgets/doc/src/findfiles.qdoc index dd06ed8bb4..df2ef40768 100644 --- a/examples/widgets/doc/src/findfiles.qdoc +++ b/examples/widgets/doc/src/findfiles.qdoc @@ -120,10 +120,12 @@ \snippet dialogs/findfiles/window.cpp 4 We use the directory's path to create a QDir; the QDir class - provides access to directory structures and their contents. We - create a list of the files (contained in the newly created QDir) - that match the specified file name. If the file name is empty - the list will contain all the files in the directory. + provides access to directory structures and their contents. + + \snippet dialogs/findfiles/window.cpp 13 + + We recursively create a list of the files (contained in the newl + created QDir) that match the specified file name. Then we search through all the files in the list, using the private \c findFiles() function, eliminating the ones that don't contain @@ -173,9 +175,7 @@ \snippet dialogs/findfiles/window.cpp 7 - After updating the QProgressDialog, we create a QFile using the - QDir::absoluteFilePath() function which returns the absolute path - name of a file in the directory. We open the file in read-only + After updating the QProgressDialog, we open the file in read-only mode, and read one line at a time using QTextStream. The QTextStream class provides a convenient interface for reading @@ -194,9 +194,18 @@ Both the \c findFiles() and \c showFiles() functions are called from the \c find() slot. In the \c showFiles() function we run through - the provided list of file names, adding each file name to the + the provided list of file names, adding each relative file name to the first column in the table widget and retrieving the file's size using - QFile and QFileInfo for the second column. + QFileInfo for the second column. For later use, we set + the absolute path as a data on the QTableWidget using the + the role absoluteFileNameRole defined to be Qt::UserRole + 1. + + \snippet dialogs/findfiles/window.cpp 17 + + This allows for retrieving the name of an item using a + convenience function: + + \snippet dialogs/findfiles/window.cpp 18 We also update the total number of files found. @@ -236,8 +245,19 @@ \snippet dialogs/findfiles/window.cpp 12 + \snippet dialogs/findfiles/window.cpp 14 + The \c openFileOfItem() slot is invoked when the user double clicks on a cell in the table. The QDesktopServices::openUrl() knows how to open a file given the file name. + + \snippet dialogs/findfiles/window.cpp 15 + \snippet dialogs/findfiles/window.cpp 16 + + We set the context menu policy to of the table view to Qt::CustomContextMenu + and connect a slot contextMenu() to its signal + customContextMenuRequested(). We retrieve the absolute file name + from the data of the QTableWidgetItem and populate the context menu + with actions offering to copy the file name and to open the file. */ -- cgit v1.2.3 From ed38f516bf1a9185ed331c2e5a38648e64a3982a Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 2 Aug 2016 20:29:55 +0300 Subject: QStringListModel: begin/endResetModel() are no signals ... so don't use emit on them. Just confuses readers. Change-Id: I24365fc533b5b35f8942d6014dbc68387aa23e22 Reviewed-by: Friedemann Kleint --- src/corelib/itemmodels/qstringlistmodel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corelib/itemmodels/qstringlistmodel.cpp b/src/corelib/itemmodels/qstringlistmodel.cpp index b0919c5d78..c6a1fac9c8 100644 --- a/src/corelib/itemmodels/qstringlistmodel.cpp +++ b/src/corelib/itemmodels/qstringlistmodel.cpp @@ -301,9 +301,9 @@ QStringList QStringListModel::stringList() const */ void QStringListModel::setStringList(const QStringList &strings) { - emit beginResetModel(); + beginResetModel(); lst = strings; - emit endResetModel(); + endResetModel(); } /*! -- cgit v1.2.3 From f200d5e824761d583ecdcf5cf952b14ec5693049 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 13 Jul 2016 10:41:09 +0200 Subject: Doc: Fix references to Control, Meta key enums MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also make use of qdoc's \note command. Change-Id: I276300cfcfde06e82b04793dbf25df8ec73e9838 Reviewed-by: Leena Miettinen Reviewed-by: Topi Reiniö --- src/gui/kernel/qkeysequence.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/kernel/qkeysequence.cpp b/src/gui/kernel/qkeysequence.cpp index a0818b8d20..f3ebf00224 100644 --- a/src/gui/kernel/qkeysequence.cpp +++ b/src/gui/kernel/qkeysequence.cpp @@ -219,9 +219,9 @@ void Q_GUI_EXPORT qt_set_sequence_auto_mnemonic(bool b) { qt_sequence_no_mnemoni code point of the character; for example, 'A' gives the same key sequence as Qt::Key_A. - \b{Note:} On OS X, references to "Ctrl", Qt::CTRL, Qt::Control + \note On OS X, references to "Ctrl", Qt::CTRL, Qt::Key_Control and Qt::ControlModifier correspond to the \uicontrol Command keys on the - Macintosh keyboard, and references to "Meta", Qt::META, Qt::Meta and + Macintosh keyboard, and references to "Meta", Qt::META, Qt::Key_Meta and Qt::MetaModifier correspond to the \uicontrol Control keys. Developers on OS X can use the same shortcut descriptions across all platforms, and their applications will automatically work as expected on OS X. -- cgit v1.2.3 From bc4ce55fff78610c15d6c8a0cb97526889cb5de3 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Thu, 4 Aug 2016 11:43:44 +0300 Subject: Don't call virtual functions with data from an old model Change-Id: I4f1ec56ce722110042f72761bbc2976e580b7149 Reviewed-by: David Faure Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/widgets/itemviews/qabstractitemview.cpp | 6 ++- .../qabstractitemview/tst_qabstractitemview.cpp | 43 +++++++++++++++++++++- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/widgets/itemviews/qabstractitemview.cpp b/src/widgets/itemviews/qabstractitemview.cpp index cb40eae9a2..d36431c716 100644 --- a/src/widgets/itemviews/qabstractitemview.cpp +++ b/src/widgets/itemviews/qabstractitemview.cpp @@ -769,8 +769,10 @@ void QAbstractItemView::setSelectionModel(QItemSelectionModel *selectionModel) QModelIndex oldCurrentIndex; if (d->selectionModel) { - oldSelection = d->selectionModel->selection(); - oldCurrentIndex = d->selectionModel->currentIndex(); + if (d->selectionModel->model() == selectionModel->model()) { + oldSelection = d->selectionModel->selection(); + oldCurrentIndex = d->selectionModel->currentIndex(); + } disconnect(d->selectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(selectionChanged(QItemSelection,QItemSelection))); diff --git a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp index a62147b707..27c9e07037 100644 --- a/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp +++ b/tests/auto/widgets/itemviews/qabstractitemview/tst_qabstractitemview.cpp @@ -1939,11 +1939,18 @@ void tst_QAbstractItemView::QTBUG50535_update_on_new_selection_model() { public: ListView() - : m_paintEventsCount(0) + : m_paintEventsCount(0), m_deselectedMustBeEmpty(false), m_selectionChangedOk(true) { } + void setSelectionModel(QItemSelectionModel *model) Q_DECL_OVERRIDE + { + m_deselectedMustBeEmpty = !selectionModel() || !model || selectionModel()->model() != model->model(); + QListView::setSelectionModel(model); + m_deselectedMustBeEmpty = false; + } int m_paintEventsCount; + bool selectionChangedOk() const { return m_selectionChangedOk; } protected: bool viewportEvent(QEvent *event) Q_DECL_OVERRIDE @@ -1952,6 +1959,24 @@ void tst_QAbstractItemView::QTBUG50535_update_on_new_selection_model() ++m_paintEventsCount; return QListView::viewportEvent(event); } + + void selectionChanged(const QItemSelection &selected, + const QItemSelection &deselected) Q_DECL_OVERRIDE + { + if (m_deselectedMustBeEmpty && !deselected.isEmpty()) + m_selectionChangedOk = false; + + // Make sure both selections belong to the same model + foreach (const QModelIndex &nmi, selected.indexes()) { + foreach (const QModelIndex &omi, deselected.indexes()) { + m_selectionChangedOk = m_selectionChangedOk && (nmi.model() == omi.model()); + } + } + QListView::selectionChanged(selected, deselected); + } + private: + bool m_deselectedMustBeEmpty; + bool m_selectionChangedOk; }; // keep the current/selected row in the "low range", i.e. be sure it's visible, otherwise we @@ -1962,7 +1987,7 @@ void tst_QAbstractItemView::QTBUG50535_update_on_new_selection_model() view.selectionModel()->setCurrentIndex(model.index(1, 0), QItemSelectionModel::SelectCurrent); view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); - + QVERIFY(view.selectionChangedOk()); QItemSelectionModel selectionModel(&model); selectionModel.setCurrentIndex(model.index(2, 0), QItemSelectionModel::Current); @@ -1970,6 +1995,7 @@ void tst_QAbstractItemView::QTBUG50535_update_on_new_selection_model() int oldPaintEventsCount = view.m_paintEventsCount; view.setSelectionModel(&selectionModel); QTRY_VERIFY(view.m_paintEventsCount > oldPaintEventsCount); + QVERIFY(view.selectionChangedOk()); QItemSelectionModel selectionModel2(&model); @@ -1979,6 +2005,19 @@ void tst_QAbstractItemView::QTBUG50535_update_on_new_selection_model() oldPaintEventsCount = view.m_paintEventsCount; view.setSelectionModel(&selectionModel2); QTRY_VERIFY(view.m_paintEventsCount > oldPaintEventsCount); + QVERIFY(view.selectionChangedOk()); + + // Tests QAbstractItemView::selectionChanged + QStandardItemModel model1; + for (int i = 0; i < 10; ++i) + model1.appendRow(new QStandardItem(QString::number(i))); + view.setModel(&model1); + + QItemSelectionModel selectionModel1(&model1); + selectionModel1.select(model1.index(0, 0), QItemSelectionModel::ClearAndSelect); + selectionModel1.setCurrentIndex(model1.index(1, 0), QItemSelectionModel::Current); + view.setSelectionModel(&selectionModel1); + QVERIFY(view.selectionChangedOk()); } void tst_QAbstractItemView::testSelectionModelInSyncWithView() -- cgit v1.2.3 From b643d6f347a72ebe97f63dce1d63414d8ced6405 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Wed, 3 Aug 2016 14:20:54 +0200 Subject: Fix 64-bit bilinear scaled image sampling A constraint ensuring we do not sample beyond the current scan-line was missing in the SSE2 optimized sampling. Discovered with lancelot. Change-Id: Ib0ece8f8bfaa034733873dc5b8baaaad5d4c0380 Reviewed-by: Erik Verbruggen --- src/gui/painting/qdrawhelper.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp index f0e5810b54..a0f7155c67 100644 --- a/src/gui/painting/qdrawhelper.cpp +++ b/src/gui/painting/qdrawhelper.cpp @@ -2815,10 +2815,16 @@ static const QRgba64 *QT_FASTCALL fetchTransformedBilinear64(QRgba64 *buffer, co sbuf2[i * 2 + 1] = ((const uint*)s2)[x2]; fx += fdx; } + int fastLen; + if (fdx > 0) + fastLen = qMin(len, int((image_x2 - (fx >> 16)) / data->m11)); + else + fastLen = qMin(len, int((image_x1 - (fx >> 16)) / data->m11)); + fastLen -= 3; const __m128i v_fdx = _mm_set1_epi32(fdx*4); __m128i v_fx = _mm_setr_epi32(fx, fx + fdx, fx + fdx + fdx, fx + fdx + fdx + fdx); - for (; i < len-3; i+=4) { + for (; i < fastLen; i += 4) { int offset = _mm_extract_epi16(v_fx, 1); sbuf1[i * 2 + 0] = ((const uint*)s1)[offset]; sbuf1[i * 2 + 1] = ((const uint*)s1)[offset + 1]; -- cgit v1.2.3 From 457d91bb07a8ad0d1a582016566ba5119bb1ac95 Mon Sep 17 00:00:00 2001 From: charlycha Date: Tue, 9 Feb 2016 06:36:07 +0100 Subject: raspberry pi: manage eglfs display id with env var Specify the display to use by setting environment variable QT_QPA_EGLFS_DISPMANX_ID Possible values are : 0: MAIN LCD 1: AUX LCD 2: HDMI 3: SDTV 4: FORCE LCD 5: FORCE TV 6: FORCE OTHER Change-Id: I146db9a7f423bd4c6c1716c64d3df4d2388e85f9 Reviewed-by: Andy Nichols --- .../eglfs_brcm/qeglfsbrcmintegration.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.cpp index 4813d9be04..544ac31877 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_brcm/qeglfsbrcmintegration.cpp @@ -87,9 +87,23 @@ void QEglFSBrcmIntegration::platformInit() bcm_host_init(); } +static int getDisplayId() +{ + // As defined in vc_dispmanx_types.h + // DISPMANX_ID_MAIN_LCD 0 + // DISPMANX_ID_AUX_LCD 1 + // DISPMANX_ID_HDMI 2 + // DISPMANX_ID_SDTV 3 + // DISPMANX_ID_FORCE_LCD 4 + // DISPMANX_ID_FORCE_TV 5 + // DISPMANX_ID_FORCE_OTHER 6 /* non-default display */ + static const int dispmanxId = qEnvironmentVariableIntValue("QT_QPA_EGLFS_DISPMANX_ID"); + return (dispmanxId >= 0 && dispmanxId <= 6) ? dispmanxId : 0; +} + EGLNativeDisplayType QEglFSBrcmIntegration::platformDisplay() const { - dispman_display = vc_dispmanx_display_open(0/* LCD */); + dispman_display = vc_dispmanx_display_open(getDisplayId()); return EGL_DEFAULT_DISPLAY; } @@ -101,7 +115,7 @@ void QEglFSBrcmIntegration::platformDestroy() QSize QEglFSBrcmIntegration::screenSize() const { uint32_t width, height; - graphics_get_display_size(0 /* LCD */, &width, &height); + graphics_get_display_size(getDisplayId(), &width, &height); return QSize(width, height); } -- cgit v1.2.3 From 595c6abf9d2cb666f2502bbf89ab3a7052717027 Mon Sep 17 00:00:00 2001 From: Alex Trotsenko Date: Thu, 28 Jul 2016 17:28:27 +0300 Subject: QLocalSocket/Tcp: open device before making a connection According to QLocalSocket's documentation, connectToServer() must initiate a connection attempt after opening the device. Otherwise, if a connection succeeds immediately, connected() signal will be emitted on closed device. So, this patch ensures that TCP-based implementation behaves correctly. Change-Id: I4cc9474815e091a1491a429a6dc17f9cf0154f58 Reviewed-by: Oswald Buddenhagen Reviewed-by: Thiago Macieira --- src/network/socket/qlocalsocket_tcp.cpp | 2 +- tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/network/socket/qlocalsocket_tcp.cpp b/src/network/socket/qlocalsocket_tcp.cpp index c0140e574e..461ece837f 100644 --- a/src/network/socket/qlocalsocket_tcp.cpp +++ b/src/network/socket/qlocalsocket_tcp.cpp @@ -239,8 +239,8 @@ void QLocalSocket::connectToServer(OpenMode openMode) QLatin1String("QLocalSocket::connectToServer")); return; } - d->tcpSocket->connectToHost(QHostAddress::LocalHost, port, openMode); QIODevice::open(openMode); + d->tcpSocket->connectToHost(QHostAddress::LocalHost, port, openMode); } bool QLocalSocket::setSocketDescriptor(qintptr socketDescriptor, diff --git a/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp b/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp index 6e55b15a18..33aceb9159 100644 --- a/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp +++ b/tests/auto/network/socket/qlocalsocket/tst_qlocalsocket.cpp @@ -190,6 +190,7 @@ private slots: void slotConnected() { QCOMPARE(state(), QLocalSocket::ConnectedState); + QVERIFY(isOpen()); } void slotDisconnected() { -- cgit v1.2.3 From 35117590c8f4634ddfdbe75966dd43adeca69369 Mon Sep 17 00:00:00 2001 From: Kai Pastor Date: Fri, 3 Jun 2016 07:33:55 +0200 Subject: Remove unneeded ';' after some macros The unneeded ';' triggered warnings in pedantic compilation mode. Change-Id: Id2324823e138560bb25234306601253d7bbd713e Reviewed-by: Richard J. Moore Reviewed-by: Friedemann Kleint Reviewed-by: Allan Sandfeld Jensen --- src/gui/image/qpixmap_blitter_p.h | 2 +- src/gui/opengl/qopengltextureblitter_p.h | 4 ++-- src/gui/painting/qblittable_p.h | 2 +- src/gui/painting/qdatabuffer_p.h | 2 +- src/gui/painting/qpaintengine_blitter_p.h | 2 +- src/network/ssl/qsslsocket_mac_p.h | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/gui/image/qpixmap_blitter_p.h b/src/gui/image/qpixmap_blitter_p.h index 6dbcbd91be..e1444f6279 100644 --- a/src/gui/image/qpixmap_blitter_p.h +++ b/src/gui/image/qpixmap_blitter_p.h @@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE class Q_GUI_EXPORT QBlittablePlatformPixmap : public QPlatformPixmap { -// Q_DECLARE_PRIVATE(QBlittablePlatformPixmap); +// Q_DECLARE_PRIVATE(QBlittablePlatformPixmap) public: QBlittablePlatformPixmap(); ~QBlittablePlatformPixmap(); diff --git a/src/gui/opengl/qopengltextureblitter_p.h b/src/gui/opengl/qopengltextureblitter_p.h index ebf3a4bfbb..65149d2cb0 100644 --- a/src/gui/opengl/qopengltextureblitter_p.h +++ b/src/gui/opengl/qopengltextureblitter_p.h @@ -83,8 +83,8 @@ public: static QMatrix3x3 sourceTransform(const QRectF &subTexture, const QSize &textureSize, Origin origin); private: - Q_DISABLE_COPY(QOpenGLTextureBlitter); - Q_DECLARE_PRIVATE(QOpenGLTextureBlitter); + Q_DISABLE_COPY(QOpenGLTextureBlitter) + Q_DECLARE_PRIVATE(QOpenGLTextureBlitter) QScopedPointer d_ptr; }; diff --git a/src/gui/painting/qblittable_p.h b/src/gui/painting/qblittable_p.h index 47218f2f35..1a5c507348 100644 --- a/src/gui/painting/qblittable_p.h +++ b/src/gui/painting/qblittable_p.h @@ -57,7 +57,7 @@ class QBlittablePrivate; class Q_GUI_EXPORT QBlittable { - Q_DECLARE_PRIVATE(QBlittable); + Q_DECLARE_PRIVATE(QBlittable) public: enum Capability { diff --git a/src/gui/painting/qdatabuffer_p.h b/src/gui/painting/qdatabuffer_p.h index 3fe39efdde..2a6b1bde4c 100644 --- a/src/gui/painting/qdatabuffer_p.h +++ b/src/gui/painting/qdatabuffer_p.h @@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE template class QDataBuffer { - Q_DISABLE_COPY(QDataBuffer); + Q_DISABLE_COPY(QDataBuffer) public: QDataBuffer(int res) { diff --git a/src/gui/painting/qpaintengine_blitter_p.h b/src/gui/painting/qpaintengine_blitter_p.h index ab44851ec7..e960fbcfa8 100644 --- a/src/gui/painting/qpaintengine_blitter_p.h +++ b/src/gui/painting/qpaintengine_blitter_p.h @@ -56,7 +56,7 @@ class QBlittable; class Q_GUI_EXPORT QBlitterPaintEngine : public QRasterPaintEngine { - Q_DECLARE_PRIVATE(QBlitterPaintEngine); + Q_DECLARE_PRIVATE(QBlitterPaintEngine) public: QBlitterPaintEngine(QBlittablePlatformPixmap *p); diff --git a/src/network/ssl/qsslsocket_mac_p.h b/src/network/ssl/qsslsocket_mac_p.h index 7a622db185..e8d9d34693 100644 --- a/src/network/ssl/qsslsocket_mac_p.h +++ b/src/network/ssl/qsslsocket_mac_p.h @@ -68,7 +68,7 @@ public: private: SSLContextRef context; - Q_DISABLE_COPY(QSecureTransportContext); + Q_DISABLE_COPY(QSecureTransportContext) }; class QSslSocketBackendPrivate : public QSslSocketPrivate @@ -115,7 +115,7 @@ private: QSecureTransportContext context; - Q_DISABLE_COPY(QSslSocketBackendPrivate); + Q_DISABLE_COPY(QSslSocketBackendPrivate) }; QT_END_NAMESPACE -- cgit v1.2.3 From 9c8a8e90a6514c23bcbeb14073a9d6bdd926d68b Mon Sep 17 00:00:00 2001 From: Anton Kudryavtsev Date: Mon, 11 Jul 2016 17:23:21 +0300 Subject: QString: fix append(const QStringRef &str) Use QStringRef::isNull instead of QStringRef::string() for validation. Non-NULL str.string() may yet leave us with a useless str.unicode(), which is the actual problem here; whereas !str.isNull() does really confirm that str.unicode() is sensible. Such test prevents situation like: const QString a; QString b; b.append(a); // b.isNull() == true b.append(QStringRef(&a)); // b.isNull() == false Auto test updated: create QStringRef from QString directly, without any condition. Change-Id: I082cd58ef656d8a53e3c1223aca01feea82fffb9 Reviewed-by: Thiago Macieira Reviewed-by: Marc Mutz --- src/corelib/tools/qstring.cpp | 2 +- tests/auto/corelib/tools/qstring/tst_qstring.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index b5119444b7..9aeec77632 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -9375,7 +9375,7 @@ QString &QString::append(const QStringRef &str) { if (str.string() == this) { str.appendTo(this); - } else if (str.string()) { + } else if (!str.isNull()) { int oldSize = size(); resize(oldSize + str.size()); memcpy(data() + oldSize, str.unicode(), str.size() * sizeof(QChar)); diff --git a/tests/auto/corelib/tools/qstring/tst_qstring.cpp b/tests/auto/corelib/tools/qstring/tst_qstring.cpp index da6cdddd4f..db4c33afde 100644 --- a/tests/auto/corelib/tools/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/tools/qstring/tst_qstring.cpp @@ -131,7 +131,7 @@ template <> class Arg : ArgBase { QStringRef ref() const - { return this->pinned.isNull() ? QStringRef() : this->pinned.midRef(0) ; } + { return QStringRef(&pinned); } public: explicit Arg(const char *str) : ArgBase(str) {} -- cgit v1.2.3 From 47511046a404d223021b72aadd660e18faa2b90c Mon Sep 17 00:00:00 2001 From: Jake Petroules Date: Tue, 5 Jul 2016 11:52:59 -0700 Subject: Fix rasterwindow example At least with the eglfs platform plugin, the QBackingStore constructor results in a null pointer access if done before creation. Change-Id: I2e78e70700fa48499a35c55797e1b962b6e6285a Reviewed-by: Rebecca Worledge Reviewed-by: Andy Nichols --- examples/gui/rasterwindow/rasterwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gui/rasterwindow/rasterwindow.cpp b/examples/gui/rasterwindow/rasterwindow.cpp index 96fe5297c8..f343ab6c30 100644 --- a/examples/gui/rasterwindow/rasterwindow.cpp +++ b/examples/gui/rasterwindow/rasterwindow.cpp @@ -45,8 +45,8 @@ RasterWindow::RasterWindow(QWindow *parent) : QWindow(parent) , m_update_pending(false) { - m_backingStore = new QBackingStore(this); create(); + m_backingStore = new QBackingStore(this); setGeometry(100, 100, 300, 200); -- cgit v1.2.3 From 91a2c8630b2204831566ab8e523c747f9d8ec927 Mon Sep 17 00:00:00 2001 From: David Faure Date: Tue, 2 Aug 2016 14:07:37 +0200 Subject: QUrl::resolved: keep treating file:name.txt as relative for now 8a33077 made QUrl::resolved() follow its documentation ("If relative is not a relative URL, this function will return relative directly.", where relative means scheme is empty). However there is much code out there (e.g. qtdeclarative) which relies on QUrl::fromLocalFile("fileName.txt") to be treated as relative, so for now, we still allow this (in Qt 5.6.x). For Qt 5.8, this commit will be reverted. [ChangeLog][QtCore][QUrl] [EDITORIAL: replaces 8a33077] QUrl::resolved() no longer treats a URL with a scheme as a relative URL if it matches this URL's scheme. For now it still treats "file:name.txt" as relative for compatibility, but be warned that in Qt 5.8 it will no longer consider those to be relative. Both isRelative() and RFC 3986 say that such URLs are not relative, so starting from Qt 5.8, resolved() will return them as is. Change-Id: Iff01e5b470319f6c46526086d765187e2259bdf5 Reviewed-by: Thiago Macieira Reviewed-by: Oswald Buddenhagen --- src/corelib/io/qurl.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index 1fe529d48d..a5643d123d 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -3167,7 +3167,8 @@ QUrl QUrl::resolved(const QUrl &relative) const if (!relative.d) return *this; QUrl t; - if (!relative.d->scheme.isEmpty()) { + // Compatibility hack (mostly for qtdeclarative) : treat "file:relative.txt" as relative even though QUrl::isRelative() says false + if (!relative.d->scheme.isEmpty() && (!relative.isLocalFile() || QDir::isAbsolutePath(relative.d->path))) { t = relative; t.detach(); } else { -- cgit v1.2.3 From 9b3a7ece479997fc093ae913255b37c937291795 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Thu, 4 Aug 2016 15:21:47 +0200 Subject: Re-add the space character as a document terminator With change 208496091d994c2ffe44ea41368fb659978c1581 the space character was replaced with a visual document terminator character. However this meant that if the whitespace was visualized without the document terminator character visualized then clicking after the text would cause it to be positioned off by one. By bringing back the space character when the terminator is not being visualized then it will correctly place the cursor at the end of the text. Change-Id: I335c1773a37a654f3196bd350562e8f92ffd5369 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/text/qtextengine.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 28fb9d2769..7378b129a9 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -1569,12 +1569,13 @@ void QTextEngine::validate() const layoutData = new LayoutData(); if (block.docHandle()) { layoutData->string = block.text(); - if (block.next().isValid()) { - if (option.flags() & QTextOption::ShowLineAndParagraphSeparators) - layoutData->string += QChar(0xb6); - } else if (option.flags() & QTextOption::ShowDocumentTerminator) { + const bool nextBlockValid = block.next().isValid(); + if (!nextBlockValid && option.flags() & QTextOption::ShowDocumentTerminator) { layoutData->string += QChar(0xA7); + } else if (option.flags() & QTextOption::ShowLineAndParagraphSeparators) { + layoutData->string += QLatin1Char(nextBlockValid ? 0xb6 : 0x20); } + } else { layoutData->string = text; } -- cgit v1.2.3 From ebde32ae3d743ad1d3f70295317dcea9c0377314 Mon Sep 17 00:00:00 2001 From: Andreas Wilhelm Date: Fri, 15 Jul 2016 14:40:00 +0200 Subject: qdbusxml2cpp: Ported to QCommandLineParser Change-Id: I8a91a376ba60b110fff9eb84e1b02e3c6e8c5e30 Reviewed-by: Rolf Eike Beer Reviewed-by: Thiago Macieira --- src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp | 203 ++++++++++++-------------------- 1 file changed, 74 insertions(+), 129 deletions(-) diff --git a/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp b/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp index 8fc54794bc..e58f194b72 100644 --- a/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp +++ b/src/tools/qdbusxml2cpp/qdbusxml2cpp.cpp @@ -27,6 +27,8 @@ ****************************************************************************/ #include +#include +#include #include #include #include @@ -59,30 +61,6 @@ static QString commandLine; static QStringList includes; static QStringList wantedInterfaces; -static const char help[] = - "Usage: " PROGRAMNAME " [options...] [xml-or-xml-file] [interfaces...]\n" - "Produces the C++ code to implement the interfaces defined in the input file.\n" - "\n" - "Options:\n" - " -a Write the adaptor code to \n" - " -c Use as the class name for the generated classes\n" - " -h Show this information\n" - " -i Add #include to the output\n" - " -l When generating an adaptor, use as the parent class\n" - " -m Generate #include \"filename.moc\" statements in the .cpp files\n" - " -N Don't use namespaces\n" - " -p Write the proxy code to \n" - " -v Be verbose.\n" - " -V Show the program version and quit.\n" - "\n" - "If the file name given to the options -a and -p does not end in .cpp or .h, the\n" - "program will automatically append the suffixes and produce both files.\n" - "You can also use a colon (:) to separate the header name from the source file\n" - "name, as in '-a filename_p.h:filename.cpp'.\n" - "\n" - "If you pass a dash (-) as the argument to either -p or -a, the output is written\n" - "to the standard output\n"; - static const char includeList[] = "#include \n" "#include \n" @@ -101,105 +79,6 @@ static const char forwardDeclarations[] = "class QVariant;\n" "QT_END_NAMESPACE\n"; -static void showHelp() -{ - printf("%s", help); - exit(0); -} - -static void showVersion() -{ - printf("%s version %s\n", PROGRAMNAME, PROGRAMVERSION); - printf("D-Bus binding tool for Qt\n"); - exit(0); -} - -static QString nextArg(QStringList &args, int i, char opt) -{ - QString arg = args.value(i); - if (arg.isEmpty()) { - printf("-%c needs at least one argument\n", opt); - exit(1); - } - return args.takeAt(i); -} - -static void parseCmdLine(QStringList args) -{ - args.takeFirst(); - - commandLine = QLatin1String(PROGRAMNAME " "); - commandLine += args.join(QLatin1Char(' ')); - - int i = 0; - while (i < args.count()) { - - if (!args.at(i).startsWith(QLatin1Char('-'))) { - ++i; - continue; - } - QString arg = args.takeAt(i); - - char c = '\0'; - if (arg.length() == 2) - c = arg.at(1).toLatin1(); - else if (arg == QLatin1String("--help")) - c = 'h'; - - switch (c) { - case 'a': - adaptorFile = nextArg(args, i, 'a'); - break; - - case 'c': - globalClassName = nextArg(args, i, 'c'); - break; - - case 'v': - verbose = true; - break; - - case 'i': - includes << nextArg(args, i, 'i'); - break; - - case 'l': - parentClassName = nextArg(args, i, 'l'); - break; - - case 'm': - includeMocs = true; - break; - - case 'N': - skipNamespaces = true; - break; - - case '?': - case 'h': - showHelp(); - break; - - case 'V': - showVersion(); - break; - - case 'p': - proxyFile = nextArg(args, i, 'p'); - break; - - default: - printf("unknown option: '%s'\n", qPrintable(arg)); - exit(1); - } - } - - if (!args.isEmpty()) - inputFile = args.takeFirst(); - - wantedInterfaces << args; -} - static QDBusIntrospection::Interfaces readInput() { QFile input(inputFile); @@ -1139,13 +1018,79 @@ static void writeAdaptor(const QString &filename, const QDBusIntrospection::Inte int main(int argc, char **argv) { - QStringList arguments; - arguments.reserve(argc); - for (int i = 0; i < argc; ++i) { - arguments.append(QString::fromLocal8Bit(argv[i])); - } + QCoreApplication app(argc, argv); + QCoreApplication::setApplicationName(QStringLiteral(PROGRAMNAME)); + QCoreApplication::setApplicationVersion(QStringLiteral(PROGRAMVERSION)); + + QCommandLineParser parser; + parser.setApplicationDescription(QLatin1String( + "Produces the C++ code to implement the interfaces defined in the input file.\n\n" + "If the file name given to the options -a and -p does not end in .cpp or .h, the\n" + "program will automatically append the suffixes and produce both files.\n" + "You can also use a colon (:) to separate the header name from the source file\n" + "name, as in '-a filename_p.h:filename.cpp'.\n\n" + "If you pass a dash (-) as the argument to either -p or -a, the output is written\n" + "to the standard output.")); + + parser.addHelpOption(); + parser.addVersionOption(); + parser.addPositionalArgument(QStringLiteral("xml-or-xml-file"), QStringLiteral("XML file to use.")); + parser.addPositionalArgument(QStringLiteral("interfaces"), QStringLiteral("List of interfaces to use."), + QStringLiteral("[interfaces ...]")); + + QCommandLineOption adapterCodeOption(QStringList() << QStringLiteral("a") << QStringLiteral("adaptor"), + QStringLiteral("Write the adaptor code to "), QStringLiteral("filename")); + parser.addOption(adapterCodeOption); + + QCommandLineOption classNameOption(QStringList() << QStringLiteral("c") << QStringLiteral("classname"), + QStringLiteral("Use as the class name for the generated classes"), QStringLiteral("classname")); + parser.addOption(classNameOption); + + QCommandLineOption addIncludeOption(QStringList() << QStringLiteral("i") << QStringLiteral("include"), + QStringLiteral("Add #include to the output"), QStringLiteral("filename")); + parser.addOption(addIncludeOption); + + QCommandLineOption adapterParentOption(QStringLiteral("l"), + QStringLiteral("When generating an adaptor, use as the parent class"), QStringLiteral("classname")); + parser.addOption(adapterParentOption); + + QCommandLineOption mocIncludeOption(QStringList() << QStringLiteral("m") << QStringLiteral("moc"), + QStringLiteral("Generate #include \"filename.moc\" statements in the .cpp files")); + parser.addOption(mocIncludeOption); + + QCommandLineOption noNamespaceOption(QStringList() << QStringLiteral("N") << QStringLiteral("no-namespaces"), + QStringLiteral("Don't use namespaces")); + parser.addOption(noNamespaceOption); + + QCommandLineOption proxyCodeOption(QStringList() << QStringLiteral("p") << QStringLiteral("proxy"), + QStringLiteral("Write the proxy code to "), QStringLiteral("filename")); + parser.addOption(proxyCodeOption); + + QCommandLineOption verboseOption(QStringList() << QStringLiteral("V") << QStringLiteral("verbose"), + QStringLiteral("Be verbose.")); + parser.addOption(verboseOption); + + parser.process(app); + + adaptorFile = parser.value(adapterCodeOption); + globalClassName = parser.value(classNameOption); + includes = parser.values(addIncludeOption); + parentClassName = parser.value(adapterParentOption); + includeMocs = parser.isSet(mocIncludeOption); + skipNamespaces = parser.isSet(noNamespaceOption); + proxyFile = parser.value(proxyCodeOption); + verbose = parser.isSet(verboseOption); + + wantedInterfaces = parser.positionalArguments(); + if (!wantedInterfaces.isEmpty()) { + inputFile = wantedInterfaces.takeFirst(); - parseCmdLine(arguments); + QFileInfo inputInfo(inputFile); + if (!inputInfo.exists() || !inputInfo.isFile() || !inputInfo.isReadable()) { + qCritical("Error: Input %s is not a file or cannot be accessed\n", qPrintable(inputFile)); + return 1; + } + } QDBusIntrospection::Interfaces interfaces = readInput(); cleanInterfaces(interfaces); -- cgit v1.2.3 From 7f66289f9d36458b0ab52d02d35ca4aa3ae722c4 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 3 Aug 2016 09:16:03 +0200 Subject: Windows QPA: Introduce command line options for DirectWrite Add option "nodirectwrite" to turn off DirectWrite fonts and "nocolorfonts" to turn off DirectWrite for colored fonts. Task-number: QTBUG-55096 Task-number: QTBUG-55097 Change-Id: If12133fbd20dc7657b3616eff833a8e8c116e070 Reviewed-by: Eskil Abrahamsen Blomfeldt --- .../platforms/windows/qwindowsfontdatabase.cpp | 32 ++++++++++++++-------- .../platforms/windows/qwindowsintegration.cpp | 4 +++ .../platforms/windows/qwindowsintegration.h | 4 ++- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp index 68a8fc5390..08769a3b39 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp @@ -40,6 +40,7 @@ #include "qwindowsfontdatabase.h" #include "qwindowsfontdatabase_ft.h" // for default font #include "qwindowscontext.h" +#include "qwindowsintegration.h" #include "qwindowsfontengine.h" #include "qwindowsfontenginedirectwrite.h" #include "qtwindows_additional.h" @@ -112,6 +113,18 @@ static void createDirectWriteFactory(IDWriteFactory **factory) *factory = static_cast(result); } + +static inline bool useDirectWrite(QFont::HintingPreference hintingPreference, bool isColorFont = false) +{ + const unsigned options = QWindowsIntegration::instance()->options(); + if (Q_UNLIKELY(options & QWindowsIntegration::DontUseDirectWriteFonts)) + return false; + if (isColorFont) + return (options & QWindowsIntegration::DontUseColorFonts) == 0; + return hintingPreference == QFont::PreferNoHinting + || hintingPreference == QFont::PreferVerticalHinting + || (QHighDpiScaling::isActive() && hintingPreference == QFont::PreferDefaultHinting); +} #endif // !QT_NO_DIRECTWRITE // Helper classes for creating font engines directly from font data @@ -1163,11 +1176,7 @@ QFontEngine *QWindowsFontDatabase::fontEngine(const QByteArray &fontData, qreal QFontEngine *fontEngine = 0; #if !defined(QT_NO_DIRECTWRITE) - bool useDirectWrite = (hintingPreference == QFont::PreferNoHinting) - || (hintingPreference == QFont::PreferVerticalHinting) - || (QHighDpiScaling::isActive() && hintingPreference == QFont::PreferDefaultHinting); - - if (!useDirectWrite) + if (!useDirectWrite(hintingPreference)) #endif { GUID guid; @@ -1804,12 +1813,13 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, isColorFont = true; } #endif - - bool useDirectWrite = (request.hintingPreference == QFont::PreferNoHinting) - || (request.hintingPreference == QFont::PreferVerticalHinting) - || (QHighDpiScaling::isActive() && request.hintingPreference == QFont::PreferDefaultHinting) - || isColorFont; - if (useDirectWrite) { + const QFont::HintingPreference hintingPreference = + static_cast(request.hintingPreference); + const bool useDw = useDirectWrite(hintingPreference, isColorFont); + qCDebug(lcQpaFonts) << __FUNCTION__ << request.family << request.pointSize + << "pt" << "hintingPreference=" << hintingPreference << "color=" << isColorFont + << dpi << "dpi" << "useDirectWrite=" << useDw; + if (useDw) { QWindowsFontEngineDirectWrite *fedw = new QWindowsFontEngineDirectWrite(directWriteFontFace, request.pixelSize, data); diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index f033e4235c..b6d2c16f89 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -199,6 +199,10 @@ static inline unsigned parseOptions(const QStringList ¶mList, } } else if (param == QLatin1String("gl=gdi")) { options |= QWindowsIntegration::DisableArb; + } else if (param == QLatin1String("nodirectwrite")) { + options |= QWindowsIntegration::DontUseDirectWriteFonts; + } else if (param == QLatin1String("nocolorfonts")) { + options |= QWindowsIntegration::DontUseColorFonts; } else if (param == QLatin1String("nomousefromtouch")) { options |= QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch; } else if (parseIntOption(param, QLatin1String("verbose"), 0, INT_MAX, &QWindowsContext::verbose) diff --git a/src/plugins/platforms/windows/qwindowsintegration.h b/src/plugins/platforms/windows/qwindowsintegration.h index 9658ef711d..0c03274799 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.h +++ b/src/plugins/platforms/windows/qwindowsintegration.h @@ -60,7 +60,9 @@ public: DisableArb = 0x4, NoNativeDialogs = 0x8, XpNativeDialogs = 0x10, - DontPassOsMouseEventsSynthesizedFromTouch = 0x20 // Do not pass OS-generated mouse events from touch. + DontPassOsMouseEventsSynthesizedFromTouch = 0x20, // Do not pass OS-generated mouse events from touch. + DontUseDirectWriteFonts = 0x40, + DontUseColorFonts = 0x80 }; explicit QWindowsIntegration(const QStringList ¶mList); -- cgit v1.2.3 From 121b7b7a3cb401cb1597b8d56b9372f09aae6b51 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 5 Aug 2016 15:55:30 +0200 Subject: Windows: Fix Adobe/Mozilla format color fonts after Windows update After the Anniversary update of Windows 10 (update 1607), color fonts using the Adobe/Mozilla format with embedded SVGs are detected as color fonts by DirectWrite, but they do not contain any colored layers. The result of this was that we would no longer draw these fonts using the pen color, but we would also not support the colored glyphs in the fonts. In order to still support using these fonts as regular monochromatic fonts, we check if there is actually a palette in the font file before registering it as a color font. [ChangeLog][QtGui][Windows] Fixed rendering Adobe/Mozilla format color fonts with other colors than black after Windows 10 Anniversary update. Task-number: QTBUG-55097 Change-Id: I8d74787e49530d1167b9f2533ffdf7ab814c3358 Reviewed-by: Friedemann Kleint Reviewed-by: Tim Jenssen --- src/plugins/platforms/windows/qwindowsfontdatabase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp index 08769a3b39..314da702eb 100644 --- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp +++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp @@ -1810,7 +1810,7 @@ QFontEngine *QWindowsFontDatabase::createEngine(const QFontDef &request, if (SUCCEEDED(directWriteFontFace->QueryInterface(__uuidof(IDWriteFontFace2), reinterpret_cast(&directWriteFontFace2)))) { if (directWriteFontFace2->IsColorFont()) - isColorFont = true; + isColorFont = directWriteFontFace2->GetPaletteEntryCount() > 0; } #endif const QFont::HintingPreference hintingPreference = -- cgit v1.2.3 From 9e8c1d83144bd17786c185107fcc2784e8a6247f Mon Sep 17 00:00:00 2001 From: Nico Vertriest Date: Fri, 1 Jul 2016 15:18:05 +0200 Subject: Doc: Link issue startpage statement qmake-manual.qdoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I8ba7df0bf54eea2a43827d538fe5259a6adf4404 Reviewed-by: Venugopal Shivashankar Reviewed-by: Topi Reiniö --- qmake/doc/src/qmake-manual.qdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qmake/doc/src/qmake-manual.qdoc b/qmake/doc/src/qmake-manual.qdoc index 8078c377b2..9f8c1b2930 100644 --- a/qmake/doc/src/qmake-manual.qdoc +++ b/qmake/doc/src/qmake-manual.qdoc @@ -28,7 +28,7 @@ /*! \page qmake-manual.html \title qmake Manual - \startpage {Qt Reference Documentation} + \startpage index.html \nextpage Overview \ingroup qttools -- cgit v1.2.3 From 4da9972e89ea793f327a5899ea1740290a8a6745 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 5 Aug 2016 13:22:06 +0200 Subject: Add -opengl es2 to the DRIVE CX configure example To make sure it does not end up picking the desktop OpenGL implementation from Mesa that may be present in the sysroot. Change-Id: I815eb7d2664f9e62d620acf8260cae40f83dfaf8 Reviewed-by: Andy Nichols --- mkspecs/devices/linux-drive-cx-g++/qmake.conf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mkspecs/devices/linux-drive-cx-g++/qmake.conf b/mkspecs/devices/linux-drive-cx-g++/qmake.conf index cb43c9e2f6..c8e85e449c 100644 --- a/mkspecs/devices/linux-drive-cx-g++/qmake.conf +++ b/mkspecs/devices/linux-drive-cx-g++/qmake.conf @@ -7,7 +7,8 @@ # -device-option VIBRANTE_SDK_TOPDIR=/opt/nvidia/vibrante-t186ref-linux # -device-option CROSS_COMPILE=/opt/nvidia/toolchains/tegra-4.9-nv/usr/bin/aarch64-gnu-linux/aarch64-gnu-linux- \ # -sysroot /opt/nvidia/vibrante-t186ref-linux/targetfs \ -# -no-gcc-sysroot +# -no-gcc-sysroot \ +# -opengl es2 include(../common/linux_device_pre.conf) -- cgit v1.2.3 From a8390bb19739c5890e8172cdfe05ece25b33f906 Mon Sep 17 00:00:00 2001 From: Rainer Keller Date: Mon, 8 Aug 2016 10:13:10 +0200 Subject: Doc: Fix saturation graphic for HSV color model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The text is correctly describing the gradient from gray to blue but the picture shows white to blue. Additionally including the SVG sources for creating the pictures. Change-Id: I608a239f4de9c2d3761196c44db024cc31ce441a Reviewed-by: Leena Miettinen Reviewed-by: Topi Reiniö --- src/gui/doc/images/qcolor-saturation.png | Bin 2150 -> 1116 bytes src/gui/doc/images/qcolor-saturation.svg | 78 +++++++++++++++++++++++++++++++ src/gui/doc/images/qcolor-value.png | Bin 1241 -> 909 bytes src/gui/doc/images/qcolor-value.svg | 78 +++++++++++++++++++++++++++++++ 4 files changed, 156 insertions(+) create mode 100644 src/gui/doc/images/qcolor-saturation.svg create mode 100644 src/gui/doc/images/qcolor-value.svg diff --git a/src/gui/doc/images/qcolor-saturation.png b/src/gui/doc/images/qcolor-saturation.png index f28776aff5..9c104f7389 100644 Binary files a/src/gui/doc/images/qcolor-saturation.png and b/src/gui/doc/images/qcolor-saturation.png differ diff --git a/src/gui/doc/images/qcolor-saturation.svg b/src/gui/doc/images/qcolor-saturation.svg new file mode 100644 index 0000000000..608c2555e8 --- /dev/null +++ b/src/gui/doc/images/qcolor-saturation.svg @@ -0,0 +1,78 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + 0 + 255 + + diff --git a/src/gui/doc/images/qcolor-value.png b/src/gui/doc/images/qcolor-value.png index 0e069123a9..add9b7f83d 100644 Binary files a/src/gui/doc/images/qcolor-value.png and b/src/gui/doc/images/qcolor-value.png differ diff --git a/src/gui/doc/images/qcolor-value.svg b/src/gui/doc/images/qcolor-value.svg new file mode 100644 index 0000000000..51c2de0338 --- /dev/null +++ b/src/gui/doc/images/qcolor-value.svg @@ -0,0 +1,78 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + 0 + 255 + + -- cgit v1.2.3 From fa95eb055401f5264cbc6aca761cb9b5feb4affc Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 8 Aug 2016 17:23:18 +0200 Subject: QHeaderView: Reset lastSectionLogicalIdx on clear() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise we can fail to stretch the last section when adding new sections. Task-number: QTBUG-52446 Change-Id: I7eb5267ac500bf4246e57c3e3a43268bb65ef1f7 Reviewed-by: Thorbjørn Lund Martsum --- src/widgets/itemviews/qheaderview.cpp | 1 + tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/widgets/itemviews/qheaderview.cpp b/src/widgets/itemviews/qheaderview.cpp index 7b393463a6..1a0b417034 100644 --- a/src/widgets/itemviews/qheaderview.cpp +++ b/src/widgets/itemviews/qheaderview.cpp @@ -3465,6 +3465,7 @@ void QHeaderViewPrivate::clear() sectionSelected.clear(); hiddenSectionSize.clear(); sectionItems.clear(); + lastSectionLogicalIdx = -1; invalidateCachedSizeHint(); } } diff --git a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp index 47ec93ce16..ea065a4db4 100644 --- a/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp +++ b/tests/auto/widgets/itemviews/qheaderview/tst_qheaderview.cpp @@ -3014,6 +3014,11 @@ void tst_QHeaderView::stretchAndRestoreLastSection() header.swapSections(1, 11); QCOMPARE(header.sectionSize(1), someOtherSectionSize); + // Clear and re-add. This triggers a different code path than seColumnCount(0) + m.clear(); + m.setColumnCount(3); + QVERIFY(header.sectionSize(2) >= biggerSizeThanAnySection); + // Test import/export of the original (not stretched) sectionSize. m.setColumnCount(0); m.setColumnCount(10); -- cgit v1.2.3