From 3ed2ec14870c4035cfd1bd986f6d8f4f55890270 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 24 Mar 2014 16:20:11 +0100 Subject: [PATCH 001/120] Fix some documentation errors. Correct links and fix typos, remove obsolete documentation, fix some snippets, mark some classes as internal. Change-Id: I9a3266605f060783413d32740057a57a820c8929 Reviewed-by: Laszlo Agocs --- src/corelib/kernel/qmimedata.cpp | 2 +- src/corelib/kernel/qobject.cpp | 6 ++-- src/corelib/tools/qmargins.cpp | 20 +++++++++++++ src/corelib/tools/qstring.cpp | 4 +-- src/corelib/xml/qxmlstream.cpp | 4 +-- src/dbus/qdbusreply.cpp | 7 ++++- src/gui/image/qimage.cpp | 2 +- src/gui/kernel/qdrag.cpp | 2 +- src/gui/kernel/qevent.cpp | 4 +-- src/gui/kernel/qopenglcontext.cpp | 4 +-- src/gui/kernel/qsessionmanager.cpp | 8 ++--- src/gui/kernel/qsurfaceformat.cpp | 2 +- src/gui/opengl/qopengltexture.cpp | 14 ++++----- src/opengl/qgl.cpp | 47 +----------------------------- src/opengl/qglfunctions.cpp | 4 +-- src/sql/kernel/qsqlquery.cpp | 2 +- 16 files changed, 55 insertions(+), 77 deletions(-) diff --git a/src/corelib/kernel/qmimedata.cpp b/src/corelib/kernel/qmimedata.cpp index 483692cdf8c..5d2adb0561e 100644 --- a/src/corelib/kernel/qmimedata.cpp +++ b/src/corelib/kernel/qmimedata.cpp @@ -299,7 +299,7 @@ QVariant QMimeDataPrivate::retrieveTypedData(const QString &format, QVariant::Ty QMacPasteboardMime maps MIME to Mac flavors. \sa QClipboard, QDragEnterEvent, QDragMoveEvent, QDropEvent, QDrag, - QWindowsMime, QMacPasteboardMime, {Drag and Drop} + QMacPasteboardMime, {Drag and Drop} */ /*! diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 262d259136e..01bedb4a3a9 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -551,7 +551,7 @@ void QMetaCallEvent::placeMetaCall(QObject *object) QObject::signalsBlocked() state is transferred to this object. The object's signals this signal blocker was blocking prior to - being moved to, if any, are unblocked \em except in the case where + being moved to, if any, are unblocked \e except in the case where both instances block the same object's signals and \c *this is unblocked while \a other is not, at the time of the move. */ @@ -2731,9 +2731,7 @@ QMetaObject::Connection QObject::connect(const QObject *sender, const char *sign Qt::ConnectionType type) but it uses QMetaMethod to specify signal and method. - \sa connect(const QObject *sender, const char *signal, - const QObject *receiver, const char *method, - Qt::ConnectionType type) + \sa connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type) */ QMetaObject::Connection QObject::connect(const QObject *sender, const QMetaMethod &signal, const QObject *receiver, const QMetaMethod &method, diff --git a/src/corelib/tools/qmargins.cpp b/src/corelib/tools/qmargins.cpp index 03993f05a98..6f2c6c2c7c9 100644 --- a/src/corelib/tools/qmargins.cpp +++ b/src/corelib/tools/qmargins.cpp @@ -333,6 +333,26 @@ QT_BEGIN_NAMESPACE \since 5.1 */ +/*! + \fn QMargins &QMargins::operator+=(int addend) + \overload + + Adds the \a addend to each component of this object + and returns a reference to it. + + \sa operator-=() +*/ + +/*! + \fn QMargins &QMargins::operator-=(int subtrahend) + \overload + + Subtracts the \a subtrahend from each component of this object + and returns a reference to it. + + \sa operator+=() +*/ + /*! \fn QMargins &QMargins::operator*=(int factor) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 7547ba8c19c..a8770e886b5 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -6168,7 +6168,7 @@ qulonglong QString::toIntegral_helper(const QChar *data, uint len, bool *ok, int \snippet qstring/main.cpp 73 - \sa number(), toULong(), toInt(), QLocale::toLong() + \sa number(), toULong(), toInt(), QLocale::toInt() */ long QString::toLong(bool *ok, int base) const @@ -6197,7 +6197,7 @@ long QString::toLong(bool *ok, int base) const \snippet qstring/main.cpp 78 - \sa number(), QLocale::toULong() + \sa number(), QLocale::toUInt() */ ulong QString::toULong(bool *ok, int base) const diff --git a/src/corelib/xml/qxmlstream.cpp b/src/corelib/xml/qxmlstream.cpp index 5461139582d..83d0c73ae11 100644 --- a/src/corelib/xml/qxmlstream.cpp +++ b/src/corelib/xml/qxmlstream.cpp @@ -349,11 +349,11 @@ QXmlStreamEntityResolver *QXmlStreamReader::entityResolver() const \l{QNetworkAccessManager} {network access manager}, you would issue a \l{QNetworkRequest} {network request} to the manager and receive a \l{QNetworkReply} {network reply} in return. Since a QNetworkReply - is a QIODevice, you connect its \l{QNetworkReply::readyRead()} + is a QIODevice, you connect its \l{QIODevice::readyRead()} {readyRead()} signal to a custom slot, e.g. \c{slotReadyRead()} in the code snippet shown in the discussion for QNetworkAccessManager. In this slot, you read all available data with - \l{QNetworkReply::readAll()} {readAll()} and pass it to the XML + \l{QIODevice::readAll()} {readAll()} and pass it to the XML stream reader using addData(). Then you call your custom parsing function that reads the XML events from the reader. diff --git a/src/dbus/qdbusreply.cpp b/src/dbus/qdbusreply.cpp index b1326c11f1d..551891fdf21 100644 --- a/src/dbus/qdbusreply.cpp +++ b/src/dbus/qdbusreply.cpp @@ -155,7 +155,7 @@ QT_BEGIN_NAMESPACE */ /*! - \fn QDBusReply::error() + \fn const QDBusError& QDBusReply::error() const Returns the error code that was returned from the remote function call. If the remote call did not return an error (i.e., if it succeeded), then the QDBusError object that is returned will @@ -164,6 +164,11 @@ QT_BEGIN_NAMESPACE \sa isValid() */ +/*! + \fn const QDBusError& QDBusReply::error() + \overload +*/ + /*! \fn QDBusReply::value() const Returns the remote function's calls return value. If the remote call returned with an error, diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 48c262ae7a6..3998bbf3ff3 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -611,7 +611,7 @@ bool QImageData::checkForAlphaPixels() const */ /*! - \fn QImage &operator=(QImage &&other) + \fn QImage &QImage::operator=(QImage &&other) Move-assigns \a other to this QImage instance. diff --git a/src/gui/kernel/qdrag.cpp b/src/gui/kernel/qdrag.cpp index 465c04cdc8e..d7fd4d5bc01 100644 --- a/src/gui/kernel/qdrag.cpp +++ b/src/gui/kernel/qdrag.cpp @@ -101,7 +101,7 @@ QT_BEGIN_NAMESPACE \l{QWidget::mouseMoveEvent()}{mouseMoveEvent()} to check whether a QDrag is required. - \sa {Drag and Drop}, QClipboard, QMimeData, QWindowsMime, QMacPasteboardMime, + \sa {Drag and Drop}, QClipboard, QMimeData, QMacPasteboardMime, {Draggable Icons Example}, {Draggable Text Example}, {Drop Site Example}, {Fridge Magnets Example} */ diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp index 92d9871dc54..bb7000a2664 100644 --- a/src/gui/kernel/qevent.cpp +++ b/src/gui/kernel/qevent.cpp @@ -628,7 +628,7 @@ QHoverEvent::~QHoverEvent() \a modifiers holds the keyboard modifier flags at the time of the event, and \a orient holds the wheel's orientation. - \sa pos(), pixelDelta(), angleDelta(), state() + \sa pos(), pixelDelta(), angleDelta() */ #ifndef QT_NO_WHEELEVENT QWheelEvent::QWheelEvent(const QPointF &pos, int delta, @@ -659,7 +659,7 @@ QWheelEvent::~QWheelEvent() \a orient holds the wheel's orientation. - \sa pos(), pixelDelta(), angleDelta(), state() + \sa pos(), pixelDelta(), angleDelta() */ QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos, int delta, Qt::MouseButtons buttons, Qt::KeyboardModifiers modifiers, diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp index 5087e33b475..e258218e85d 100644 --- a/src/gui/kernel/qopenglcontext.cpp +++ b/src/gui/kernel/qopenglcontext.cpp @@ -165,7 +165,7 @@ void QOpenGLVersionProfile::setVersion(int majorVersion, int minorVersion) /*! Returns the OpenGL profile. Only makes sense if profiles are supported by this version. - \sa setProfile(), supportsProfiles() + \sa setProfile() */ QSurfaceFormat::OpenGLContextProfile QOpenGLVersionProfile::profile() const { @@ -176,7 +176,7 @@ QSurfaceFormat::OpenGLContextProfile QOpenGLVersionProfile::profile() const Sets the OpenGL profile \a profile. Only makes sense if profiles are supported by this version. - \sa profile(), supportsProfiles() + \sa profile() */ void QOpenGLVersionProfile::setProfile(QSurfaceFormat::OpenGLContextProfile profile) { diff --git a/src/gui/kernel/qsessionmanager.cpp b/src/gui/kernel/qsessionmanager.cpp index b9ef35854ce..a428840ca89 100644 --- a/src/gui/kernel/qsessionmanager.cpp +++ b/src/gui/kernel/qsessionmanager.cpp @@ -201,7 +201,7 @@ QString QSessionManager::sessionKey() const Here's an example of how an application's QGuiApplication::commitDataRequest() might be implemented: - \snippet code/src_gui_kernel_qguiapplication.cpp 8 + \snippet code/src_gui_kernel_qguiapplication.cpp 1 If an error occurred within the application while saving its data, you may want to try allowsErrorInteraction() instead. @@ -293,7 +293,7 @@ QSessionManager::RestartHint QSessionManager::restartHint() const If the session manager is capable of restoring sessions it will execute \a command in order to restore the application. The command defaults to - \snippet code/src_gui_kernel_qguiapplication.cpp 9 + \snippet code/src_gui_kernel_qguiapplication.cpp 2 The \c -session option is mandatory; otherwise QGuiApplication cannot tell whether it has been restored or what the current session identifier @@ -321,7 +321,7 @@ void QSessionManager::setRestartCommand(const QStringList &command) To iterate over the list, you can use the \l foreach pseudo-keyword: - \snippet code/src_gui_kernel_qguiapplication.cpp 10 + \snippet code/src_gui_kernel_qguiapplication.cpp 3 \sa setRestartCommand(), restartHint() */ @@ -347,7 +347,7 @@ void QSessionManager::setDiscardCommand(const QStringList &command) To iterate over the list, you can use the \l foreach pseudo-keyword: - \snippet code/src_gui_kernel_qguiapplication.cpp 11 + \snippet code/src_gui_kernel_qguiapplication.cpp 4 \sa setDiscardCommand(), restartCommand(), setRestartCommand() */ diff --git a/src/gui/kernel/qsurfaceformat.cpp b/src/gui/kernel/qsurfaceformat.cpp index 23c0e597792..2b8e611dffd 100644 --- a/src/gui/kernel/qsurfaceformat.cpp +++ b/src/gui/kernel/qsurfaceformat.cpp @@ -387,7 +387,7 @@ void QSurfaceFormat::setOption(QSurfaceFormat::FormatOption option, bool on) Returns true if the format option \a option is set; otherwise returns false. - \sa options(), testOption() + \sa options() */ bool QSurfaceFormat::testOption(QSurfaceFormat::FormatOption option) const { diff --git a/src/gui/opengl/qopengltexture.cpp b/src/gui/opengl/qopengltexture.cpp index 983496230df..078274eabd3 100644 --- a/src/gui/opengl/qopengltexture.cpp +++ b/src/gui/opengl/qopengltexture.cpp @@ -2668,12 +2668,12 @@ void QOpenGLTexture::generateMipMaps() } /*! - Generates mipmaps for this texture object from mipmap level \baseLevel. If you are + Generates mipmaps for this texture object from mipmap level \a baseLevel. If you are using a texture target and filtering option that requires mipmaps and you have disabled automatic mipmap generation then you need to call this function or the overload to create the mipmap chain. - The generation of mipmaps to above \baseLevel is achieved by setting the mipmap + The generation of mipmaps to above \a baseLevel is achieved by setting the mipmap base level to \a baseLevel and then generating the mipmap chain. If \a resetBaseLevel is \c true, then the baseLevel of the texture will be reset to its previous value. @@ -3000,7 +3000,7 @@ void QOpenGLTexture::setBorderColor(QColor color) } /*! - Sets the color red to \a {r}, green to \a {g}, blue to \{b}, and \a {a} to the + Sets the color red to \a {r}, green to \a {g}, blue to \a {b}, and \a {a} to the alpha value. \overload */ @@ -3033,8 +3033,8 @@ void QOpenGLTexture::setBorderColor(float r, float g, float b, float a) } /*! - Sets the color red to \a {r}, green to \a {g}, blue to \a {b}, and \a the alpha - value to {a}. + Sets the color red to \a {r}, green to \a {g}, blue to \a {b}, and the alpha + value to \a {a}. \overload */ void QOpenGLTexture::setBorderColor(int r, int g, int b, int a) @@ -3068,8 +3068,8 @@ void QOpenGLTexture::setBorderColor(int r, int g, int b, int a) } /*! - Sets the color red to \a {r}, green to \a {g}, blue to \a {b}, and \a the alpha - value to {a}. + Sets the color red to \a {r}, green to \a {g}, blue to \a {b}, and the alpha + value to \a {a}. \overload */ void QOpenGLTexture::setBorderColor(uint r, uint g, uint b, uint a) diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index de1de476b88..e602a05af96 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -3227,43 +3227,6 @@ void QGLContext::moveToThread(QThread *thread) visual. On other platforms it may work differently. */ -/*! \fn int QGLContext::choosePixelFormat(void* dummyPfd, HDC pdc) - - \b{Win32 only:} This virtual function chooses a pixel format - that matches the OpenGL \l{setFormat()}{format}. - Reimplement this function in a subclass if you need a custom - context. - - \warning The \a dummyPfd pointer and \a pdc are used as a \c - PIXELFORMATDESCRIPTOR*. We use \c void to avoid using - Windows-specific types in our header files. - - \sa chooseContext() -*/ - -/*! \fn void *QGLContext::chooseVisual() - - \b{X11 only:} This virtual function tries to find a visual that - matches the format, reducing the demands if the original request - cannot be met. - - The algorithm for reducing the demands of the format is quite - simple-minded, so override this method in your subclass if your - application has spcific requirements on visual selection. - - \sa chooseContext() -*/ - -/*! \fn void *QGLContext::tryVisual(const QGLFormat& f, int bufDepth) - \internal - - \b{X11 only:} This virtual function chooses a visual that matches - the OpenGL \l{format()}{format}. Reimplement this function - in a subclass if you need a custom visual. - - \sa chooseContext() -*/ - /*! \fn void QGLContext::reset() @@ -3706,7 +3669,7 @@ QGLWidget::~QGLWidget() */ /*! - \fn QFunctionPointer QGLContext::getProcAddress() const + \fn QFunctionPointer QGLContext::getProcAddress(const QString &proc) const Returns a function pointer to the GL extension function passed in \a proc. 0 is returned if a pointer to the function could not be @@ -4045,14 +4008,6 @@ void QGLWidget::paintEvent(QPaintEvent *) */ -/*! - \fn void QGLWidget::setMouseTracking(bool enable) - - If \a enable is true then mouse tracking is enabled; otherwise it - is disabled. -*/ - - /*! Renders the current scene on a pixmap and returns the pixmap. diff --git a/src/opengl/qglfunctions.cpp b/src/opengl/qglfunctions.cpp index 450f17b171f..d6d77d05683 100644 --- a/src/opengl/qglfunctions.cpp +++ b/src/opengl/qglfunctions.cpp @@ -466,7 +466,7 @@ void QGLFunctions::initializeGLFunctions(const QGLContext *context) */ /*! - \fn void QGLFunctions::glBufferData(GLenum target, qgl_GLsizeiptr size, const void* data, GLenum usage) + \fn void QGLFunctions::glBufferData(GLenum target, qopengl_GLsizeiptr size, const void* data, GLenum usage) Convenience function that calls glBufferData(\a target, \a size, \a data, \a usage). @@ -475,7 +475,7 @@ void QGLFunctions::initializeGLFunctions(const QGLContext *context) */ /*! - \fn void QGLFunctions::glBufferSubData(GLenum target, qgl_GLintptr offset, qgl_GLsizeiptr size, const void* data) + \fn void QGLFunctions::glBufferSubData(GLenum target, qopengl_GLintptr offset, qopengl_GLsizeiptr size, const void* data) Convenience function that calls glBufferSubData(\a target, \a offset, \a size, \a data). diff --git a/src/sql/kernel/qsqlquery.cpp b/src/sql/kernel/qsqlquery.cpp index 0cfc37833d2..b08f6bc8ef1 100644 --- a/src/sql/kernel/qsqlquery.cpp +++ b/src/sql/kernel/qsqlquery.cpp @@ -311,7 +311,7 @@ QSqlQuery& QSqlQuery::operator=(const QSqlQuery& other) /*! Returns \c true if the query is not \l{isActive()}{active}, the query is not positioned on a valid record, - there is no such field, or the field is null; otherwise \c false. + there is no such \a field, or the \a field is null; otherwise \c false. Note that for some drivers, isNull() will not return accurate information until after an attempt is made to retrieve data. From 48679a3748108fc600853f5f7355cb8495c649d2 Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Sat, 22 Mar 2014 13:04:10 +0200 Subject: [PATCH 002/120] Fix tst_QTextScriptEngine failures on some platforms The text shaping process has been unified for all platforms. Task-number: QTBUG-23064 Task-number: QTBUG-24565 Task-number: QTBUG-26495 Change-Id: Ida4c4be85f1a72c04399d2e6760fa36b33a0464e Reviewed-by: Friedemann Kleint Reviewed-by: Lars Knoll --- .../tst_qtextscriptengine.cpp | 287 ++++++++++-------- 1 file changed, 166 insertions(+), 121 deletions(-) diff --git a/tests/auto/gui/text/qtextscriptengine/tst_qtextscriptengine.cpp b/tests/auto/gui/text/qtextscriptengine/tst_qtextscriptengine.cpp index 74802c32175..c4db6696950 100644 --- a/tests/auto/gui/text/qtextscriptengine/tst_qtextscriptengine.cpp +++ b/tests/auto/gui/text/qtextscriptengine/tst_qtextscriptengine.cpp @@ -86,12 +86,13 @@ private slots: void greek_data(); void greek(); - void controlInSyllable_qtbug14204(); - void combiningMarks_qtbug15675(); - void mirroredChars_data(); void mirroredChars(); + void controlInSyllable_qtbug14204(); + void combiningMarks_qtbug15675_data(); + void combiningMarks_qtbug15675(); + void thaiIsolatedSaraAm(); void thaiWithZWJ(); void thaiMultipleVowels(); @@ -1051,87 +1052,18 @@ void tst_QTextScriptEngine::greek() doShapingTests(); } -void tst_QTextScriptEngine::controlInSyllable_qtbug14204() -{ -#if 0 && defined(Q_OS_UNIX) - // ### the test is incorrect -> disable for now - QString s; - s.append(QChar(0x0915)); - s.append(QChar(0x094d)); - s.append(QChar(0x200d)); - s.append(QChar(0x0915)); - - QTextLayout layout(s); - QTextEngine *e = layout.engine(); - e->itemize(); - e->shape(0); - - QCOMPARE(e->layoutData->items[0].num_glyphs, ushort(2)); - QVERIFY(e->layoutData->glyphLayout.advances[1].toInt() != 0); -#endif -} - -void tst_QTextScriptEngine::combiningMarks_qtbug15675() -{ -#if defined(Q_OS_MAC) - QString s; - s.append(QChar(0x0061)); - s.append(QChar(0x0062)); - s.append(QChar(0x0300)); - s.append(QChar(0x0063)); - - QFont font("Monaco"); - QTextLayout layout(s, font); - QTextEngine *e = layout.engine(); - e->itemize(); - e->shape(0); - - QCOMPARE(e->layoutData->items[0].num_glyphs, ushort(4)); - QCOMPARE(e->layoutData->glyphLayout.advances[2].toInt(), 0); -#else - QFontDatabase db; - - if (!db.families().contains("DejaVu Sans Mono")) - QSKIP("Required font (DejaVu Sans Mono) doesn't exist, skip test."); - - QString s; - s.append(QChar(0x0062)); - s.append(QChar(0x0332)); - s.append(QChar(0x0063)); - - QTextLayout layout(s, QFont("DejaVu Sans Mono")); - QTextEngine *e = layout.engine(); - e->itemize(); - e->shape(0); - - QCOMPARE(e->layoutData->items[0].num_glyphs, ushort(3)); - QCOMPARE(e->layoutData->glyphLayout.advances[1].toInt(), 0); -#endif -} - void tst_QTextScriptEngine::mirroredChars_data() { - QTest::addColumn("hintingPreference"); + QTest::addColumn("s"); - QTest::newRow("Default hinting") << int(QFont::PreferDefaultHinting); - QTest::newRow("No hinting") << int(QFont::PreferNoHinting); - QTest::newRow("Vertical hinting") << int(QFont::PreferVerticalHinting); - QTest::newRow("Full hinting") << int(QFont::PreferFullHinting); + QTest::newRow("()") << QStringLiteral("()"); + QTest::newRow("[]") << QStringLiteral("[]"); + QTest::newRow("{}") << QStringLiteral("{}"); } void tst_QTextScriptEngine::mirroredChars() { -#if defined(Q_OS_MAC) - QSKIP("Not supported on Mac"); -#endif - QFETCH(int, hintingPreference); - - QFont font; - font.setHintingPreference(QFont::HintingPreference(hintingPreference)); - - QString s; - s.append(QLatin1Char('(')); - s.append(QLatin1Char(')')); + QFETCH(QString, s); glyph_t leftParenthesis; glyph_t rightParenthesis; @@ -1144,10 +1076,12 @@ void tst_QTextScriptEngine::mirroredChars() QTextEngine *e = layout.engine(); e->itemize(); + QCOMPARE(e->layoutData->items.size(), 1); + e->shape(0); QCOMPARE(e->layoutData->items[0].num_glyphs, ushort(2)); - const QGlyphLayout &glyphLayout = e->layoutData->glyphLayout; + const QGlyphLayout glyphLayout = e->shapedGlyphs(&e->layoutData->items[0]); leftParenthesis = glyphLayout.glyphs[0]; rightParenthesis = glyphLayout.glyphs[1]; } @@ -1158,61 +1092,170 @@ void tst_QTextScriptEngine::mirroredChars() QTextEngine *e = layout.engine(); e->itemize(); + QCOMPARE(e->layoutData->items.size(), 1); + e->shape(0); QCOMPARE(e->layoutData->items[0].num_glyphs, ushort(2)); - const QGlyphLayout &glyphLayout = e->layoutData->glyphLayout; + const QGlyphLayout glyphLayout = e->shapedGlyphs(&e->layoutData->items[0]); QCOMPARE(glyphLayout.glyphs[0], rightParenthesis); QCOMPARE(glyphLayout.glyphs[1], leftParenthesis); } } +void tst_QTextScriptEngine::controlInSyllable_qtbug14204() +{ + QFontDatabase db; + if (!db.families().contains(QStringLiteral("Aparajita"))) + QSKIP("couldn't find 'Aparajita' font"); + + QFont font(QStringLiteral("Aparajita")); + font.setStyleStrategy(QFont::NoFontMerging); + + QString s; + s.append(QChar(0x0915)); + s.append(QChar(0x094d)); + s.append(QChar(0x200d)); + s.append(QChar(0x0915)); + + QTextLayout layout(s, font); + QTextEngine *e = layout.engine(); + e->itemize(); + QCOMPARE(e->layoutData->items.size(), 1); + + QFontEngine *fe = e->fontEngine(e->layoutData->items[0]); + if (fe->type() == QFontEngine::Box) + QSKIP("OpenType support missing for script"); + QCOMPARE(fe->fontDef.family, font.family()); + + e->shape(0); + QCOMPARE(e->layoutData->items[0].num_glyphs, ushort(2)); + + const ushort *log_clusters = e->logClusters(&e->layoutData->items[0]); + QCOMPARE(log_clusters[0], ushort(0)); + QCOMPARE(log_clusters[1], ushort(0)); + QCOMPARE(log_clusters[2], ushort(0)); + QCOMPARE(log_clusters[3], ushort(0)); +} + +void tst_QTextScriptEngine::combiningMarks_qtbug15675_data() +{ + QTest::addColumn("font"); + QTest::addColumn("string"); + + bool hasTests = false; + + QStringList families; + families << QStringLiteral("Monaco"); + families << QStringLiteral("DejaVu Sans Mono"); + + foreach (const QString &family, families) { + QFont font(family); + font.setStyleStrategy(QFont::NoFontMerging); + if (QFontInfo(font).family() != family) + continue; + + hasTests = true; + + QString s(QStringLiteral("ab cd")); + for (ushort uc = 0x0300; uc < 0x0370; ++uc) { + s[2] = QChar(uc); + QByteArray testName = family.toLatin1() + ": abcd"; + QTest::newRow(testName.constData()) << font << s; + } + } + + if (!hasTests) + QSKIP("Couldn't find required fonts, skip test."); +} + +void tst_QTextScriptEngine::combiningMarks_qtbug15675() +{ + QFETCH(QFont, font); + QFETCH(QString, string); + + QTextLayout layout(string, font); + QTextEngine *e = layout.engine(); + e->itemize(); + QCOMPARE(e->layoutData->items.size(), 1); + + QFontEngine *fe = e->fontEngine(e->layoutData->items[0]); + if (fe->type() == QFontEngine::Box) + QSKIP("OpenType support missing for script"); + QCOMPARE(fe->fontDef.family, font.family()); + + e->shape(0); + const int diff = e->layoutData->items[0].num_glyphs - string.size(); + QVERIFY(diff >= -1 && diff <= 1); // could compose or decompose exactly one character + + const ushort *log_clusters = e->logClusters(&e->layoutData->items[0]); + QCOMPARE(log_clusters[0], ushort(0)); + QCOMPARE(log_clusters[1], ushort(1)); + QCOMPARE(log_clusters[2], ushort(1)); + QCOMPARE(log_clusters[3], ushort(3 + diff)); + QCOMPARE(log_clusters[4], ushort(4 + diff)); + + const QGlyphLayout glyphLayout = e->shapedGlyphs(&e->layoutData->items[0]); + for (int i = 0; i < glyphLayout.numGlyphs; ++i) { + if ((diff >= 0 && i == 2) || (diff > 0 && i == 2 + diff)) + QCOMPARE(glyphLayout.advances[i].toInt(), 0); + else + QVERIFY(glyphLayout.advances[i].toInt() != 0); + } +} + void tst_QTextScriptEngine::thaiIsolatedSaraAm() { - if (QFontDatabase().families(QFontDatabase::Any).contains("Waree")) { - QString s; - s.append(QChar(0x0e33)); + QFontDatabase db; + if (!db.families().contains("Waree")) + QSKIP("couldn't find 'Waree' font"); - QTextLayout layout(s, QFont("Waree")); - layout.setCacheEnabled(true); - layout.beginLayout(); - layout.createLine(); - layout.endLayout(); + QFont font(QStringLiteral("Waree")); + font.setStyleStrategy(QFont::NoFontMerging); - QTextEngine *e = layout.engine(); - e->itemize(); - e->shape(0); - QCOMPARE(e->layoutData->items[0].num_glyphs, ushort(3)); + QString s; + s.append(QChar(0x0e33)); - unsigned short *logClusters = e->logClusters(&e->layoutData->items[0]); - QCOMPARE(logClusters[0], ushort(0)); - } else - QSKIP("Cannot find Waree."); + QTextLayout layout(s, font); + QTextEngine *e = layout.engine(); + e->itemize(); + QCOMPARE(e->layoutData->items.size(), 1); + + QFontEngine *fe = e->fontEngine(e->layoutData->items[0]); + if (fe->type() == QFontEngine::Box) + QSKIP("OpenType support missing for script"); + QCOMPARE(fe->fontDef.family, font.family()); + + e->shape(0); + QVERIFY(e->layoutData->items[0].num_glyphs > 0); + + const ushort *log_clusters = e->logClusters(&e->layoutData->items[0]); + QCOMPARE(log_clusters[0], ushort(0)); } void tst_QTextScriptEngine::thaiWithZWJ() { -#ifdef Q_OS_WIN - QSKIP("This test currently fails on Windows - QTBUG-24565"); -#endif + QFontDatabase db; + if (!db.families().contains("Waree")) + QSKIP("couldn't find 'Waree' font"); + + QFont font(QStringLiteral("Waree")); + font.setStyleStrategy(QFont::NoFontMerging); + QString s(QString::fromUtf8("\xe0\xb8\xa3\xe2\x80\x8d\xe0\xb8\xa3\xe2\x80" "\x8c\x2e\xe0\xb8\xa3\x2e\xe2\x80\x9c\xe0\xb8" "\xa3\xe2\x80\xa6\xe0\xb8\xa3\xe2\x80\x9d\xe0" "\xb8\xa3\xa0\xe0\xb8\xa3\xe6\x9c\xac\xe0\xb8\xa3") + QChar(0x0363)/*superscript 'a', for testing Inherited class*/); - QTextLayout layout(s); - layout.setCacheEnabled(true); - layout.beginLayout(); - layout.createLine(); - layout.endLayout(); + QTextLayout layout(s, font); QTextEngine *e = layout.engine(); - e->width(0, s.length()); //force itemize and shape - - // A thai implementation could either remove the ZWJ and ZWNJ characters, or hide them. - // The current implementation hides them, so we test for that. - // But make sure that we don't hide anything else + e->itemize(); QCOMPARE(e->layoutData->items.size(), 11); + + for (int item = 0; item < e->layoutData->items.size(); ++item) + e->shape(item); + QCOMPARE(e->layoutData->items[0].num_glyphs, ushort(7)); // Thai: The ZWJ and ZWNJ characters are inherited, so should be part of the thai script QCOMPARE(e->layoutData->items[1].num_glyphs, ushort(1)); // Common: The smart quotes cannot be handled by thai, so should be a separate item QCOMPARE(e->layoutData->items[2].num_glyphs, ushort(1)); // Thai: Thai character @@ -1231,15 +1274,18 @@ void tst_QTextScriptEngine::thaiWithZWJ() QCOMPARE(logClusters[i], ushort(i)); for (int i = 0; i < 10; i++) QCOMPARE(logClusters[i+7], ushort(0)); -#ifdef Q_OS_MAC - QEXPECT_FAIL("", "QTBUG-23064", Abort); -#endif QCOMPARE(logClusters[17], ushort(1)); - // The only characters that we should be hiding are the ZWJ and ZWNJ characters in position 1 - // and 3. - for (int i = 0; i < 18; i++) - QCOMPARE((bool)e->layoutData->glyphLayout.attributes[i].dontPrint, (i == 1 || i == 3)); + // A thai implementation could either remove the ZWJ and ZWNJ characters, or hide them. + // The current implementation hides them, so we test for that. + // The only characters that we should be hiding are the ZWJ and ZWNJ characters in position 1 and 3. + const QGlyphLayout glyphLayout = e->layoutData->glyphLayout; + for (int i = 0; i < 18; i++) { + if (i == 1 || i == 3) + QCOMPARE(glyphLayout.advances[i].toInt(), 0); + else + QVERIFY(glyphLayout.advances[i].toInt() != 0); + } } void tst_QTextScriptEngine::thaiMultipleVowels() @@ -1253,14 +1299,13 @@ void tst_QTextScriptEngine::thaiMultipleVowels() for (int i = 0; i < 10; i++) s += s; //Repeat the string to make it more likely to crash if we have a buffer overflow - QTextLayout layout(s); - layout.setCacheEnabled(true); - layout.beginLayout(); - layout.createLine(); - layout.endLayout(); + QTextLayout layout(s); QTextEngine *e = layout.engine(); - e->width(0, s.length()); //force itemize and shape + e->itemize(); + + for (int item = 0; item < e->layoutData->items.size(); ++item) + e->shape(item); // If we haven't crashed at this point, then the test has passed. } From cd8e11ed416035763dc25a25a71291d10976943a Mon Sep 17 00:00:00 2001 From: Sergio Ahumada Date: Mon, 24 Mar 2014 12:45:48 +0100 Subject: [PATCH 003/120] Doc: Fix warning about nonexistent 'message' parameter Change-Id: I3461f2468ef90452ae7e3830625bf3ed57d22a41 Reviewed-by: Friedemann Kleint --- src/testlib/qtestcase.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp index 7b225ef5b48..3ab3fcc44c7 100644 --- a/src/testlib/qtestcase.cpp +++ b/src/testlib/qtestcase.cpp @@ -2591,10 +2591,10 @@ void QTest::ignoreMessage(QtMsgType type, const char *message) /*! \overload - Ignores messages created by qDebug() or qWarning(). If the \a message + Ignores messages created by qDebug() or qWarning(). If the message matching \a messagePattern with the corresponding \a type is outputted, it will be removed from the - test log. If the test finished and the \a message was not outputted, + test log. If the test finished and the message was not outputted, a test failure is appended to the test log. \b {Note:} Invoking this function will only ignore one message. From 225a5b4787b3a04fd32958dba3e479761efc0623 Mon Sep 17 00:00:00 2001 From: Giuseppe D'Angelo Date: Mon, 17 Mar 2014 14:06:43 +0100 Subject: [PATCH 004/120] Do not use -Bsymbolic* on anything but x86 and x86-64 We're getting problems with PMF comparisons failing on ARM and PPC, which in turn break the new PMF-based connect syntax. Dropping -Bsymbolic* seems to work around the issue (which has been reported upstream, and it's likely to be a linker issue, see the discussion in the bug report). Task-number: QTBUG-36129 Change-Id: I8675a57acf26fdb9fbbc4d03896d5f6a9a96d506 Reviewed-by: Thiago Macieira --- config.tests/unix/bsymbolic_functions.test | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config.tests/unix/bsymbolic_functions.test b/config.tests/unix/bsymbolic_functions.test index d495e56befc..4d66ee6de02 100755 --- a/config.tests/unix/bsymbolic_functions.test +++ b/config.tests/unix/bsymbolic_functions.test @@ -6,6 +6,10 @@ VERBOSE=$2 cat >>bsymbolic_functions.c << EOF +#if !(defined(__i386) || defined(__i386__) || defined(__x86_64) || defined(__x86_64__) || defined(__amd64)) +#error "Symbolic function binding on this architecture may be broken, disabling it (see QTBUG-36129)." +#endif + int main() { return 0; } EOF From dbb6b58abede12cf9f2fad3086dd59a9d46b7ee7 Mon Sep 17 00:00:00 2001 From: John Layt Date: Sun, 23 Mar 2014 17:07:26 +0100 Subject: [PATCH 005/120] QPrintDialog - Convert manual test to .ui file Convert the manual print dialogs test to use a ui file as subsequent changes will add a lot more widgets. Change-Id: I06ac54b67532f0eea1e91a2d9aca4f587d2fa332 Reviewed-by: Friedemann Kleint --- tests/manual/dialogs/dialogs.pro | 1 + tests/manual/dialogs/printdialogpanel.cpp | 151 +++++------- tests/manual/dialogs/printdialogpanel.h | 18 +- tests/manual/dialogs/printdialogpanel.ui | 270 ++++++++++++++++++++++ tests/manual/dialogs/utils.cpp | 21 ++ tests/manual/dialogs/utils.h | 4 + 6 files changed, 354 insertions(+), 111 deletions(-) create mode 100644 tests/manual/dialogs/printdialogpanel.ui diff --git a/tests/manual/dialogs/dialogs.pro b/tests/manual/dialogs/dialogs.pro index 71c41119fea..21ebf9b6225 100644 --- a/tests/manual/dialogs/dialogs.pro +++ b/tests/manual/dialogs/dialogs.pro @@ -8,3 +8,4 @@ SOURCES += main.cpp filedialogpanel.cpp colordialogpanel.cpp fontdialogpanel.cpp wizardpanel.cpp messageboxpanel.cpp printdialogpanel.cpp utils.cpp HEADERS += filedialogpanel.h colordialogpanel.h fontdialogpanel.h \ wizardpanel.h messageboxpanel.h printdialogpanel.h utils.h +FORMS += printdialogpanel.ui diff --git a/tests/manual/dialogs/printdialogpanel.cpp b/tests/manual/dialogs/printdialogpanel.cpp index 5c89055e22c..b012d34db0e 100644 --- a/tests/manual/dialogs/printdialogpanel.cpp +++ b/tests/manual/dialogs/printdialogpanel.cpp @@ -65,7 +65,7 @@ #include #include -const FlagData modeComboData[] = +const FlagData printerModeComboData[] = { {"ScreenResolution", QPrinter::ScreenResolution}, {"PrinterResolution", QPrinter::PrinterResolution}, @@ -260,91 +260,30 @@ public slots: void slotPaintRequested(QPrinter *p) { print(p); } }; -class PageSizeControl : public QWidget { -public: - explicit PageSizeControl(QWidget *parent = 0); - QSizeF pageSize() const { return QSizeF(m_width->value(), m_height->value()); } - void setPageSize(const QSizeF &s) { m_width->setValue(s.width()); m_height->setValue(s.height()); } - -private: - QDoubleSpinBox *m_width; - QDoubleSpinBox *m_height; -}; - -PageSizeControl::PageSizeControl(QWidget *parent) - : QWidget(parent) - , m_width(new QDoubleSpinBox(this)) - , m_height(new QDoubleSpinBox(this)) -{ - m_width->setRange(1, 1000); - m_width->setSingleStep(10); - m_height->setRange(1, 1000); - m_height->setSingleStep(10); - QHBoxLayout *hBoxLayout = new QHBoxLayout(this); - hBoxLayout->addWidget(m_width); - hBoxLayout->addWidget(new QLabel("x", this)); - hBoxLayout->addWidget(m_height); - hBoxLayout->addWidget(new QLabel("mm", this)); -} - PrintDialogPanel::PrintDialogPanel(QWidget *parent) : QWidget(parent) - , m_creationGroupBox(new QGroupBox(tr("Create"), this)) - , m_settingsGroupBox(new QGroupBox(tr("Settings"), this)) - , m_dialogsGroupBox(new QGroupBox(tr("Dialogs"), this)) - , m_pageSizeCombo(new QComboBox) { - // Create with resolution - QHBoxLayout *hBoxLayout = new QHBoxLayout(m_creationGroupBox); - m_modeCombo = createCombo(m_creationGroupBox, modeComboData, sizeof(modeComboData)/sizeof(FlagData)); - hBoxLayout->addWidget(m_modeCombo); - m_createButton = new QPushButton(tr("Create"), m_creationGroupBox); - connect(m_createButton, SIGNAL(clicked()), this, SLOT(createPrinter())); - hBoxLayout->addWidget(m_createButton); - m_deleteButton = new QPushButton(tr("Delete"), m_creationGroupBox); - connect(m_deleteButton, SIGNAL(clicked()), this, SLOT(deletePrinter())); - hBoxLayout->addWidget(m_deleteButton); - hBoxLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::Ignored)); + m_panel.setupUi(this); - QFormLayout *formLayout = new QFormLayout(m_settingsGroupBox); - m_pageSizeCombo = createCombo(m_settingsGroupBox, pageSizeComboData, sizeof(pageSizeComboData)/sizeof(FlagData)); - connect(m_pageSizeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(enableCustomSizeControl())); - formLayout->addRow(tr("Paper #:"), m_pageSizeCombo); - m_customPageSizeControl = new PageSizeControl; - formLayout->addRow(tr("Custom size:"), m_customPageSizeControl); - m_orientationCombo = createCombo(m_settingsGroupBox, orientationComboData, sizeof(orientationComboData)/sizeof(FlagData)); - formLayout->addRow("Orientation:", m_orientationCombo); - m_fullPageCheckBox = new QCheckBox(tr("Full page"), m_settingsGroupBox); - formLayout->addRow(m_fullPageCheckBox); + // Setup the Create box + populateCombo(m_panel.m_printerModeCombo, printerModeComboData, sizeof(printerModeComboData)/sizeof(FlagData)); + connect(m_panel.m_createButton, SIGNAL(clicked()), this, SLOT(createPrinter())); + connect(m_panel.m_deleteButton, SIGNAL(clicked()), this, SLOT(deletePrinter())); - QVBoxLayout *vBoxLayout = new QVBoxLayout(m_dialogsGroupBox); + // Setup the Settings box + populateCombo(m_panel.m_pageSizeCombo, pageSizeComboData, sizeof(pageSizeComboData)/sizeof(FlagData)); + connect(m_panel.m_pageSizeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(enableCustomSizeControl())); + populateCombo(m_panel.m_orientationCombo, orientationComboData, sizeof(orientationComboData)/sizeof(FlagData)); - m_printDialogOptionsControl = new OptionsControl(tr("Options"), printDialogOptions, sizeof(printDialogOptions) / sizeof(FlagData), m_dialogsGroupBox); - vBoxLayout->addWidget(m_printDialogOptionsControl); - m_printDialogRangeCombo = createCombo(m_dialogsGroupBox, printRangeOptions, sizeof(printRangeOptions) / sizeof(FlagData)); - vBoxLayout->addWidget(m_printDialogRangeCombo); - - { - QPrintDialog dialog; - m_printDialogOptionsControl->setValue(dialog.options()); - m_printDialogRangeCombo->setCurrentIndex(dialog.printRange()); - } - - QPushButton *button = new QPushButton(tr("Print..."), m_dialogsGroupBox); - connect(button, SIGNAL(clicked()), this, SLOT(showPrintDialog())); - vBoxLayout->addWidget(button); - button = new QPushButton(tr("Preview..."), m_dialogsGroupBox); - connect(button, SIGNAL(clicked()), this, SLOT(showPreviewDialog())); - vBoxLayout->addWidget(button); - button = new QPushButton(tr("Page Setup..."), m_dialogsGroupBox); - connect(button, SIGNAL(clicked()), this, SLOT(showPageSetupDialog())); - vBoxLayout->addWidget(button); - - QGridLayout *gridLayout = new QGridLayout(this); - gridLayout->addWidget(m_creationGroupBox, 0, 0); - gridLayout->addWidget(m_settingsGroupBox, 1, 0); - gridLayout->addWidget(m_dialogsGroupBox, 0, 1, 2, 1); - gridLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Ignored, QSizePolicy::MinimumExpanding), 2, 0, 1, 2); + // Setup the Dialogs box + m_panel.m_dialogOptionsGroupBox->populateOptions(printDialogOptions, sizeof(printDialogOptions) / sizeof(FlagData)); + populateCombo(m_panel.m_printDialogRangeCombo, printRangeOptions, sizeof(printRangeOptions) / sizeof(FlagData)); + QPrintDialog dialog; + m_panel.m_dialogOptionsGroupBox->setValue(dialog.options()); + m_panel.m_printDialogRangeCombo->setCurrentIndex(dialog.printRange()); + connect(m_panel.m_printButton, SIGNAL(clicked()), this, SLOT(showPrintDialog())); + connect(m_panel.m_printPreviewButton, SIGNAL(clicked()), this, SLOT(showPreviewDialog())); + connect(m_panel.m_pageSetupButton, SIGNAL(clicked()), this, SLOT(showPageSetupDialog())); enablePanels(); } @@ -356,16 +295,16 @@ PrintDialogPanel::~PrintDialogPanel() void PrintDialogPanel::enablePanels() { const bool exists = !m_printer.isNull(); - m_createButton->setEnabled(!exists); - m_modeCombo->setEnabled(!exists); - m_deleteButton->setEnabled(exists); - m_settingsGroupBox->setEnabled(exists); - m_dialogsGroupBox->setEnabled(exists); + m_panel.m_createButton->setEnabled(!exists); + m_panel.m_printerModeCombo->setEnabled(!exists); + m_panel.m_deleteButton->setEnabled(exists); + m_panel.m_settingsGroupBox->setEnabled(exists); + m_panel.m_dialogsGroupBox->setEnabled(exists); } void PrintDialogPanel::createPrinter() { - const QPrinter::PrinterMode mode = comboBoxValue(m_modeCombo); + const QPrinter::PrinterMode mode = comboBoxValue(m_panel.m_printerModeCombo); m_printer.reset(new QPrinter(mode)); // Can set only once. retrieveSettings(m_printer.data()); enablePanels(); @@ -378,36 +317,49 @@ void PrintDialogPanel::deletePrinter() enablePanels(); } +QSizeF PrintDialogPanel::pageSize() const +{ + return QSizeF(m_panel.m_pageWidth->value(), m_panel.m_pageHeight->value()); +} + +void PrintDialogPanel::setPageSize(const QSizeF &sizef) +{ + m_panel.m_pageWidth->setValue(sizef.width()); + m_panel.m_pageHeight->setValue(sizef.height()); +} + void PrintDialogPanel::applySettings(QPrinter *printer) const { - const QPrinter::PageSize pageSize = comboBoxValue(m_pageSizeCombo); - if (pageSize == QPrinter::Custom) - printer->setPaperSize(m_customPageSizeControl->pageSize(), QPrinter::Millimeter); + const QPrinter::PageSize pageSizeId = comboBoxValue(m_panel.m_pageSizeCombo); + if (pageSizeId == QPrinter::Custom) + printer->setPaperSize(pageSize(), QPrinter::Millimeter); else - printer->setPageSize(pageSize); - printer->setOrientation(comboBoxValue(m_orientationCombo)); - printer->setFullPage(m_fullPageCheckBox->isChecked()); + printer->setPageSize(pageSizeId); + printer->setOrientation(comboBoxValue(m_panel.m_orientationCombo)); + printer->setFullPage(m_panel.m_fullPageCheckBox->isChecked()); } void PrintDialogPanel::retrieveSettings(const QPrinter *printer) { - setComboBoxValue(m_pageSizeCombo, printer->pageSize()); - setComboBoxValue(m_orientationCombo, printer->orientation()); - m_fullPageCheckBox->setChecked(printer->fullPage()); - m_customPageSizeControl->setPageSize(m_printer->paperSize(QPrinter::Millimeter)); + setComboBoxValue(m_panel.m_pageSizeCombo, printer->pageSize()); + setComboBoxValue(m_panel.m_orientationCombo, printer->orientation()); + m_panel.m_fullPageCheckBox->setChecked(printer->fullPage()); + setPageSize(m_printer->paperSize(QPrinter::Millimeter)); } void PrintDialogPanel::enableCustomSizeControl() { - m_customPageSizeControl->setEnabled(m_pageSizeCombo->currentIndex() == QPrinter::Custom); + bool custom = (m_panel.m_pageSizeCombo->currentIndex() == QPrinter::Custom); + m_panel.m_pageWidth->setEnabled(custom); + m_panel.m_pageHeight->setEnabled(custom); } void PrintDialogPanel::showPrintDialog() { applySettings(m_printer.data()); QPrintDialog dialog(m_printer.data(), this); - dialog.setOptions(m_printDialogOptionsControl->value()); - dialog.setPrintRange(comboBoxValue(m_printDialogRangeCombo)); + dialog.setOptions(m_panel.m_dialogOptionsGroupBox->value()); + dialog.setPrintRange(comboBoxValue(m_panel.m_printDialogRangeCombo)); if (dialog.exec() == QDialog::Accepted) { retrieveSettings(m_printer.data()); print(m_printer.data()); @@ -431,6 +383,7 @@ void PrintDialogPanel::showPageSetupDialog() retrieveSettings(m_printer.data()); } +#include "moc_printdialogpanel.cpp" #include "printdialogpanel.moc" #endif // !QT_NO_PRINTER diff --git a/tests/manual/dialogs/printdialogpanel.h b/tests/manual/dialogs/printdialogpanel.h index c8697827696..a7ae257cf84 100644 --- a/tests/manual/dialogs/printdialogpanel.h +++ b/tests/manual/dialogs/printdialogpanel.h @@ -44,6 +44,8 @@ #ifndef QT_NO_PRINTER +#include "ui_printdialogpanel.h" + #include QT_BEGIN_NAMESPACE @@ -73,22 +75,14 @@ private slots: void enableCustomSizeControl(); private: + QSizeF pageSize() const; + void setPageSize(const QSizeF &sizef); void applySettings(QPrinter *printer) const; void retrieveSettings(const QPrinter *printer); void enablePanels(); - QGroupBox *m_creationGroupBox; - QPushButton *m_createButton; - QPushButton *m_deleteButton; - QGroupBox *m_settingsGroupBox; - QCheckBox *m_fullPageCheckBox; - QGroupBox *m_dialogsGroupBox; - OptionsControl *m_printDialogOptionsControl; - QComboBox *m_printDialogRangeCombo; - QComboBox *m_modeCombo; - QComboBox *m_orientationCombo; - QComboBox *m_pageSizeCombo; - PageSizeControl *m_customPageSizeControl; + Ui::PrintDialogPanel m_panel; + QScopedPointer m_printer; }; diff --git a/tests/manual/dialogs/printdialogpanel.ui b/tests/manual/dialogs/printdialogpanel.ui new file mode 100644 index 00000000000..a185629fc1f --- /dev/null +++ b/tests/manual/dialogs/printdialogpanel.ui @@ -0,0 +1,270 @@ + + + PrintDialogPanel + + + + 0 + 0 + 507 + 291 + + + + + 0 + 0 + + + + Form + + + + + + + + + 0 + 0 + + + + Create + + + + + + Printer Mode: + + + + + + + + + + + + Create + + + + + + + Delete + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + 0 + 0 + + + + Settings + + + + + + Page Size: + + + + + + + + + + + + mm + + + 1000.000000000000000 + + + 10.000000000000000 + + + + + + + x + + + + + + + mm + + + 1000.000000000000000 + + + 10.000000000000000 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Orientation: + + + + + + + + + + Full Page Mode: + + + + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 22 + + + + + + + + + + + + + 0 + 0 + + + + Dialogs + + + + + + Options + + + + + + + + + + Print... + + + + + + + Preview... + + + + + + + Page Setup... + + + + + + + + + + Qt::Vertical + + + + 20 + 80 + + + + + + + + + + + OptionsControl + QGroupBox +
utils.h
+ 1 +
+
+ + +
diff --git a/tests/manual/dialogs/utils.cpp b/tests/manual/dialogs/utils.cpp index 7e0067c7f36..2dc01359b1e 100644 --- a/tests/manual/dialogs/utils.cpp +++ b/tests/manual/dialogs/utils.cpp @@ -52,11 +52,23 @@ QComboBox *createCombo(QWidget *parent, const FlagData *d, size_t size) return c; } +void populateCombo(QComboBox *combo, const FlagData *d, size_t size) +{ + for (size_t i = 0; i < size; ++i) + combo->addItem(QLatin1String(d[i].description), QVariant(d[i].value)); +} + void setComboBoxValue(QComboBox *c, int v) { c->setCurrentIndex(c->findData(QVariant(v))); } +OptionsControl::OptionsControl(QWidget *parent) + : QGroupBox(parent) +{ + setLayout(new QVBoxLayout(this)); +} + OptionsControl::OptionsControl(const QString &title, const FlagData *data, size_t count, QWidget *parent) : QGroupBox(title, parent) { @@ -68,6 +80,15 @@ OptionsControl::OptionsControl(const QString &title, const FlagData *data, size_ } } +void OptionsControl::populateOptions(const FlagData *data, size_t count) +{ + for (size_t i = 0; i < count; ++i) { + QCheckBox *box = new QCheckBox(QString::fromLatin1(data[i].description)); + m_checkBoxes.push_back(CheckBoxFlagPair(box, data[i].value)); + layout()->addWidget(box); + } +} + void OptionsControl::setValue(int flags) { foreach (const CheckBoxFlagPair &cf, m_checkBoxes) diff --git a/tests/manual/dialogs/utils.h b/tests/manual/dialogs/utils.h index 634795627f7..ac91754139d 100644 --- a/tests/manual/dialogs/utils.h +++ b/tests/manual/dialogs/utils.h @@ -59,6 +59,7 @@ struct FlagData // Helpers for creating combo boxes representing enumeration values from flag data. QComboBox *createCombo(QWidget *parent, const FlagData *d, size_t size); +void populateCombo(QComboBox *combo, const FlagData *d, size_t size); template Enum comboBoxValue(const QComboBox *c) @@ -71,8 +72,11 @@ void setComboBoxValue(QComboBox *c, int v); // A group box with check boxes for option flags. class OptionsControl : public QGroupBox { public: + OptionsControl(QWidget *parent); explicit OptionsControl(const QString &title, const FlagData *data, size_t count, QWidget *parent); + void populateOptions(const FlagData *data, size_t count); + void setValue(int flags); template Enum value() const { return static_cast(intValue()); } From d48db922d4310bd001faa708d9cd39e5c17863fa Mon Sep 17 00:00:00 2001 From: John Layt Date: Mon, 24 Mar 2014 11:51:05 +0100 Subject: [PATCH 006/120] QPrintDialog - Add more options to manual test Add all the available QPrinter options to the QPrintDialog manual test to allow for testing presets. Change-Id: Ia6394094fc9920da0d6c645793d51650404899d8 Reviewed-by: Friedemann Kleint --- tests/manual/dialogs/printdialogpanel.cpp | 385 +++++++++++++++++-- tests/manual/dialogs/printdialogpanel.h | 48 ++- tests/manual/dialogs/printdialogpanel.ui | 437 +++++++++++++++++++++- 3 files changed, 811 insertions(+), 59 deletions(-) diff --git a/tests/manual/dialogs/printdialogpanel.cpp b/tests/manual/dialogs/printdialogpanel.cpp index b012d34db0e..f7d027020c4 100644 --- a/tests/manual/dialogs/printdialogpanel.cpp +++ b/tests/manual/dialogs/printdialogpanel.cpp @@ -45,6 +45,7 @@ #include "utils.h" #include +#include #include #include #include @@ -64,6 +65,7 @@ #include #include #include +#include const FlagData printerModeComboData[] = { @@ -72,12 +74,7 @@ const FlagData printerModeComboData[] = {"HighResolution", QPrinter::HighResolution} }; -const FlagData orientationComboData[] = -{ - {"Portrait", QPrinter::Portrait}, - {"Landscape", QPrinter::Landscape}, -}; - +#if QT_VERSION < 0x050300 const FlagData pageSizeComboData[] = { {"A4", QPrinter::A4}, @@ -112,6 +109,76 @@ const FlagData pageSizeComboData[] = {"Tabloid", QPrinter::Tabloid}, {"Custom", QPrinter::Custom} }; +#endif + +const FlagData printRangeComboData[] = +{ + {"AllPages", QPrinter::AllPages}, + {"Selection", QPrinter::Selection}, + {"PageRange", QPrinter::PageRange}, + {"CurrentPage", QPrinter::CurrentPage} +}; + +const FlagData pageOrderComboData[] = +{ + {"FirstPageFirst", QPrinter::FirstPageFirst}, + {"LastPageFirst", QPrinter::LastPageFirst}, +}; + +const FlagData duplexModeComboData[] = +{ + {"DuplexNone", QPrinter::DuplexNone}, + {"DuplexAuto", QPrinter::DuplexAuto}, + {"DuplexLongSide", QPrinter::DuplexLongSide}, + {"DuplexShortSide", QPrinter::DuplexShortSide}, +}; + +const FlagData paperSourceComboData[] = +{ + {"OnlyOne", QPrinter::OnlyOne}, + {"Lower", QPrinter::Lower}, + {"Middle", QPrinter::Middle}, + {"Manual", QPrinter::Manual}, + {"Envelope", QPrinter::Envelope}, + {"EnvelopeManual", QPrinter::EnvelopeManual}, + {"Auto", QPrinter::Auto}, + {"Tractor", QPrinter::Tractor}, + {"SmallFormat", QPrinter::SmallFormat}, + {"LargeFormat", QPrinter::LargeFormat}, + {"LargeCapacity", QPrinter::LargeCapacity}, + {"Cassette", QPrinter::Cassette}, + {"FormSource", QPrinter::FormSource}, + {"DuplexLongSide", QPrinter::DuplexLongSide}, + {"DuplexShortSide", QPrinter::DuplexShortSide}, +}; + +const FlagData colorModeComboData[] = +{ + {"GrayScale", QPrinter::GrayScale}, + {"Color", QPrinter::Color}, +}; + +const FlagData unitsComboData[] = +{ + {"Millimeter", QPageLayout::Millimeter}, + {"Inch", QPageLayout::Inch}, + {"Point", QPageLayout::Point}, + {"Pica", QPageLayout::Pica}, + {"Didot", QPageLayout::Didot}, + {"Cicero", QPageLayout::Cicero}, +}; + +const FlagData orientationComboData[] = +{ + {"Portrait", QPageLayout::Portrait}, + {"Landscape", QPageLayout::Landscape}, +}; + +const FlagData layoutModeComboData[] = +{ + {"StandardMode", QPageLayout::StandardMode}, + {"FullPageMode", QPageLayout::FullPageMode}, +}; const FlagData printDialogOptions[] = { @@ -123,14 +190,6 @@ const FlagData printDialogOptions[] = {"PrintCurrentPage", QPrintDialog::PrintCurrentPage} }; -const FlagData printRangeOptions[] = -{ - {"AllPages", QPrintDialog::AllPages}, - {"Selection", QPrintDialog::Selection}, - {"PageRange", QPrintDialog::PageRange}, - {"CurrentPage", QPrintDialog::CurrentPage} -}; - QTextStream &operator<<(QTextStream &s, const QSizeF &size) { s << size.width() << 'x' << size.height(); @@ -261,8 +320,12 @@ public slots: }; PrintDialogPanel::PrintDialogPanel(QWidget *parent) - : QWidget(parent) + : QWidget(parent), m_blockSignals(true) { +#if QT_VERSION < 0x050300 + m_printerLayout.setOutputFormat(QPrinter::PdfFormat); +#endif + m_panel.setupUi(this); // Setup the Create box @@ -270,22 +333,55 @@ PrintDialogPanel::PrintDialogPanel(QWidget *parent) connect(m_panel.m_createButton, SIGNAL(clicked()), this, SLOT(createPrinter())); connect(m_panel.m_deleteButton, SIGNAL(clicked()), this, SLOT(deletePrinter())); - // Setup the Settings box + // Setup the Page Layout box + populateCombo(m_panel.m_unitsCombo, unitsComboData, sizeof(unitsComboData)/sizeof(FlagData)); + connect(m_panel.m_unitsCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(unitsChanged())); +#if QT_VERSION >= 0x050300 + for (int i = QPageSize::A4; i < QPageSize::LastPageSize; ++i) { + QPageSize::PageSizeId id = QPageSize::PageSizeId(i); + m_panel.m_pageSizeCombo->addItem(QPageSize::name(id), QVariant(id)); + } +#else populateCombo(m_panel.m_pageSizeCombo, pageSizeComboData, sizeof(pageSizeComboData)/sizeof(FlagData)); - connect(m_panel.m_pageSizeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(enableCustomSizeControl())); +#endif + connect(m_panel.m_pageSizeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(pageSizeChanged())); + connect(m_panel.m_pageWidth, SIGNAL(valueChanged(double)), this, SLOT(pageDimensionsChanged())); + connect(m_panel.m_pageHeight, SIGNAL(valueChanged(double)), this, SLOT(pageDimensionsChanged())); populateCombo(m_panel.m_orientationCombo, orientationComboData, sizeof(orientationComboData)/sizeof(FlagData)); + connect(m_panel.m_orientationCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(orientationChanged())); + connect(m_panel.m_leftMargin, SIGNAL(valueChanged(double)), this, SLOT(marginsChanged())); + connect(m_panel.m_topMargin, SIGNAL(valueChanged(double)), this, SLOT(marginsChanged())); + connect(m_panel.m_rightMargin, SIGNAL(valueChanged(double)), this, SLOT(marginsChanged())); + connect(m_panel.m_bottomMargin, SIGNAL(valueChanged(double)), this, SLOT(marginsChanged())); + populateCombo(m_panel.m_layoutModeCombo, layoutModeComboData, sizeof(layoutModeComboData)/sizeof(FlagData)); + connect(m_panel.m_layoutModeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(layoutModeChanged())); + + // Setup the Print Job box + m_panel.m_printerCombo->addItem(tr("Print to PDF"), QVariant("PdfFormat")); +#if QT_VERSION >= 0x050300 + foreach (const QString &name, QPrinterInfo::availablePrinterNames()) + m_panel.m_printerCombo->addItem(name, QVariant(name)); +#else + foreach (const QPrinterInfo &printer, QPrinterInfo::availablePrinters()) + m_panel.m_printerCombo->addItem(printer.printerName(), QVariant(printer.printerName())); +#endif + connect(m_panel.m_printerCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(printerChanged())); + populateCombo(m_panel.m_printRangeCombo, printRangeComboData, sizeof(printRangeComboData)/sizeof(FlagData)); + populateCombo(m_panel.m_pageOrderCombo, pageOrderComboData, sizeof(pageOrderComboData)/sizeof(FlagData)); + populateCombo(m_panel.m_duplexModeCombo, duplexModeComboData, sizeof(duplexModeComboData)/sizeof(FlagData)); + populateCombo(m_panel.m_paperSourceCombo, paperSourceComboData, sizeof(paperSourceComboData)/sizeof(FlagData)); + populateCombo(m_panel.m_colorModeCombo, colorModeComboData, sizeof(colorModeComboData)/sizeof(FlagData)); // Setup the Dialogs box m_panel.m_dialogOptionsGroupBox->populateOptions(printDialogOptions, sizeof(printDialogOptions) / sizeof(FlagData)); - populateCombo(m_panel.m_printDialogRangeCombo, printRangeOptions, sizeof(printRangeOptions) / sizeof(FlagData)); QPrintDialog dialog; m_panel.m_dialogOptionsGroupBox->setValue(dialog.options()); - m_panel.m_printDialogRangeCombo->setCurrentIndex(dialog.printRange()); connect(m_panel.m_printButton, SIGNAL(clicked()), this, SLOT(showPrintDialog())); connect(m_panel.m_printPreviewButton, SIGNAL(clicked()), this, SLOT(showPreviewDialog())); connect(m_panel.m_pageSetupButton, SIGNAL(clicked()), this, SLOT(showPageSetupDialog())); enablePanels(); + m_blockSignals = false; } PrintDialogPanel::~PrintDialogPanel() @@ -298,7 +394,8 @@ void PrintDialogPanel::enablePanels() m_panel.m_createButton->setEnabled(!exists); m_panel.m_printerModeCombo->setEnabled(!exists); m_panel.m_deleteButton->setEnabled(exists); - m_panel.m_settingsGroupBox->setEnabled(exists); + m_panel.m_pageLayoutGroupBox->setEnabled(exists); + m_panel.m_printJobGroupBox->setEnabled(exists); m_panel.m_dialogsGroupBox->setEnabled(exists); } @@ -308,7 +405,6 @@ void PrintDialogPanel::createPrinter() m_printer.reset(new QPrinter(mode)); // Can set only once. retrieveSettings(m_printer.data()); enablePanels(); - enableCustomSizeControl(); } void PrintDialogPanel::deletePrinter() @@ -317,41 +413,249 @@ void PrintDialogPanel::deletePrinter() enablePanels(); } -QSizeF PrintDialogPanel::pageSize() const +QSizeF PrintDialogPanel::customPageSize() const { return QSizeF(m_panel.m_pageWidth->value(), m_panel.m_pageHeight->value()); } -void PrintDialogPanel::setPageSize(const QSizeF &sizef) -{ - m_panel.m_pageWidth->setValue(sizef.width()); - m_panel.m_pageHeight->setValue(sizef.height()); -} - +// Apply the settings to the QPrinter void PrintDialogPanel::applySettings(QPrinter *printer) const { - const QPrinter::PageSize pageSizeId = comboBoxValue(m_panel.m_pageSizeCombo); - if (pageSizeId == QPrinter::Custom) - printer->setPaperSize(pageSize(), QPrinter::Millimeter); + QString printerName = m_panel.m_printerCombo->currentData().toString(); + if (printerName == QStringLiteral("PdfFormat")) + printer->setOutputFileName(m_panel.m_fileName->text()); else - printer->setPageSize(pageSizeId); - printer->setOrientation(comboBoxValue(m_panel.m_orientationCombo)); - printer->setFullPage(m_panel.m_fullPageCheckBox->isChecked()); + printer->setPrinterName(printerName); + printer->setPrintRange(comboBoxValue(m_panel.m_printRangeCombo)); + printer->setFromTo(m_panel.m_fromPage->value(), m_panel.m_toPage->value()); + printer->setPageOrder(comboBoxValue(m_panel.m_pageOrderCombo)); + printer->setCopyCount(m_panel.m_copyCount->value()); + printer->setCollateCopies(m_panel.m_collateCopies->isChecked()); + printer->setDuplex(comboBoxValue(m_panel.m_duplexModeCombo)); + printer->setPaperSource(comboBoxValue(m_panel.m_paperSourceCombo)); + printer->setColorMode(comboBoxValue(m_panel.m_colorModeCombo)); + printer->setResolution(m_panel.m_resolution->value()); + +#if QT_VERSION >= 0x050300 + printer->setPageLayout(m_pageLayout); +#else + if (m_printerLayout.pageSize() == QPrinter::Custom) + printer->setPaperSize(customPageSize(), m_units); + else + printer->setPageSize(m_printerLayout.pageSize()); + printer->setOrientation(m_printerLayout.orientation()); + printer->setFullPage(m_printerLayout.fullPage()); + double left, top, right, bottom; + m_printerLayout.getPageMargins(&left, &top, &right, &bottom, m_units); + printer->setPageMargins(left, top, right, bottom, m_units); +#endif } +// Retrieve the settings from the QPrinter void PrintDialogPanel::retrieveSettings(const QPrinter *printer) { - setComboBoxValue(m_panel.m_pageSizeCombo, printer->pageSize()); - setComboBoxValue(m_panel.m_orientationCombo, printer->orientation()); - m_panel.m_fullPageCheckBox->setChecked(printer->fullPage()); - setPageSize(m_printer->paperSize(QPrinter::Millimeter)); + if (printer->outputFormat() == QPrinter::NativeFormat) { + m_panel.m_printerCombo->setCurrentIndex(m_panel.m_printerCombo->findData(QVariant(printer->printerName()))); + m_panel.m_fileName->setEnabled(false); + } else { + m_panel.m_printerCombo->setCurrentIndex(m_panel.m_printerCombo->findData(QVariant(QStringLiteral("PdfFormat")))); + m_panel.m_fileName->setEnabled(true); + } + m_panel.m_fileName->setText(printer->outputFileName()); + setComboBoxValue(m_panel.m_printRangeCombo, printer->printRange()); + m_panel.m_fromPage->setValue(printer->fromPage()); + m_panel.m_toPage->setValue(printer->toPage()); + setComboBoxValue(m_panel.m_pageOrderCombo, printer->pageOrder()); + m_panel.m_copyCount->setValue(printer->copyCount()); + m_panel.m_collateCopies->setChecked(printer->collateCopies()); + setComboBoxValue(m_panel.m_duplexModeCombo, printer->duplex()); + setComboBoxValue(m_panel.m_paperSourceCombo, printer->paperSource()); + setComboBoxValue(m_panel.m_colorModeCombo, printer->colorMode()); + m_panel.m_resolution->setValue(printer->resolution()); + +#if QT_VERSION >= 0x050300 + m_pageLayout = printer->pageLayout(); +#else + if (printer->pageSize() == QPrinter::Custom) + m_printerLayout.setPaperSize(customPageSize(), m_units); + else + m_printerLayout.setPageSize(printer->pageSize()); + m_printerLayout.setOrientation(printer->orientation()); + m_printerLayout.setFullPage(printer->fullPage()); + double left, top, right, bottom; + printer->getPageMargins(&left, &top, &right, &bottom, m_units); + m_printerLayout.setPageMargins(left, top, right, bottom, m_units); +#endif + updatePageLayoutWidgets(); } -void PrintDialogPanel::enableCustomSizeControl() +void PrintDialogPanel::updatePageLayoutWidgets() { - bool custom = (m_panel.m_pageSizeCombo->currentIndex() == QPrinter::Custom); + m_blockSignals = true; +#if QT_VERSION >= 0x050300 + setComboBoxValue(m_panel.m_unitsCombo, m_pageLayout.units()); + setComboBoxValue(m_panel.m_pageSizeCombo, m_pageLayout.pageSize().id()); + QSizeF sizef = m_pageLayout.pageSize().size(QPageSize::Unit(m_pageLayout.units())); + bool custom = (m_pageLayout.pageSize().id() == QPageSize::Custom); + setComboBoxValue(m_panel.m_orientationCombo, m_pageLayout.orientation()); + m_panel.m_leftMargin->setValue(m_pageLayout.margins().left()); + m_panel.m_topMargin->setValue(m_pageLayout.margins().top()); + m_panel.m_rightMargin->setValue(m_pageLayout.margins().right()); + m_panel.m_bottomMargin->setValue(m_pageLayout.margins().bottom()); + setComboBoxValue(m_panel.m_layoutModeCombo, m_pageLayout.mode()); + QRectF rectf = m_pageLayout.paintRect(); +#else + setComboBoxValue(m_panel.m_unitsCombo, m_units); + setComboBoxValue(m_panel.m_pageSizeCombo, m_printerLayout.pageSize()); + QSizeF sizef = m_printerLayout.paperSize(m_units); + bool custom = (m_printerLayout.pageSize() == QPrinter::Custom); + setComboBoxValue(m_panel.m_orientationCombo, m_printerLayout.orientation()); + double left, top, right, bottom; + m_printerLayout.getPageMargins(&left, &top, &right, &bottom, m_units); + m_panel.m_leftMargin->setValue(left); + m_panel.m_topMargin->setValue(top); + m_panel.m_rightMargin->setValue(right); + m_panel.m_bottomMargin->setValue(bottom); + if (m_printerLayout.fullPage()) + setComboBoxValue(m_panel.m_layoutModeCombo, QPageLayout::FullPageMode); + else + setComboBoxValue(m_panel.m_layoutModeCombo, QPageLayout::StandardMode); + QRectF rectf = m_printerLayout.pageRect(m_units); +#endif + m_panel.m_pageWidth->setValue(sizef.width()); + m_panel.m_pageHeight->setValue(sizef.height()); m_panel.m_pageWidth->setEnabled(custom); m_panel.m_pageHeight->setEnabled(custom); + m_panel.m_rectX->setValue(rectf.x()); + m_panel.m_rectY->setValue(rectf.y()); + m_panel.m_rectWidth->setValue(rectf.width()); + m_panel.m_rectHeight->setValue(rectf.height()); + QString suffix; + switch (comboBoxValue(m_panel.m_unitsCombo)) { + case QPageLayout::Millimeter: + suffix = tr(" mm"); + break; + case QPageLayout::Point: + suffix = tr(" pt"); + break; + case QPageLayout::Inch: + suffix = tr(" in"); + break; + case QPageLayout::Pica: + suffix = tr(" pc"); + break; + case QPageLayout::Didot: + suffix = tr(" DD"); + break; + case QPageLayout::Cicero: + suffix = tr(" CC"); + break; + } + m_panel.m_pageWidth->setSuffix(suffix); + m_panel.m_pageHeight->setSuffix(suffix); + m_panel.m_leftMargin->setSuffix(suffix); + m_panel.m_topMargin->setSuffix(suffix); + m_panel.m_rightMargin->setSuffix(suffix); + m_panel.m_bottomMargin->setSuffix(suffix); + m_panel.m_rectX->setSuffix(suffix); + m_panel.m_rectY->setSuffix(suffix); + m_panel.m_rectWidth->setSuffix(suffix); + m_panel.m_rectHeight->setSuffix(suffix); + m_blockSignals = false; +} + +void PrintDialogPanel::unitsChanged() +{ + if (m_blockSignals) + return; +#if QT_VERSION >= 0x050300 + m_pageLayout.setUnits(comboBoxValue(m_panel.m_unitsCombo)); +#else + m_units = comboBoxValue(m_panel.m_unitsCombo); +#endif + updatePageLayoutWidgets(); +} + +void PrintDialogPanel::pageSizeChanged() +{ + if (m_blockSignals) + return; +#if QT_VERSION >= 0x050300 + const QPageSize::PageSizeId pageSizeId = comboBoxValue(m_panel.m_pageSizeCombo); + QPageSize pageSize; + if (pageSizeId == QPageSize::Custom) + pageSize = QPageSize(QSizeF(200, 200), QPageSize::Unit(m_pageLayout.units())); + else + pageSize = QPageSize(pageSizeId); + m_pageLayout.setPageSize(pageSize); +#else + const QPrinter::PageSize pageSize = comboBoxValue(m_panel.m_pageSizeCombo); + if (pageSize == QPrinter::Custom) + m_printerLayout.setPaperSize(QSizeF(200, 200), m_units); + else + m_printerLayout.setPageSize(pageSize); +#endif + updatePageLayoutWidgets(); +} + +void PrintDialogPanel::pageDimensionsChanged() +{ + if (m_blockSignals) + return; +#if QT_VERSION >= 0x050300 + m_pageLayout.setPageSize(QPageSize(customPageSize(), QPageSize::Unit(m_pageLayout.units()))); +#else + m_printerLayout.setPaperSize(customPageSize(), m_units); +#endif + updatePageLayoutWidgets(); +} + +void PrintDialogPanel::orientationChanged() +{ + if (m_blockSignals) + return; +#if QT_VERSION >= 0x050300 + m_pageLayout.setOrientation(comboBoxValue(m_panel.m_orientationCombo)); +#else + m_printerLayout.setOrientation(comboBoxValue(m_panel.m_orientationCombo)); +#endif + updatePageLayoutWidgets(); +} + +void PrintDialogPanel::marginsChanged() +{ + if (m_blockSignals) + return; +#if QT_VERSION >= 0x050300 + m_pageLayout.setMargins(QMarginsF(m_panel.m_leftMargin->value(), m_panel.m_topMargin->value(), + m_panel.m_rightMargin->value(), m_panel.m_bottomMargin->value())); +#else + m_printerLayout.setPageMargins(m_panel.m_leftMargin->value(), m_panel.m_topMargin->value(), + m_panel.m_rightMargin->value(), m_panel.m_bottomMargin->value(), + m_units); +#endif + updatePageLayoutWidgets(); +} + +void PrintDialogPanel::layoutModeChanged() +{ + if (m_blockSignals) + return; +#if QT_VERSION >= 0x050300 + m_pageLayout.setMode(comboBoxValue(m_panel.m_layoutModeCombo)); +#else + bool fullPage = (comboBoxValue(m_panel.m_layoutModeCombo) == QPageLayout::FullPageMode); + m_printerLayout.setFullPage(fullPage); +#endif + updatePageLayoutWidgets(); +} + +void PrintDialogPanel::printerChanged() +{ + bool isPdf = (m_panel.m_printerCombo->currentData().toString() == QStringLiteral("PdfFormat")); + m_panel.m_fileName->setEnabled(isPdf); + if (isPdf && m_panel.m_fileName->text().isEmpty()) + m_panel.m_fileName->setText(QDir::homePath() + QDir::separator() + QStringLiteral("print.pdf")); } void PrintDialogPanel::showPrintDialog() @@ -359,7 +663,6 @@ void PrintDialogPanel::showPrintDialog() applySettings(m_printer.data()); QPrintDialog dialog(m_printer.data(), this); dialog.setOptions(m_panel.m_dialogOptionsGroupBox->value()); - dialog.setPrintRange(comboBoxValue(m_panel.m_printDialogRangeCombo)); if (dialog.exec() == QDialog::Accepted) { retrieveSettings(m_printer.data()); print(m_printer.data()); diff --git a/tests/manual/dialogs/printdialogpanel.h b/tests/manual/dialogs/printdialogpanel.h index a7ae257cf84..3932cd174f4 100644 --- a/tests/manual/dialogs/printdialogpanel.h +++ b/tests/manual/dialogs/printdialogpanel.h @@ -46,6 +46,10 @@ #include "ui_printdialogpanel.h" +#if QT_VERSION >= 0x050300 +#include +#endif +#include #include QT_BEGIN_NAMESPACE @@ -59,6 +63,31 @@ QT_END_NAMESPACE class PageSizeControl; class OptionsControl; +#if QT_VERSION < 0x050300 +// Copied from class QPageLayout introduced in Qt 5.3 +namespace QPageLayout +{ + enum Unit { + Millimeter, + Point, + Inch, + Pica, + Didot, + Cicero + }; + + enum Orientation { + Portrait, + Landscape + }; + + enum Mode { + StandardMode, // Paint Rect includes margins + FullPageMode // Paint Rect excludes margins + }; +} +#endif + class PrintDialogPanel : public QWidget { Q_OBJECT @@ -72,17 +101,30 @@ private slots: void showPrintDialog(); void showPreviewDialog(); void showPageSetupDialog(); - void enableCustomSizeControl(); + void unitsChanged(); + void pageSizeChanged(); + void pageDimensionsChanged(); + void orientationChanged(); + void marginsChanged(); + void layoutModeChanged(); + void printerChanged(); private: - QSizeF pageSize() const; - void setPageSize(const QSizeF &sizef); + QSizeF customPageSize() const; void applySettings(QPrinter *printer) const; void retrieveSettings(const QPrinter *printer); + void updatePageLayoutWidgets(); void enablePanels(); + bool m_blockSignals; Ui::PrintDialogPanel m_panel; +#if QT_VERSION >= 0x050300 + QPageLayout m_pageLayout; +#else + QPrinter m_printerLayout; + QPrinter::Unit m_units; +#endif QScopedPointer m_printer; }; diff --git a/tests/manual/dialogs/printdialogpanel.ui b/tests/manual/dialogs/printdialogpanel.ui index a185629fc1f..733d52ad9e9 100644 --- a/tests/manual/dialogs/printdialogpanel.ui +++ b/tests/manual/dialogs/printdialogpanel.ui @@ -6,8 +6,8 @@ 0 0 - 507 - 291 + 650 + 707 @@ -79,7 +79,7 @@ - + 0 @@ -87,20 +87,30 @@ - Settings + Page Layout + + + Units: + + + + + + + Page Size: - + - + @@ -150,30 +160,430 @@ - + Orientation: - + - + + + + Margins: + + + + + + + + + 1000.000000000000000 + + + + + + + l + + + + + + + 1000.000000000000000 + + + + + + + t + + + + + + + 1000.000000000000000 + + + + + + + r + + + + + + + 1000.000000000000000 + + + + + + + b + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + - Full Page Mode: + Layout Mode: + + + + + + + + + + Paint Rect: + + + + + + + + + false + + + QAbstractSpinBox::NoButtons + + + mm + + + 1000.000000000000000 + + + + + + + x + + + + + + + false + + + QAbstractSpinBox::NoButtons + + + 1000.000000000000000 + + + + + + + y + + + + + + + false + + + QAbstractSpinBox::NoButtons + + + 1000.000000000000000 + + + + + + + w + + + + + + + false + + + QAbstractSpinBox::NoButtons + + + 1000.000000000000000 + + + + + + + h + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + 0 + 0 + + + + Print Job + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + Printer: + + + + + + + + + + File Name: + + + + + + + + + + Print Range: + + + + + + + + + + Page Range: - + + + + + 0 + + + 100 + + + 0 + + + + + + + to + + + + + + + 0 + + + 100 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + - + Copies: + + + + + + 100 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Collate Copies + + + + + + + + + Duplex Mode: + + + + + + + + + + Paper Source: + + + + + + + + + + Color Mode: + + + + + + + + + + Resolution: + + + + + + + + + 1 + + + 5000 + + + 100 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Page Order: + + + + + + @@ -213,9 +623,6 @@ - - - From 742ef8fa79e896e72213cea2411181148cd90ef1 Mon Sep 17 00:00:00 2001 From: Samuel Gaist Date: Sun, 23 Mar 2014 22:42:10 +0100 Subject: [PATCH 007/120] Implement DownloadLocation retrieving using SHGetKnownFolderPath MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch implements the TODO concerning the retrieval of DownloadLocation using SHGetKnownFolderPath [ChangeLog][QtCore][Windows] Now QStandardPaths::DownloadLocation returns the proper path for Windows Vista and up Task-number: QTBUG-35194 Change-Id: Ifc7686e23de76dbfd7826a75e4bf99aa5b9268b0 Reviewed-by: Jan Arve Sæther --- src/corelib/io/qstandardpaths_win.cpp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/corelib/io/qstandardpaths_win.cpp b/src/corelib/io/qstandardpaths_win.cpp index a0344a02063..62da5ea245e 100644 --- a/src/corelib/io/qstandardpaths_win.cpp +++ b/src/corelib/io/qstandardpaths_win.cpp @@ -49,6 +49,10 @@ #include #endif +#if !defined(Q_OS_WINCE) +const GUID qCLSID_FOLDERID_Downloads = { 0x374de290, 0x123f, 0x4565, { 0x91, 0x64, 0x39, 0xc4, 0x92, 0x5e, 0x46, 0x7b } }; +#endif + #include #include #if !defined(Q_OS_WINCE) @@ -68,6 +72,10 @@ QT_BEGIN_NAMESPACE +#if !defined(Q_OS_WINCE) +typedef HRESULT (WINAPI *GetKnownFolderPath)(REFKNOWNFOLDERID, DWORD, HANDLE, LPWSTR*); +#endif + static QString convertCharArray(const wchar_t *path) { return QDir::fromNativeSeparators(QString::fromWCharArray(path)); @@ -77,6 +85,10 @@ QString QStandardPaths::writableLocation(StandardLocation type) { QString result; +#if !defined(Q_OS_WINCE) + static GetKnownFolderPath SHGetKnownFolderPath = (GetKnownFolderPath)QSystemLibrary::resolve(QLatin1String("shell32"), "SHGetKnownFolderPath"); +#endif + wchar_t path[MAX_PATH]; switch (type) { @@ -107,7 +119,18 @@ QString QStandardPaths::writableLocation(StandardLocation type) result = convertCharArray(path); break; - case DownloadLocation: // TODO implement with SHGetKnownFolderPath(FOLDERID_Downloads) (starting from Vista) + case DownloadLocation: +#if !defined(Q_OS_WINCE) + if (SHGetKnownFolderPath) { + LPWSTR path; + if (SHGetKnownFolderPath(qCLSID_FOLDERID_Downloads, 0, 0, &path) == S_OK) { + result = convertCharArray(path); + CoTaskMemFree(path); + } + break; + } +#endif + // fall through case DocumentsLocation: if (SHGetSpecialFolderPath(0, path, CSIDL_PERSONAL, FALSE)) result = convertCharArray(path); From d1778a26a3abab9a6656a49c01dcb12f0e692e85 Mon Sep 17 00:00:00 2001 From: Konstantin Ritt Date: Fri, 21 Mar 2014 15:08:39 +0200 Subject: [PATCH 008/120] [HarfBuzz-NG] Optimize Unicode de-/composition callbacks Use QStringIterator instead of QString::toUcs4() and escape earlier. Change-Id: If80b886bece1a43af7078e8cdc9c31babf602731 Reviewed-by: Lars Knoll --- src/gui/text/qharfbuzzng.cpp | 59 ++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 33 deletions(-) diff --git a/src/gui/text/qharfbuzzng.cpp b/src/gui/text/qharfbuzzng.cpp index 1258ea9a784..b0bade83ee3 100644 --- a/src/gui/text/qharfbuzzng.cpp +++ b/src/gui/text/qharfbuzzng.cpp @@ -264,16 +264,12 @@ _hb_qt_unicode_compose(hb_unicode_funcs_t * /*ufuncs*/, // ### optimize QString s = QString::fromUcs4(&a, 1) + QString::fromUcs4(&b, 1); QString normalized = s.normalized(QString::NormalizationForm_C); - if (normalized.isEmpty()) - return false; - QVector ucs4str = normalized.toUcs4(); - if (ucs4str.size() == 1) { - *ab = ucs4str.at(0); - return true; - } + QStringIterator it(normalized); + Q_ASSERT(it.hasNext()); // size>0 + *ab = it.next(); - return false; + return !it.hasNext(); // size==1 } static hb_bool_t @@ -287,29 +283,28 @@ _hb_qt_unicode_decompose(hb_unicode_funcs_t * /*ufuncs*/, return false; QString normalized = QChar::decomposition(ab); - Q_ASSERT(!normalized.isEmpty()); + if (normalized.isEmpty()) + return false; - const QVector ucs4str = normalized.toUcs4(); - Q_ASSERT(ucs4str.size() <= HB_UNICODE_MAX_DECOMPOSITION_LEN); + QStringIterator it(normalized); + Q_ASSERT(it.hasNext()); // size>0 + *a = it.next(); - if (ucs4str.size() == 1) { - *a = ucs4str.at(0); + if (!it.hasNext()) { // size==1 *b = 0; return *a != ab; } - if (ucs4str.size() == 2) { - *a = ucs4str.at(0); - *b = ucs4str.at(1); - + // size>1 + *b = it.next(); + if (!it.hasNext()) { // size==2 // Here's the ugly part: if ab decomposes to a single character and // that character decomposes again, we have to detect that and undo // the second part :-( - QString recomposed = normalized.normalized(QString::NormalizationForm_C); - if (recomposed.isEmpty() || recomposed == normalized) - return false; - - hb_codepoint_t c = recomposed.toUcs4().at(0); + const QString recomposed = normalized.normalized(QString::NormalizationForm_C); + QStringIterator jt(recomposed); + Q_ASSERT(jt.hasNext()); // size>0 + const hb_codepoint_t c = jt.next(); if (c != *a && c != ab) { *a = c; *b = 0; @@ -317,17 +312,18 @@ _hb_qt_unicode_decompose(hb_unicode_funcs_t * /*ufuncs*/, return true; } + // size>2 // If decomposed to more than two characters, take the last one, // and recompose the rest to get the first component - *b = ucs4str.last(); - normalized.chop(1); - QString recomposed = normalized.normalized(QString::NormalizationForm_C); - if (recomposed.isEmpty() || recomposed == normalized) - return false; - + do { + *b = it.next(); + } while (it.hasNext()); + normalized.chop(QChar::requiresSurrogates(*b) ? 2 : 1); + const QString recomposed = normalized.normalized(QString::NormalizationForm_C); + QStringIterator jt(recomposed); + Q_ASSERT(jt.hasNext()); // size>0 // We expect that recomposed has exactly one character now - *a = recomposed.toUcs4().at(0); - + *a = jt.next(); return true; } @@ -337,9 +333,6 @@ _hb_qt_unicode_decompose_compatibility(hb_unicode_funcs_t * /*ufuncs*/, hb_codepoint_t *decomposed, void * /*user_data*/) { - if (QChar::decompositionTag(u) == QChar::NoDecomposition) // !NFKD - return 0; - const QString normalized = QChar::decomposition(u); uint outlen = 0; From 6cf7c3212fd8ed55b2bf18d6b87d1ef2bd543431 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Fri, 21 Mar 2014 19:30:12 +0200 Subject: [PATCH 009/120] Set default activity launchMode to singleInstance This attriute is needed otherwise if the user puts the application in background and uses the appication icon to bring it back in front, andriod will create a new activity. Task-number: QTBUG-37186 Change-Id: Icdc87239c1a07a3e555296692a4866eb6351348e Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/android/java/AndroidManifest.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/android/java/AndroidManifest.xml b/src/android/java/AndroidManifest.xml index 3209ab58ace..1741101bc12 100644 --- a/src/android/java/AndroidManifest.xml +++ b/src/android/java/AndroidManifest.xml @@ -4,7 +4,8 @@ + android:screenOrientation="unspecified" + android:launchMode="singleInstance"> From 63de1350c2a926a9941ee1b72a73c84b08cb0fdb Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Mon, 24 Mar 2014 10:07:46 +0100 Subject: [PATCH 010/120] winphone: deploy default font files as DirectWrite is not supported For Visual Studio we can add the fonts we want to deploy to the project file by using the DEPLOYMENT variable. Change-Id: Ifc87a12a2bb4ec4ff1c0a8dc8f0b1fbf37e4e513 Reviewed-by: Andrew Knight --- mkspecs/features/winrt/font_deployment.prf | 60 ++++++++++++++++++++++ mkspecs/winphone-arm-msvc2012/qmake.conf | 1 + mkspecs/winphone-x86-msvc2012/qmake.conf | 1 + 3 files changed, 62 insertions(+) create mode 100644 mkspecs/features/winrt/font_deployment.prf diff --git a/mkspecs/features/winrt/font_deployment.prf b/mkspecs/features/winrt/font_deployment.prf new file mode 100644 index 00000000000..36db5b7cace --- /dev/null +++ b/mkspecs/features/winrt/font_deployment.prf @@ -0,0 +1,60 @@ +# Provide default fonts for windows phone +# The DEFAULTFONTS variable indicates, whether the default set of fonts is +# used for deployment. The check below won't work after the fonts are added +# so this helper variable is added and used for the user warning check later. +!defined(FONTS, var):winphone { + FONTS = \ + $$[QT_HOST_PREFIX/src]/lib/fonts/DejaVuSans.ttf \ + $$[QT_HOST_PREFIX/src]/lib/fonts/DejaVuSans-Bold.ttf \ + $$[QT_HOST_PREFIX/src]/lib/fonts/DejaVuSans-BoldOblique.ttf \ + $$[QT_HOST_PREFIX/src]/lib/fonts/DejaVuSansMono.ttf \ + $$[QT_HOST_PREFIX/src]/lib/fonts/DejaVuSansMono-Bold.ttf \ + $$[QT_HOST_PREFIX/src]/lib/fonts/DejaVuSansMono-BoldOblique.ttf \ + $$[QT_HOST_PREFIX/src]/lib/fonts/DejaVuSansMono-Oblique.ttf \ + $$[QT_HOST_PREFIX/src]/lib/fonts/DejaVuSans-Oblique.ttf \ + $$[QT_HOST_PREFIX/src]/lib/fonts/DejaVuSerif.ttf \ + $$[QT_HOST_PREFIX/src]/lib/fonts/DejaVuSerif-Bold.ttf \ + $$[QT_HOST_PREFIX/src]/lib/fonts/DejaVuSerif-BoldOblique.ttf \ + $$[QT_HOST_PREFIX/src]/lib/fonts/DejaVuSerif-Oblique.ttf + DEFAULTFONTS = +} + +if(build_pass:equals(TEMPLATE, "app"))| \ +if(!build_pass:equals(TEMPLATE, "vcapp")) { + defined(DEFAULTFONTS, var) { + message(Default fonts will automatically be deployed with your application. \ + To avoid automatic deployment unset the \"FONTS\" variable (\"FONTS =\") in your .pro file. \ + You can also customize which fonts are deployed by setting the \"FONTS\" variable.) + } + + contains(TEMPLATE, "vc.*") { + BUILD_DIR = $$OUT_PWD + } else { + load(resolve_target) + BUILD_DIR = $$dirname(QMAKE_RESOLVED_TARGET) + } + + for (FONT, FONTS) { + font_$${FONT}.input = $$FONT + font_$${FONT}.output = $$BUILD_DIR/fonts/$$basename(FONT) + font_$${FONT}.CONFIG = verbatim + QMAKE_SUBSTITUTES += font_$${FONT} + } + + !isEmpty(FONTS):equals(TEMPLATE, "app") { + fonts.files = $$BUILD_DIR/fonts/* + isEmpty($$target.path) { + fonts.path = $$OUT_PWD/fonts + } else { + fonts.path = $$target.path/fonts + } + + INSTALLS += fonts + } +} + +!isEmpty(FONTS):winphone:equals(TEMPLATE, "vcapp"):build_pass { + fonts.files = $$OUT_PWD/fonts/* + fonts.path = fonts + DEPLOYMENT += fonts +} diff --git a/mkspecs/winphone-arm-msvc2012/qmake.conf b/mkspecs/winphone-arm-msvc2012/qmake.conf index 72961c320dd..ce95fdf0b99 100644 --- a/mkspecs/winphone-arm-msvc2012/qmake.conf +++ b/mkspecs/winphone-arm-msvc2012/qmake.conf @@ -7,6 +7,7 @@ include(../common/winrt_winphone/qmake.conf) QMAKE_COMPILER_DEFINES += _MSC_VER=1700 QMAKE_PLATFORM = winphone $$QMAKE_PLATFORM +CONFIG += font_deployment DEFINES += WINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP ARM __ARM__ __arm__ QMAKE_LFLAGS += /MACHINE:ARM diff --git a/mkspecs/winphone-x86-msvc2012/qmake.conf b/mkspecs/winphone-x86-msvc2012/qmake.conf index f7838d187a3..ff3d714bc52 100644 --- a/mkspecs/winphone-x86-msvc2012/qmake.conf +++ b/mkspecs/winphone-x86-msvc2012/qmake.conf @@ -7,6 +7,7 @@ include(../common/winrt_winphone/qmake.conf) QMAKE_COMPILER_DEFINES += _MSC_VER=1700 QMAKE_PLATFORM = winphone $$QMAKE_PLATFORM +CONFIG += font_deployment DEFINES += WINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP X86 __X86__ __x86__ QMAKE_LFLAGS += /MACHINE:X86 From 305907ecfaa8452f9ffc46791088b60b3d620180 Mon Sep 17 00:00:00 2001 From: Oliver Wolff Date: Mon, 24 Mar 2014 10:16:28 +0100 Subject: [PATCH 011/120] WinPhone: Install DejaVu ttf fonts into Qt As these fonts are deployed as part of the package for WinPhone projects by default they have to be installed in order to be available in the packages. Change-Id: Iaaca7b7db0525f06d3e1716d5a337550ffb1dea9 Reviewed-by: Andrew Knight --- src/plugins/platforms/winrt/winrt.pro | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro index 306bbc8174c..60c87bb61a3 100644 --- a/src/plugins/platforms/winrt/winrt.pro +++ b/src/plugins/platforms/winrt/winrt.pro @@ -1,6 +1,15 @@ TARGET = qwinrt CONFIG -= precompile_header +# For Windows Phone 8 we have to deploy fonts together with the application as DirectWrite +# is not supported here. +# TODO: Add a condition/remove this block if Windows Phone 8.1 supports DirectWrite +winphone { + fonts.path = $$[QT_INSTALL_LIBS]/fonts + fonts.files = $$QT_SOURCE_TREE/lib/fonts/DejaVu*.ttf + INSTALLS += fonts +} + PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QWinRTIntegrationPlugin load(qt_plugin) From ce8271ce051677a90e975db3a3b82b1e9c7261eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Nowacki?= Date: Tue, 18 Mar 2014 10:05:57 +0100 Subject: [PATCH 012/120] Remove useless Q_NO_DECLARED_NOT_DEFINED flag The flag is used only in qstring.h and gives no real value. Task-number: QTBUG-37437 Change-Id: I7513b56af208a5edee8452b8bbcb9b128e25133d Reviewed-by: Friedemann Kleint Reviewed-by: Lars Knoll --- src/corelib/tools/qstring.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index cf0726d831c..2d9a42957ec 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -711,7 +711,7 @@ public: Q_DECL_CONSTEXPR inline QString(QStringDataPtr dd) : d(dd.ptr) {} private: -#if defined(QT_NO_CAST_FROM_ASCII) && !defined(Q_NO_DECLARED_NOT_DEFINED) +#if defined(QT_NO_CAST_FROM_ASCII) QString &operator+=(const char *s); QString &operator+=(const QByteArray &s); QString(const char *ch); From a6bf169479df40f489fed549c893958f2519010e Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Fri, 21 Mar 2014 14:31:23 +0100 Subject: [PATCH 013/120] OSX: make reported window state consistent with reality You can't always get what you want: if you exit from fullscreen mode via showNormal, it might actually be maximized; or if you exit via showMaximized, it might actually be normal, if that's the mode the NSWindow remembers. We can't set the state, we can only toggle it. But now at least it's predictable, so that if you call showNormal or showMaximized twice, you will definitely get back to that state. Task-number: QTBUG-35166 Change-Id: I7422960a64f624920566c25763f5c3b03a684fb5 Reviewed-by: Gabriel de Dietrich --- src/plugins/platforms/cocoa/qcocoawindow.h | 1 + src/plugins/platforms/cocoa/qcocoawindow.mm | 26 +++++++++++++++++---- src/plugins/platforms/cocoa/qnsview.mm | 8 +++++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 6e1f00eebec..34ec142d900 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -252,6 +252,7 @@ public: // for QNSView QList m_childWindows; Qt::WindowFlags m_windowFlags; + bool m_effectivelyMaximized; Qt::WindowState m_synchedWindowState; Qt::WindowModality m_windowModality; QPointer m_activePopupWindow; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index c7fba4eef00..f25aea67fab 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -352,6 +352,7 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) , m_contentViewIsToBeEmbedded(false) , m_parentCocoaWindow(0) , m_isNSWindowChild(false) + , m_effectivelyMaximized(false) , m_synchedWindowState(Qt::WindowActive) , m_windowModality(Qt::NonModal) , m_windowUnderMouse(false) @@ -1436,7 +1437,6 @@ void QCocoaWindow::syncWindowState(Qt::WindowState newState) { if (!m_nsWindow) return; - // if content view width or height is 0 then the window animations will crash so // do nothing except set the new state NSRect contentRect = [contentView() frame]; @@ -1446,9 +1446,7 @@ void QCocoaWindow::syncWindowState(Qt::WindowState newState) return; } - if ((m_synchedWindowState & Qt::WindowMaximized) != (newState & Qt::WindowMaximized)) { - [m_nsWindow performZoom : m_nsWindow]; // toggles - } + Qt::WindowState predictedState = newState; if ((m_synchedWindowState & Qt::WindowMinimized) != (newState & Qt::WindowMinimized)) { if (newState & Qt::WindowMinimized) { @@ -1458,12 +1456,26 @@ void QCocoaWindow::syncWindowState(Qt::WindowState newState) } } + if ((m_synchedWindowState & Qt::WindowMaximized) != (newState & Qt::WindowMaximized) || (m_effectivelyMaximized && newState == Qt::WindowNoState)) { + if ((m_synchedWindowState & Qt::WindowFullScreen) == (newState & Qt::WindowFullScreen)) { + [m_nsWindow performZoom : m_nsWindow]; // toggles + m_effectivelyMaximized = !m_effectivelyMaximized; + } else if (!(newState & Qt::WindowMaximized)) { + // it would be nice to change the target geometry that toggleFullScreen will animate toward + // but there is no known way, so the maximized state is not possible at this time + predictedState = static_cast(static_cast(newState) | Qt::WindowMaximized); + m_effectivelyMaximized = true; + } + } + if ((m_synchedWindowState & Qt::WindowFullScreen) != (newState & Qt::WindowFullScreen)) { bool fakeFullScreen = true; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { if (window()->flags() & Qt::WindowFullscreenButtonHint) { fakeFullScreen = false; + if (m_effectivelyMaximized && m_synchedWindowState == Qt::WindowFullScreen) + predictedState = Qt::WindowMaximized; [m_nsWindow toggleFullScreen : m_nsWindow]; } } @@ -1490,8 +1502,12 @@ void QCocoaWindow::syncWindowState(Qt::WindowState newState) } } +#ifdef QT_COCOA_ENABLE_WINDOW_DEBUG + qDebug() << "QCocoaWindow::syncWindowState" << newState << "actual" << predictedState << "was" << m_synchedWindowState << "effectively maximized" << m_effectivelyMaximized; +#endif + // New state is now the current synched state - m_synchedWindowState = newState; + m_synchedWindowState = predictedState; } bool QCocoaWindow::setWindowModified(bool modified) diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 47081ab8902..1197aa9148d 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -281,6 +281,12 @@ static QTouchDevice *touchDevice = 0; - (void)notifyWindowStateChanged:(Qt::WindowState)newState { + // If the window was maximized, then fullscreen, then tried to go directly to "normal" state, + // this notification will say that it is "normal", but it will still look maximized, and + // if you called performZoom it would actually take it back to "normal". + // So we should say that it is maximized because it actually is. + if (newState == Qt::WindowNoState && m_platformWindow->m_effectivelyMaximized) + newState = Qt::WindowMaximized; QWindowSystemInterface::handleWindowStateChanged(m_window, newState); // We want to read the window state back from the window, // but the event we just sent may be asynchronous. @@ -346,6 +352,8 @@ static QTouchDevice *touchDevice = 0; - (void)notifyWindowWillZoom:(BOOL)willZoom { Qt::WindowState newState = willZoom ? Qt::WindowMaximized : Qt::WindowNoState; + if (!willZoom) + m_platformWindow->m_effectivelyMaximized = false; [self notifyWindowStateChanged:newState]; } From f65a0b6e3f4bee40dcabcb65e5fdd7d7eb9dd87f Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 24 Mar 2014 15:08:57 +0100 Subject: [PATCH 014/120] Update evdevtouch readme MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed/updated some out of date information. Change-Id: Iec2105f15c83f04dafbed15a9600e3de0e03f0de Reviewed-by: Jørgen Lind Reviewed-by: Shawn Rutledge --- src/plugins/generic/evdevtouch/README | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/plugins/generic/evdevtouch/README b/src/plugins/generic/evdevtouch/README index 833b511fd87..e5c9aff0af4 100644 --- a/src/plugins/generic/evdevtouch/README +++ b/src/plugins/generic/evdevtouch/README @@ -1,20 +1,17 @@ Generic plug-in for evdev multiple touch (ABS_MT) events. Supports protocol type A & B. Type B is supported both directly and via libmtdev. -Single-touch devices reporting ABS_X and Y only are not supported -by this plugin. Use tslib or evdevmouse instead. - The protocol type will be detected automatically. libmtdev is automatically detected based on library availability. To disable it, pass -no-mtdev to configure. -Tested with the following kernel drivers: - bcm5974 (type A) - hid_magicmouse (type A with ABS_MT_TRACKING_ID) (type B over libmtdev) - wacom (type B) +Single-touch devices reporting ABS_X and Y are supported too. Keep in +mind however that the libudev-based device discovery may not be able +to recognize such devices. If mouse events are sufficient, it may be +better to use evdevmouse or tslib with such devices. -To use this "driver", pass -plugin EvdevTouch on the command line. +To use this plugin, pass -plugin EvdevTouch on the command line. If automatic detection does not work, use -plugin EvdevTouch:/dev/input/eventN to explicitly set the device file From 895fa0de79b40345d5abefe7514527dfd585cbe1 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Tue, 25 Mar 2014 12:46:15 +0100 Subject: [PATCH 015/120] Fix grammar in QFontInfo::styleName() doc. Change-Id: I673ecc8931f4824dc4fb923056354cfd2e119e40 Reviewed-by: Jerome Pasion --- src/gui/text/qfont.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index 2e21a81187c..a8b3aabf19e 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -2395,7 +2395,7 @@ QString QFontInfo::family() const \since 4.8 Returns the style name of the matched window system font on - system that supports it. + systems that support it. \sa QFont::styleName() */ From dd1220651c50b0bacceab618df8fdf3a7f26a0ab Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 24 Mar 2014 18:42:19 +0100 Subject: [PATCH 016/120] eglfs: Avoid double surfaceFormatFor() calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hooks' surfaceFormatFor() function is called twice on the format when creating platform contexts, once from the integration and once from the constructor. This is potentially dangerous. Do it only once. Change-Id: I58eadce01b8f2183abe116f88b1ee9f2b47c003d Reviewed-by: Jørgen Lind --- src/plugins/platforms/eglfs/qeglfscontext.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/eglfs/qeglfscontext.cpp b/src/plugins/platforms/eglfs/qeglfscontext.cpp index 9083abc5627..4d443b91e33 100644 --- a/src/plugins/platforms/eglfs/qeglfscontext.cpp +++ b/src/plugins/platforms/eglfs/qeglfscontext.cpp @@ -53,8 +53,8 @@ QT_BEGIN_NAMESPACE QEglFSContext::QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display) - : QEGLPlatformContext(QEglFSHooks::hooks()->surfaceFormatFor(format), share, display, - QEglFSIntegration::chooseConfig(display, QEglFSHooks::hooks()->surfaceFormatFor(format))) + : QEGLPlatformContext(format, share, display, + QEglFSIntegration::chooseConfig(display, format)) { } From ebcb5c176fa3552960f3b96c2fcbd7aaa2b29e50 Mon Sep 17 00:00:00 2001 From: Kalle Viironen Date: Wed, 26 Feb 2014 16:16:34 +0200 Subject: [PATCH 017/120] Externalize license key handling from configure Enterprise only license key handling removed from configure. This does not affect the functionality of the Open Source version nor the enterprise version. Change-Id: I01736eba3066c56b6e50e022fae8de6aa9bd884b Reviewed-by: Lars Knoll Reviewed-by: Oswald Buddenhagen --- configure | 312 ++----------------------------- tools/configure/configureapp.cpp | 38 ++-- tools/configure/configureapp.h | 1 - tools/configure/tools.cpp | 193 +++---------------- tools/configure/tools.h | 6 +- 5 files changed, 58 insertions(+), 492 deletions(-) diff --git a/configure b/configure index 96273193a6a..52588c39d25 100755 --- a/configure +++ b/configure @@ -2766,203 +2766,25 @@ if [ "$COMMERCIAL_USER" = "ask" ]; then done fi -CFG_RTOS_ENABLED=yes -EditionString=Commercial if [ -f "$relpath"/LICENSE.PREVIEW.COMMERCIAL ] && [ $COMMERCIAL_USER = "yes" ]; then # Commercial preview release Licensee="Preview" Edition="Preview" - LicenseType="Technology Preview" + EditionString="Technology Preview" elif [ $COMMERCIAL_USER = "yes" ]; then - # one of commercial editions - - # read in the license file - [ -z "$LICENSE_FILE" ] && LICENSE_FILE="$QT_LICENSE_FILE" - [ -z "$LICENSE_FILE" ] && LICENSE_FILE="$HOME/.qt-license" - if [ -f "$LICENSE_FILE" ]; then - tr -d '\r' <"$LICENSE_FILE" >"${LICENSE_FILE}.tmp" - diff "${LICENSE_FILE}.tmp" "${LICENSE_FILE}" >/dev/null 2>&1 || LICENSE_FILE="${LICENSE_FILE}.tmp" - . "$LICENSE_FILE" >/dev/null 2>&1 - if [ -z "$LicenseKeyExt" ]; then - echo - echo "You are using an old license file." - echo - echo "Please install the license file supplied by Digia," - echo "or install the Qt Open Source Edition if you intend to" - echo "develop free software." - exit 1 - fi - if [ -z "$Licensee" ]; then - echo - echo "Invalid license key. Please check the license key." + if test -x "$relpath/bin/licheck"; then + LicheckOutput=`$relpath/bin/licheck $relpath $outpath $PLATFORM $XPLATFORM` + if [ $? -ne 0 ]; then exit 1 + else + eval "$LicheckOutput" fi else - if [ -z "$LicenseKeyExt" ]; then - echo - echo $ECHO_N "Please enter your license key: $ECHO_C" - read LicenseKeyExt - Licensee="Unknown user" - fi - fi - - # Key verification - echo "$LicenseKeyExt" | grep ".....*-....*-....*-....*-.....*-.....*-...." >/dev/null 2>&1 \ - && LicenseValid="yes" \ - || LicenseValid="no" - if [ "$LicenseValid" != "yes" ]; then echo - echo "Invalid license key. Please check the license key." - exit 1 - fi - ProductCode=`echo $LicenseKeyExt | cut -f 1 -d - | cut -b 1` - PlatformCode=`echo $LicenseKeyExt | cut -f 2 -d -` - LicenseTypeCode=`echo $LicenseKeyExt | cut -f 3 -d -` - LicenseFeatureCode=`echo $LicenseKeyExt | cut -f 4 -d - | cut -b 1` - - # determine which edition we are licensed to use - case "$LicenseTypeCode" in - F4M) - LicenseType="Commercial" - case $ProductCode in - F) - Edition="Universal" - ;; - B) - Edition="FullFramework" - EditionString="Full Framework" - ;; - L) - Edition="GUIFramework" - EditionString="GUI Framework" - ;; - esac - ;; - Z4M|R4M|Q4M) - LicenseType="Evaluation" - QMakeVar add DEFINES QT_EVAL - case $ProductCode in - B) - Edition="Evaluation" - ;; - esac - ;; - esac - if [ -z "$LicenseType" -o -z "$Edition" ]; then - echo - echo "Invalid license key. Please check the license key." - exit 1 - fi - - # verify that we are licensed to use Qt on this platform - LICENSE_EXTENSION= - case "$PlatformCode" in - *L) - CFG_RTOS_ENABLED=yes - PlatformCode=`echo "$PlatformCode" | sed 'h;y/8NPQRTZ/UCWX9M7/;x;G;s/\(.\)....\(.\)./\1\2/'` - ;; - *) - CFG_RTOS_ENABLED=no - PlatformCode=`echo "$PlatformCode" | sed 's/.$//'` - ;; - esac - ### EMBEDDED_QPA logic missing ### - case "$PlatformCode,$XPLATFORM_MAC" in - X9,* | XC,* | XU,* | XW,* | XM,*) - # Qt All-OS - LICENSE_EXTENSION="-ALLOS" - ;; - 8M,* | KM,* | S9,* | SC,* | SM,* | SU,* | SW,* | X9,* | XC,* | XU,* | XW,*) - # Qt for Embedded Linux - LICENSE_EXTENSION="-EMBEDDED" - ;; - 6M,* | N7,* | N9,* | NX,*) - # Embedded no-deploy - LICENSE_EXTENSION="-EMBEDDED" - ;; - FM,* | LM,yes | ZM,no) - # Desktop - LICENSE_EXTENSION="-DESKTOP" - ;; - *) - Platform=Linux/X11 - [ "$XPLATFORM_MAC" = "yes" ] && Platform='Mac OS X' - echo - echo "You are not licensed for the $Platform platform." - echo - echo "Please use the contact form at http://qt.digia.com/contact-us" - echo "to upgrade your license to include the $Platform platform, or install" - echo "the Qt Open Source Edition if you intend to develop free software." - exit 1 - ;; - esac - - if test -r "$relpath/.LICENSE"; then - # Generic, non-final license - LICENSE_EXTENSION="" - line=`sed 'y/a-z/A-Z/;q' "$relpath"/.LICENSE` - case "$line" in - *BETA*) - Edition=Beta - ;; - *TECHNOLOGY?PREVIEW*) - Edition=Preview - ;; - *EVALUATION*) - Edition=Evaluation - ;; - *) - echo >&2 "Invalid license files; cannot continue" - exit 1 - ;; - esac - Licensee="$Edition" - EditionString="$Edition" - fi - - case "$LicenseFeatureCode" in - B|G|L|Y) - # US - case "$LicenseType" in - Commercial) - cp -f "$relpath/.LICENSE${LICENSE_EXTENSION}-US" "$outpath/LICENSE" - ;; - Evaluation) - cp -f "$relpath/.LICENSE-EVALUATION-US" "$outpath/LICENSE" - ;; - esac - ;; - 2|4|5|F) - # non-US - case "$LicenseType" in - Commercial) - cp -f "$relpath/.LICENSE${LICENSE_EXTENSION}" "$outpath/LICENSE" - ;; - Evaluation) - cp -f "$relpath/.LICENSE-EVALUATION" "$outpath/LICENSE" - ;; - esac - ;; - *) - echo - echo "Invalid license key. Please check the license key." - exit 1 - ;; - esac - case "$LicenseFeatureCode" in - 4|B|F|Y) - CFG_RTOS_ENABLED=yes - ;; - 2|5|G|L) - CFG_RTOS_ENABLED=no - ;; - esac - if [ '!' -f "$outpath/LICENSE" ]; then - echo "The LICENSE, LICENSE.GPL LICENSE.LGPL file shipped with" - echo "this software has disappeared." - echo - echo "Sorry, you are not licensed to use this software." - echo "Try re-installing." + echo "Error: This is the Open Source version of Qt." + echo "If you want to use Enterprise features of Qt," + echo "use the contact form at http://qt.digia.com/contact-us" + echo "to purchase a license." echo exit 1 fi @@ -2972,22 +2794,11 @@ elif [ $COMMERCIAL_USER = "no" ]; then Edition="OpenSource" EditionString="Open Source" fi -echo -echo "This is the Qt ${EditionString} Edition." -echo -if [ "$CFG_RTOS_ENABLED" = "no" ]; then - case `basename "$XPLATFORM"` in - qnx-* | vxworks-*) - echo "" - echo "You are not licensed for Qt for `basename $XPLATFORM`." - echo "" - echo "Please use the contact form at http://qt.digia.com/contact-us" - echo "to upgrade your license to include this platform, or install" - echo "the Qt Open Source Edition if you intend to develop free software." - exit 1 - ;; - esac +if [ "$Edition" = "OpenSource" ] || [ "$Edition" = "Preview" ]; then + echo + echo "This is the Qt ${EditionString} Edition." + echo fi if [ "$Edition" = "OpenSource" ]; then @@ -3003,7 +2814,7 @@ if [ "$Edition" = "OpenSource" ]; then fi echo if [ "$OPT_CONFIRM_LICENSE" = "yes" ]; then - echo "You have already accepted the terms of the $LicenseType license." + echo "You have already accepted the terms of the $EditionString license." acceptance=yes else if [ -f "$relpath/LICENSE.GPL" ]; then @@ -3034,7 +2845,7 @@ elif [ "$Edition" = "Preview" ]; then while true; do if [ "$OPT_CONFIRM_LICENSE" = "yes" ]; then - echo "You have already accepted the terms of the $LicenseType license." + echo "You have already accepted the terms of the $EditionString license." acceptance=yes else echo "You are licensed to use this software under the terms of" @@ -3058,77 +2869,6 @@ elif [ "$Edition" = "Preview" ]; then more "$relpath/LICENSE.PREVIEW.COMMERCIAL" fi done -elif [ "$Edition" != "OpenSource" ]; then - if [ -n "$ExpiryDate" ]; then - ExpiryDate=`echo $ExpiryDate | sed -e 's,-,,g' | tr -d '\n\r'` - [ -z "$ExpiryDate" ] && ExpiryDate="0" - Today=`date +%Y%m%d` - if [ "$Today" -gt "$ExpiryDate" ]; then - case "$LicenseType" in - Commercial|Academic|Educational) - echo - echo "WARNING WARNING WARNING WARNING" - echo - echo " Your support and upgrade period has expired." - echo - echo " You may continue to use your last licensed release" - echo " of Qt under the terms of your existing license" - echo " agreement. But you are not entitled to technical" - echo " support, nor are you entitled to use any more recent" - echo " Qt releases." - echo - echo " Please use the contact form at http://qt.digia.com/contact-us" - echo " to renew your support and upgrades for this license." - echo - echo "WARNING WARNING WARNING WARNING" - echo - sleep 3 - ;; - Evaluation|*) - echo - echo "NOTICE NOTICE NOTICE NOTICE" - echo - echo " Your Evaluation license has expired." - echo - echo " You are no longer licensed to use this software. Please" - echo " use the contact form at http://qt.digia.com/contact-us to" - echo " purchase license, or install the Qt Open Source Edition" - echo " if you intend to develop free software." - echo - echo "NOTICE NOTICE NOTICE NOTICE" - echo - exit 1 - ;; - esac - fi - fi - TheLicense=`head -n 1 "$outpath/LICENSE"` - while true; do - if [ "$OPT_CONFIRM_LICENSE" = "yes" ]; then - echo "You have already accepted the terms of the $TheLicense." - acceptance=yes - else - echo "You are licensed to use this software under the terms of" - echo "the $TheLicense." - echo - echo "Type '?' to view the $TheLicense." - echo "Type 'yes' to accept this license offer." - echo "Type 'no' to decline this license offer." - echo - echo $ECHO_N "Do you accept the terms of the $TheLicense? $ECHO_C" - read acceptance - fi - echo - if [ "$acceptance" = "yes" ]; then - break - elif [ "$acceptance" = "no" ]; then - echo "You are not licensed to use this software." - echo - exit 1 - else [ "$acceptance" = "?" ] - more "$outpath/LICENSE" - fi - done fi #------------------------------------------------------------------------------- @@ -3851,22 +3591,6 @@ else chmod -w "$outpath/src/corelib/global/qconfig.cpp" fi -# ----------------------------------------------------------------------------- -if [ "$LicenseType" = "Evaluation" ]; then - EVALKEY=qt_qevalkey=$LicenseKeyExt -elif echo "$DEFINES" | grep QT_EVAL >/dev/null 2>&1; then - EVALKEY=qt_qevalkey= -fi - -if [ -n "$EVALKEY" ]; then - rm -f "$outpath/src/corelib/global/qconfig_eval.cpp" - cat > "$outpath/src/corelib/global/qconfig_eval.cpp" <>"$outpath/src/corelib/global/qconfig.h.new" <>"$outpath/src/corelib/global/qconfig.h.new" [ '!' -z "$LicenseKeyExt" ] && echo "#define QT_PRODUCT_LICENSEKEY \"$LicenseKeyExt\"" >>"$outpath/src/corelib/global/qconfig.h.new" diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index fddf99d2da2..9cebe6682b4 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -3388,7 +3388,7 @@ void Configure::generateConfigfiles() << endl; } tmpStream << "/* License information */" << endl; - tmpStream << "#define QT_PRODUCT_LICENSEE \"" << licenseInfo[ "LICENSEE" ] << "\"" << endl; + tmpStream << "#define QT_PRODUCT_LICENSEE \"" << dictionary[ "LICENSEE" ] << "\"" << endl; tmpStream << "#define QT_PRODUCT_LICENSE \"" << dictionary[ "EDITION" ] << "\"" << endl; tmpStream << endl; if (dictionary["BUILDDEV"] == "yes") { @@ -3508,16 +3508,6 @@ void Configure::generateConfigfiles() dictionary[ "DONE" ] = "error"; } - if (dictionary["EDITION"] == "Evaluation" || qmakeDefines.contains("QT_EVAL")) { - FileWriter tmpStream(buildPath + "/src/corelib/global/qconfig_eval.cpp"); - - tmpStream << "/* Evaluation license key */" << endl - << "static const volatile char qt_eval_key_data [512 + 12] = \"qt_qevalkey=" << licenseInfo["LICENSEKEYEXT"] << "\";" << endl; - - if (!tmpStream.flush()) - dictionary[ "DONE" ] = "error"; - } - } void Configure::displayConfig() @@ -3542,10 +3532,10 @@ void Configure::displayConfig() sout << " PATH=\n " << env << endl; if (dictionary[QStringLiteral("EDITION")] != QStringLiteral("OpenSource")) { - QString l1 = licenseInfo[ "LICENSEE" ]; - QString l2 = licenseInfo[ "LICENSEID" ]; + QString l1 = dictionary[ "LICENSEE" ]; + QString l2 = dictionary[ "LICENSEID" ]; QString l3 = dictionary["EDITION"] + ' ' + "Edition"; - QString l4 = licenseInfo[ "EXPIRYDATE" ]; + QString l4 = dictionary[ "EXPIRYDATE" ]; sout << "Licensee...................." << (l1.isNull() ? "" : l1) << endl; sout << "License ID.................." << (l2.isNull() ? "" : l2) << endl; sout << "Product license............." << (l3.isNull() ? "" : l3) << endl; @@ -3877,7 +3867,7 @@ void Configure::generateQConfigCpp() { FileWriter tmpStream(buildPath + "/src/corelib/global/qconfig.cpp"); tmpStream << "/* Licensed */" << endl - << "static const char qt_configure_licensee_str [512 + 12] = \"qt_lcnsuser=" << licenseInfo["LICENSEE"] << "\";" << endl + << "static const char qt_configure_licensee_str [512 + 12] = \"qt_lcnsuser=" << dictionary["LICENSEE"] << "\";" << endl << "static const char qt_configure_licensed_products_str [512 + 12] = \"qt_lcnsprod=" << dictionary["EDITION"] << "\";" << endl << endl << "/* Build date */" << endl @@ -4302,7 +4292,7 @@ void Configure::readLicense() } if (hasOpenSource && openSource) { cout << endl << "This is the " << dictionary["PLATFORM NAME"] << " Open Source Edition." << endl; - licenseInfo["LICENSEE"] = "Open Source"; + dictionary["LICENSEE"] = "Open Source"; dictionary["EDITION"] = "OpenSource"; cout << endl; if (!showLicense(dictionary["LICENSE FILE"])) { @@ -4316,20 +4306,14 @@ void Configure::readLicense() } #ifdef COMMERCIAL_VERSION else { - Tools::checkLicense(dictionary, licenseInfo, firstLicensePath(), sourcePath); - if (dictionary["DONE"] != "error") { - // give the user some feedback, and prompt for license acceptance - cout << endl << "This is the " << dictionary["PLATFORM NAME"] << " " << dictionary["EDITION"] << " Edition."<< endl << endl; - if (!showLicense(dictionary["LICENSE FILE"])) { - cout << "Configuration aborted since license was not accepted"; - dictionary["DONE"] = "error"; - return; - } - } + Tools::checkLicense(dictionary, sourcePath, buildPath); } #else // !COMMERCIAL_VERSION else { - cout << endl << "Cannot build commercial edition from the open source version of the library." << endl; + cout << endl << "Error: This is the Open Source version of Qt." + << endl << "If you want to use Enterprise features of Qt," + << endl << "use the contact form at http://qt.digia.com/contact-us" + << endl << "to purchase a license." << endl << endl; dictionary["DONE"] = "error"; } #endif diff --git a/tools/configure/configureapp.h b/tools/configure/configureapp.h index 36668f18ba3..e8de10dcf74 100644 --- a/tools/configure/configureapp.h +++ b/tools/configure/configureapp.h @@ -147,7 +147,6 @@ private: QString sybase; QString sybaseLibs; - QMap licenseInfo; QString outputLine; QTextStream outStream; diff --git a/tools/configure/tools.cpp b/tools/configure/tools.cpp index 07c3c82a0b9..e2a6f3cc8a4 100644 --- a/tools/configure/tools.cpp +++ b/tools/configure/tools.cpp @@ -40,191 +40,56 @@ ****************************************************************************/ #include "tools.h" +#include "environment.h" #include #include #include +#include - -// std stuff ------------------------------------ #include -#include -#include -#define NUMBER_OF_PARTS 7 -std::ostream &operator<<(std::ostream &s, const QString &val); // defined in configureapp.cpp +std::ostream &operator<<(std::ostream &s, const QString &val); using namespace std; -void Tools::checkLicense(QMap &dictionary, QMap &licenseInfo, - const QString &path, const QString &sourcePath) +void Tools::checkLicense(QMap &dictionary, + const QString &sourcePath, const QString &buildPath) { - QString tpLicense = sourcePath + "/LICENSE.PREVIEW.OPENSOURCE"; + QString tpLicense = sourcePath + "/LICENSE.PREVIEW.COMMERCIAL"; if (QFile::exists(tpLicense)) { dictionary["EDITION"] = "Preview"; dictionary["LICENSE FILE"] = tpLicense; - return; // No license key checking in Tech Preview - } - tpLicense = sourcePath + "/LICENSE.PREVIEW.COMMERCIAL"; - if (QFile::exists(tpLicense)) { - dictionary["EDITION"] = "Preview"; - dictionary["LICENSE FILE"] = tpLicense; - return; // No license key checking in Tech Preview - } - - // Read in the license file - QFile licenseFile(path); - if( !path.isEmpty() && licenseFile.open( QFile::ReadOnly ) ) { - cout << "Reading license file in....." << qPrintable(path) << endl; - - QString buffer = licenseFile.readLine(1024); - while (!buffer.isEmpty()) { - if( buffer[ 0 ] != '#' ) { - QStringList components = buffer.split( '=' ); - if ( components.size() >= 2 ) { - QStringList::Iterator it = components.begin(); - QString key = (*it++).trimmed().remove('"').toUpper(); - QString value = (*it++).trimmed().remove('"'); - licenseInfo[ key ] = value; - } - } - // read next line - buffer = licenseFile.readLine(1024); - } - licenseFile.close(); - } else { - cout << "License file not found in " << QDir::homePath() << endl; - cout << "Please put the Qt license file, '.qt-license' in your home " - << "directory and run configure again."; - dictionary["DONE"] = "error"; return; } - // Verify license info... - QString licenseKey = licenseInfo["LICENSEKEYEXT"]; - QByteArray clicenseKey = licenseKey.toLatin1(); - //We check the license - static const char * const SEP = "-"; - char *licenseParts[NUMBER_OF_PARTS]; - int partNumber = 0; - for (char *part = strtok(clicenseKey.data(), SEP); part != 0; part = strtok(0, SEP)) - licenseParts[partNumber++] = part; - if (partNumber < (NUMBER_OF_PARTS-1)) { - dictionary["DONE"] = "error"; - cout << "License file does not contain proper license key." < -#include #include - class Tools { public: - static void checkLicense(QMap &dictionary, QMap &licenseInfo, - const QString &path, const QString &sourcePath); + static void checkLicense(QMap &dictionary, + const QString &sourcePath, const QString &buildPath); }; #endif // _TOOLS_H_ From dc685cf6331f5fb46285cf10d6464c2ecf41f73e Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 24 Mar 2014 20:09:11 +0100 Subject: [PATCH 018/120] eglfs: Print the chosen config in debug mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit q_printEglConfig has been left unused. Start using it again, in case QT_QPA_EGLFS_DEBUG is set. This will, similarly to QSG_INFO, help debugging, especially on embedded devices. Change-Id: I1448632ed055dd71e98259f042d3cac64620a4ce Reviewed-by: Jørgen Lind --- src/platformsupport/eglconvenience/qeglconvenience.cpp | 4 +--- src/platformsupport/eglconvenience/qeglplatformcontext.cpp | 7 +++++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/platformsupport/eglconvenience/qeglconvenience.cpp b/src/platformsupport/eglconvenience/qeglconvenience.cpp index 7cf1f88b02d..f014ae42e53 100644 --- a/src/platformsupport/eglconvenience/qeglconvenience.cpp +++ b/src/platformsupport/eglconvenience/qeglconvenience.cpp @@ -446,11 +446,9 @@ void q_printEglConfig(EGLDisplay display, EGLConfig config) for (index = 0; attrs[index].attr != -1; ++index) { EGLint value; if (eglGetConfigAttrib(display, config, attrs[index].attr, &value)) { - qWarning("\t%s: %d\n", attrs[index].name, (int)value); + qDebug("\t%s: %d", attrs[index].name, (int)value); } } - - qWarning("\n"); } #ifdef Q_OS_LINUX diff --git a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp index 9c3b9b539c3..0dcb9f68bb3 100644 --- a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp +++ b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp @@ -44,6 +44,7 @@ #include "qeglpbuffer_p.h" #include #include +#include QT_BEGIN_NAMESPACE @@ -191,6 +192,12 @@ void QEGLPlatformContext::init(const QSurfaceFormat &format, QPlatformOpenGLCont return; } + static const bool printConfig = qgetenv("QT_QPA_EGLFS_DEBUG").toInt(); + if (printConfig) { + qDebug() << "Created context for format" << format << "with config:"; + q_printEglConfig(m_eglDisplay, m_eglConfig); + } + #ifndef QT_NO_OPENGL // Make the context current to ensure the GL version query works. This needs a surface too. const EGLint pbufferAttributes[] = { From 11a6270079657e40ff57d47be1eef6cb09a40d23 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 24 Mar 2014 20:03:22 +0100 Subject: [PATCH 019/120] eglfs: Add a way to force 24/32 bit configs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some embedded devices do not play nicely with 16-bit (565) EGL configurations, resulting in ugly banding in Quick apps. Add a QT_QPA_EGLFS_FORCE888 environment variable that can be set on systems where it is known that only 24 or 32 bit configs provide acceptable results. Change-Id: I7b8d7b9a2cd40b51a844d0795b7156b735e18ebb Reviewed-by: Jørgen Lind --- src/plugins/platforms/eglfs/qeglfshooks_stub.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp b/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp index dfb766db322..4aa3f292603 100644 --- a/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp +++ b/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp @@ -141,7 +141,16 @@ QImage::Format QEglFSHooks::screenFormat() const QSurfaceFormat QEglFSHooks::surfaceFormatFor(const QSurfaceFormat &inputFormat) const { - return inputFormat; + QSurfaceFormat format = inputFormat; + + static const bool force888 = qgetenv("QT_QPA_EGLFS_FORCE888").toInt(); + if (force888) { + format.setRedBufferSize(8); + format.setGreenBufferSize(8); + format.setBlueBufferSize(8); + } + + return format; } bool QEglFSHooks::filterConfig(EGLDisplay, EGLConfig) const From e7ad615cca2f4ae5383f1772b7c2845d59c4d68a Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 24 Mar 2014 19:58:58 +0100 Subject: [PATCH 020/120] Remove unused ifdef MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The QEGL_DEBUG defines have been removed some time ago from eglfs and eglconvenience, except for this one. It is also inconvenient due to the OpenGL dependency of it. Quick apps can anyway get the same information with QSG_INFO=1. Change-Id: Ie25c5286234a10699652d618d6f4174c6d3238e2 Reviewed-by: Jørgen Lind --- .../eglconvenience/qeglplatformcontext.cpp | 32 ++++--------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp index 0dcb9f68bb3..eec6463c210 100644 --- a/src/platformsupport/eglconvenience/qeglplatformcontext.cpp +++ b/src/platformsupport/eglconvenience/qeglplatformcontext.cpp @@ -268,37 +268,15 @@ bool QEGLPlatformContext::makeCurrent(QPlatformSurface *surface) return true; } - bool ok = eglMakeCurrent(m_eglDisplay, eglSurface, eglSurface, m_eglContext); - if (!ok) - qWarning("QEGLPlatformContext::makeCurrent: eglError: %x, this: %p \n", eglGetError(), this); -#ifdef QEGL_EXTRA_DEBUG - static bool showDebug = true; - if (showDebug) { - showDebug = false; - const char *str = (const char*)glGetString(GL_VENDOR); - qWarning("Vendor %s\n", str); - str = (const char*)glGetString(GL_RENDERER); - qWarning("Renderer %s\n", str); - str = (const char*)glGetString(GL_VERSION); - qWarning("Version %s\n", str); - - str = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION); - qWarning("Extensions %s\n",str); - - str = (const char*)glGetString(GL_EXTENSIONS); - qWarning("Extensions %s\n", str); - - } -#endif - + const bool ok = eglMakeCurrent(m_eglDisplay, eglSurface, eglSurface, m_eglContext); if (ok) { if (!m_swapIntervalEnvChecked) { m_swapIntervalEnvChecked = true; if (qEnvironmentVariableIsSet("QT_QPA_EGLFS_SWAPINTERVAL")) { QByteArray swapIntervalString = qgetenv("QT_QPA_EGLFS_SWAPINTERVAL"); - bool ok; - const int swapInterval = swapIntervalString.toInt(&ok); - if (ok) + bool intervalOk; + const int swapInterval = swapIntervalString.toInt(&intervalOk); + if (intervalOk) m_swapIntervalFromEnv = swapInterval; } } @@ -309,6 +287,8 @@ bool QEGLPlatformContext::makeCurrent(QPlatformSurface *surface) m_swapInterval = requestedSwapInterval; eglSwapInterval(eglDisplay(), m_swapInterval); } + } else { + qWarning("QEGLPlatformContext::makeCurrent: eglError: %x, this: %p \n", eglGetError(), this); } return ok; From f254474d71fb6e11f721e57214940c289a387c8e Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 24 Mar 2014 19:55:29 +0100 Subject: [PATCH 021/120] egl: Remove commented code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix also the statement about buffer size handling. Change-Id: I94e93fa4df7fee9b789ecca33d8722fbfc86ccc5 Reviewed-by: Jørgen Lind --- .../eglconvenience/qeglconvenience.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/platformsupport/eglconvenience/qeglconvenience.cpp b/src/platformsupport/eglconvenience/qeglconvenience.cpp index f014ae42e53..e6624fb9ff4 100644 --- a/src/platformsupport/eglconvenience/qeglconvenience.cpp +++ b/src/platformsupport/eglconvenience/qeglconvenience.cpp @@ -82,16 +82,7 @@ QVector q_createConfigAttributesFromFormat(const QSurfaceFormat &format) // put in the list before 32-bit configs. So, to make sure 16-bit is preffered over 32-bit, // we must set the red/green/blue sizes to zero. This has an unfortunate consequence that // if the application sets the red/green/blue size to 5/6/5 on the QSurfaceFormat, - // they will probably get a 32-bit config, even when there's an RGB565 config available. - -// // Now normalize the values so -1 becomes 0 -// redSize = redSize > 0 ? redSize : 0; -// greenSize = greenSize > 0 ? greenSize : 0; -// blueSize = blueSize > 0 ? blueSize : 0; -// alphaSize = alphaSize > 0 ? alphaSize : 0; -// depthSize = depthSize > 0 ? depthSize : 0; -// stencilSize = stencilSize > 0 ? stencilSize : 0; -// sampleCount = sampleCount > 0 ? sampleCount : 0; + // they might still get a 32-bit config, even when there's an RGB565 config available. QVector configAttributes; From 15be1e8c069b6b7b846d3e16f6a814c4a52e4165 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 24 Mar 2014 14:20:25 +0100 Subject: [PATCH 022/120] Fix up warnings in linuxfb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the warning about the graphics mode switch. In some environments it just pollutes the output since it will always fail. Change the errno-based warnings to qErrnoWarning. Change-Id: Ib7a7bfe64eda29996db288e52d369dcfad76c096 Reviewed-by: Friedemann Kleint Reviewed-by: Jørgen Lind --- src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp b/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp index aca8d76041a..72d5833e735 100644 --- a/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp +++ b/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp @@ -360,7 +360,7 @@ bool QLinuxFbScreen::initialize() // Open the device mFbFd = openFramebufferDevice(fbDevice); if (mFbFd == -1) { - qWarning("Failed to open framebuffer %s : %s", qPrintable(fbDevice), strerror(errno)); + qErrnoWarning(errno, "Failed to open framebuffer %s", qPrintable(fbDevice)); return false; } @@ -371,12 +371,12 @@ bool QLinuxFbScreen::initialize() memset(&finfo, 0, sizeof(finfo)); if (ioctl(mFbFd, FBIOGET_FSCREENINFO, &finfo) != 0) { - qWarning("Error reading fixed information: %s", strerror(errno)); + qErrnoWarning(errno, "Error reading fixed information"); return false; } if (ioctl(mFbFd, FBIOGET_VSCREENINFO, &vinfo)) { - qWarning("Error reading variable information: %s", strerror(errno)); + qErrnoWarning(errno, "Error reading variable information"); return false; } @@ -391,7 +391,7 @@ bool QLinuxFbScreen::initialize() mMmap.size = finfo.smem_len; uchar *data = (unsigned char *)mmap(0, mMmap.size, PROT_READ | PROT_WRITE, MAP_SHARED, mFbFd, 0); if ((long)data == -1) { - qWarning("Failed to mmap framebuffer: %s", strerror(errno)); + qErrnoWarning(errno, "Failed to mmap framebuffer"); return false; } @@ -420,10 +420,12 @@ bool QLinuxFbScreen::initialize() mTtyFd = openTtyDevice(ttyDevice); if (mTtyFd == -1) - qWarning() << "Failed to open tty" << strerror(errno); + qErrnoWarning(errno, "Failed to open tty"); - if (doSwitchToGraphicsMode && !switchToGraphicsMode(mTtyFd, &mOldTtyMode)) - qWarning() << "Failed to set graphics mode" << strerror(errno); + if (doSwitchToGraphicsMode) + switchToGraphicsMode(mTtyFd, &mOldTtyMode); + // Do not warn if the switch fails: the ioctl fails when launching from + // a remote console and there is nothing we can do about it. blankScreen(mFbFd, false); From 7f41e56ec3e69569b62e9ee76537a1123fc66bfc Mon Sep 17 00:00:00 2001 From: Andrew Knight Date: Sun, 16 Mar 2014 12:38:50 +0200 Subject: [PATCH 023/120] WinRT: Prevent GUI dispatcher lookup from non-GUI thread When we create an event dispatcher outside of the main thread, we shouldn't be looking up the core event dispatcher as it will fail. This ends up printing a scary warning for all e.g. Qt Quick apps when in reality nothing bad actually happened. Task-number: QTBUG-35327 Change-Id: I2060f0a9d4baffc42ca727e8d4e1ef7c13f6a2df Reviewed-by: Maurice Kalinowski --- src/corelib/kernel/qeventdispatcher_winrt.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/corelib/kernel/qeventdispatcher_winrt.cpp b/src/corelib/kernel/qeventdispatcher_winrt.cpp index 56f4ac40de1..1d4b57642c2 100644 --- a/src/corelib/kernel/qeventdispatcher_winrt.cpp +++ b/src/corelib/kernel/qeventdispatcher_winrt.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -109,6 +110,11 @@ QEventDispatcherWinRT::QEventDispatcherWinRT(QObject *parent) : QAbstractEventDispatcher(*new QEventDispatcherWinRTPrivate, parent) { Q_D(QEventDispatcherWinRT); + + // Only look up the event dispatcher in the main thread + if (QThread::currentThread() != QCoreApplicationPrivate::theMainThread) + return; + ComPtr application; HRESULT hr = RoGetActivationFactory(HString::MakeReference(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication).Get(), IID_PPV_ARGS(&application)); From d668f1be22c0e0219c02bcc6928a825ca4f33e42 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 25 Mar 2014 13:12:48 +0100 Subject: [PATCH 024/120] Fix regression in minimized state handling WM_STATE and _NET_WM_STATE are not the same. c6e271da6d1d972ad73a97871baafe57578a69a9 introduces a severe regression in this respect, making applications on xcb not to follow window state changes properly. Task-number: QTBUG-37695 Change-Id: Ia058bc11d5aa988eab513939c9f755c2f77512ee Reviewed-by: Martin Klapetek Reviewed-by: Shawn Rutledge --- src/plugins/platforms/xcb/qxcbwindow.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index d890398416e..bed6eb59dc9 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -1829,21 +1829,21 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev return; Qt::WindowState newState = Qt::WindowNoState; - if (event->atom == atom(QXcbAtom::_NET_WM_STATE)) { // WM_STATE: Quick check for 'Minimize'. + if (event->atom == atom(QXcbAtom::WM_STATE)) { // WM_STATE: Quick check for 'Minimize'. const xcb_get_property_cookie_t get_cookie = - xcb_get_property(xcb_connection(), 0, m_window, atom(QXcbAtom::_NET_WM_STATE), - XCB_ATOM_ANY, 0, 1024); + xcb_get_property(xcb_connection(), 0, m_window, atom(QXcbAtom::WM_STATE), + XCB_ATOM_ANY, 0, 1024); xcb_get_property_reply_t *reply = xcb_get_property_reply(xcb_connection(), get_cookie, NULL); - if (reply && reply->format == 32 && reply->type == atom(QXcbAtom::_NET_WM_STATE)) { + if (reply && reply->format == 32 && reply->type == atom(QXcbAtom::WM_STATE)) { const quint32 *data = (const quint32 *)xcb_get_property_value(reply); if (reply->length != 0 && XCB_WM_STATE_ICONIC == data[0]) newState = Qt::WindowMinimized; } free(reply); - } // WM_STATE: Quick check for 'Minimize'. + } if (newState != Qt::WindowMinimized) { // Something else changed, get _NET_WM_STATE. const NetWmStates states = netWmStates(); if ((states & NetWmStateMaximizedHorz) && (states & NetWmStateMaximizedVert)) From 0b87f4f6c912a508f170cd25ff5317bb77665fa9 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 25 Mar 2014 10:08:05 +0100 Subject: [PATCH 025/120] Android: Fix font merging Our fallback fonts would contain a minimal list of hardcoded fallback fonts, which is neither sufficient for displaying all text, nor portable to different vendors which can supply different font sets. [ChangeLog][Android] Fixed font merging problem which caused e.g. missing glyphs for Arabic numerals. Task-number: QTBUG-37738 Change-Id: Ic971343a1cd5610c79a81f6f6152c637937b5626 Reviewed-by: Konstantin Ritt --- src/gui/text/qfontdatabase.cpp | 2 +- .../basic/qbasicfontdatabase.cpp | 6 +++++- .../basic/qbasicfontdatabase_p.h | 2 +- .../android/qandroidplatformfontdatabase.cpp | 20 ++++++++++++++----- .../android/qandroidplatformfontdatabase.h | 3 +++ 5 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index ae7b6c1c0d5..558258c30e2 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -531,7 +531,7 @@ static const int scriptForWritingSystem[] = { Q_STATIC_ASSERT(sizeof(scriptForWritingSystem) / sizeof(scriptForWritingSystem[0]) == QFontDatabase::WritingSystemsCount); -int qt_script_for_writing_system(QFontDatabase::WritingSystem writingSystem) +Q_GUI_EXPORT int qt_script_for_writing_system(QFontDatabase::WritingSystem writingSystem) { return scriptForWritingSystem[writingSystem]; } diff --git a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp index 88814151b61..26ae0eb7243 100644 --- a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp +++ b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase.cpp @@ -220,7 +220,7 @@ void QBasicFontDatabase::releaseHandle(void *handle) extern FT_Library qt_getFreetype(); -QStringList QBasicFontDatabase::addTTFile(const QByteArray &fontData, const QByteArray &file) +QStringList QBasicFontDatabase::addTTFile(const QByteArray &fontData, const QByteArray &file, QSupportedWritingSystems *supportedWritingSystems) { FT_Library library = qt_getFreetype(); @@ -259,6 +259,8 @@ QStringList QBasicFontDatabase::addTTFile(const QByteArray &fontData, const QByt if (cm->encoding == FT_ENCODING_ADOBE_CUSTOM || cm->encoding == FT_ENCODING_MS_SYMBOL) { writingSystems.setSupported(QFontDatabase::Symbol); + if (supportedWritingSystems) + supportedWritingSystems->setSupported(QFontDatabase::Symbol); break; } } @@ -277,6 +279,8 @@ QStringList QBasicFontDatabase::addTTFile(const QByteArray &fontData, const QByt }; writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + if (supportedWritingSystems) + *supportedWritingSystems = writingSystems; if (os2->usWeightClass == 0) ; diff --git a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase_p.h b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase_p.h index 45d7218eceb..247a2855e2e 100644 --- a/src/platformsupport/fontdatabases/basic/qbasicfontdatabase_p.h +++ b/src/platformsupport/fontdatabases/basic/qbasicfontdatabase_p.h @@ -64,7 +64,7 @@ public: QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName); void releaseHandle(void *handle); - static QStringList addTTFile(const QByteArray &fontData, const QByteArray &file); + static QStringList addTTFile(const QByteArray &fontData, const QByteArray &file, QSupportedWritingSystems *supportedWritingSystems = 0); static QString fontNameFromTTFile(const QString &filename); }; diff --git a/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp b/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp index 7f68b44ed8b..7423e6c55a4 100644 --- a/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp +++ b/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp @@ -60,7 +60,17 @@ void QAndroidPlatformFontDatabase::populateFontDatabase() QDir dir(fontpath, QLatin1String("*.ttf")); for (int i = 0; i < int(dir.count()); ++i) { const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i])); - addTTFile(QByteArray(), file); + + QSupportedWritingSystems supportedWritingSystems; + QStringList families = addTTFile(QByteArray(), file, &supportedWritingSystems); + + extern int qt_script_for_writing_system(QFontDatabase::WritingSystem writingSystem); + for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) { + if (i == QFontDatabase::Any || supportedWritingSystems.supported(QFontDatabase::WritingSystem(i))) { + QChar::Script script = QChar::Script(qt_script_for_writing_system(QFontDatabase::WritingSystem(i))); + m_fallbacks[script] += families; + } + } } } @@ -71,9 +81,9 @@ QStringList QAndroidPlatformFontDatabase::fallbacksForFamily(const QString &fami { Q_UNUSED(family); Q_UNUSED(style); - Q_UNUSED(script); - if (styleHint == QFont::Monospace) - return QString(qgetenv("QT_ANDROID_FONTS_MONOSPACE")).split(";"); - return QString(qgetenv("QT_ANDROID_FONTS")).split(";"); + if (styleHint == QFont::Monospace) + return QString(qgetenv("QT_ANDROID_FONTS_MONOSPACE")).split(";") + m_fallbacks[script]; + + return QString(qgetenv("QT_ANDROID_FONTS")).split(";") + m_fallbacks[script]; } diff --git a/src/plugins/platforms/android/qandroidplatformfontdatabase.h b/src/plugins/platforms/android/qandroidplatformfontdatabase.h index 3cbfe95d366..cdd3cf16746 100644 --- a/src/plugins/platforms/android/qandroidplatformfontdatabase.h +++ b/src/plugins/platforms/android/qandroidplatformfontdatabase.h @@ -53,6 +53,9 @@ public: QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const; + +private: + QHash m_fallbacks; }; #endif // QANDROIDPLATFORMFONTDATABASE_H From a0dc3e608fe67ae1ec3f0ee92e1dc15ebaa0fe9e Mon Sep 17 00:00:00 2001 From: Tasuku Suzuki Date: Wed, 19 Feb 2014 01:05:32 +0900 Subject: [PATCH 026/120] qmake: change a linker option in .pc file from -llibhoge to -lhoge Change-Id: Ib4d01bf190eec753f1b5e37e8e5871514e43ac71 Reviewed-by: Oswald Buddenhagen --- qmake/generators/makefile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index fe8d289a7c0..bad4eb54561 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -3299,7 +3299,7 @@ MakefileGenerator::writePkgConfigFile() pkgConfiglibName = "-framework " + bundle + " "; } else { pkgConfiglibDir = "-L${libdir}"; - pkgConfiglibName = "-l" + fileInfo(fname).completeBaseName(); + pkgConfiglibName = "-l" + unescapeFilePath(project->first("QMAKE_ORIG_TARGET")); if (project->isActiveConfig("shared")) pkgConfiglibName += project->first("TARGET_VERSION_EXT").toQString(); } From f1f07eae2d40f202a709af33ca1e8d86551c9ace Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Sat, 22 Mar 2014 08:08:08 +0200 Subject: [PATCH 027/120] Android: Fix software keyboard show/hide state Task-number: QTBUG-34831 Change-Id: Ic38334d011ceef2dc75e4fb3fcea48f62aeea757 Reviewed-by: Paul Olav Tvete --- .../qt5/android/QtActivityDelegate.java | 22 +++++++---- .../qt5/android/QtInputConnection.java | 39 +++---------------- 2 files changed, 20 insertions(+), 41 deletions(-) diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java index ea8e5cd44c3..e62b5dab825 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtActivityDelegate.java @@ -120,7 +120,7 @@ public class QtActivityDelegate private boolean m_keyboardIsVisible = false; public boolean m_backKeyPressedSent = false; - + private long m_showHideTimeStamp = System.nanoTime(); public void setFullScreen(boolean enterFullScreen) { @@ -201,12 +201,18 @@ public class QtActivityDelegate private final int ApplicationInactive = 0x2; private final int ApplicationActive = 0x4; - public void setKeyboardVisibility(boolean visibility) + + public boolean setKeyboardVisibility(boolean visibility, long timeStamp) { + if (m_showHideTimeStamp > timeStamp) + return false; + m_showHideTimeStamp = timeStamp; + if (m_keyboardIsVisible == visibility) - return; + return false; m_keyboardIsVisible = visibility; QtNative.keyboardVisibilityChanged(m_keyboardIsVisible); + return true; } public void resetSoftwareKeyboard() { @@ -304,11 +310,11 @@ public class QtActivityDelegate QtNativeInputConnection.updateCursorPosition(); //FALLTHROUGH case InputMethodManager.RESULT_UNCHANGED_SHOWN: - setKeyboardVisibility(true); + setKeyboardVisibility(true, System.nanoTime()); break; case InputMethodManager.RESULT_HIDDEN: case InputMethodManager.RESULT_UNCHANGED_HIDDEN: - setKeyboardVisibility(false); + setKeyboardVisibility(false, System.nanoTime()); break; } } @@ -331,11 +337,11 @@ public class QtActivityDelegate switch (resultCode) { case InputMethodManager.RESULT_SHOWN: case InputMethodManager.RESULT_UNCHANGED_SHOWN: - setKeyboardVisibility(true); + setKeyboardVisibility(true, System.nanoTime()); break; case InputMethodManager.RESULT_HIDDEN: case InputMethodManager.RESULT_UNCHANGED_HIDDEN: - setKeyboardVisibility(false); + setKeyboardVisibility(false, System.nanoTime()); break; } } @@ -827,7 +833,7 @@ public class QtActivityDelegate if (keyCode == KeyEvent.KEYCODE_BACK && !m_backKeyPressedSent) { hideSoftwareKeyboard(); - setKeyboardVisibility(false); + setKeyboardVisibility(false, System.nanoTime()); return true; } diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtInputConnection.java b/src/android/jar/src/org/qtproject/qt5/android/QtInputConnection.java index 5e6e227c2b1..655ab95dd80 100644 --- a/src/android/jar/src/org/qtproject/qt5/android/QtInputConnection.java +++ b/src/android/jar/src/org/qtproject/qt5/android/QtInputConnection.java @@ -82,18 +82,11 @@ class QtNativeInputConnection } class HideKeyboardRunnable implements Runnable { - private QtInputConnection m_connection; - HideKeyboardRunnable(QtInputConnection connection) - { - m_connection = connection; - } + private long m_hideTimeStamp = System.nanoTime(); @Override public void run() { - if (m_connection.getInputState() == QtInputConnection.InputStates.Hiding) { - QtNative.activityDelegate().setKeyboardVisibility(false); - m_connection.reset(); - } + QtNative.activityDelegate().setKeyboardVisibility(false, m_hideTimeStamp); } } @@ -107,34 +100,14 @@ public class QtInputConnection extends BaseInputConnection private static final int ID_SWITCH_INPUT_METHOD = android.R.id.switchInputMethod; private static final int ID_ADD_TO_DICTIONARY = android.R.id.addToDictionary; - - enum InputStates { Visible, FinishComposing, Hiding }; - private QtEditText m_view = null; - private InputStates m_inputState = InputStates.Visible; - - public void reset() - { - m_inputState = InputStates.Visible; - } - - public InputStates getInputState() - { - return m_inputState; - } private void setClosing(boolean closing) { - if (closing && m_inputState == InputStates.Hiding) - return; - - if (closing && m_view.getActivityDelegate().isSoftwareKeyboardVisible()) { - m_view.postDelayed(new HideKeyboardRunnable(this), 100); - m_inputState = InputStates.Hiding; + if (closing) { + m_view.postDelayed(new HideKeyboardRunnable(), 100); } else { - if (m_inputState == InputStates.Hiding) - QtNative.activityDelegate().setKeyboardVisibility(true); - m_inputState = closing ? InputStates.FinishComposing : InputStates.Visible; + QtNative.activityDelegate().setKeyboardVisibility(true, System.nanoTime()); } } @@ -154,7 +127,7 @@ public class QtInputConnection extends BaseInputConnection @Override public boolean endBatchEdit() { -// setClosing(false); + setClosing(false); return true; } From 12bd35aa24c914046e30a46f650ed2e43c4956b1 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Mon, 24 Mar 2014 09:35:52 +0200 Subject: [PATCH 028/120] REG: Fix window repaint geometry Task-number: QTBUG-37530 Change-Id: I642c8ef8cf7de50e4a84d8356693b82f8674cece Reviewed-by: Paul Olav Tvete --- .../platforms/android/qandroidplatformrasterwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/platforms/android/qandroidplatformrasterwindow.cpp b/src/plugins/platforms/android/qandroidplatformrasterwindow.cpp index 334b9cdd236..eb5a73c4a34 100644 --- a/src/plugins/platforms/android/qandroidplatformrasterwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformrasterwindow.cpp @@ -57,7 +57,7 @@ void QAndroidPlatformRasterWindow::repaint(const QRegion ®ion) if (QAndroidPlatformWindow::parent()) return; - QRect currentGeometry = geometry().translated(mapToGlobal(QPoint(0,0))); + QRect currentGeometry = geometry(); QRect dirtyClient = region.boundingRect(); QRect dirtyRegion(currentGeometry.left() + dirtyClient.left(), @@ -74,7 +74,7 @@ void QAndroidPlatformRasterWindow::repaint(const QRegion ®ion) void QAndroidPlatformRasterWindow::setGeometry(const QRect &rect) { - m_oldGeometry = geometry().translated(mapToGlobal(QPoint(0,0)));; + m_oldGeometry = geometry(); QAndroidPlatformWindow::setGeometry(rect); } From cd08d34452c9dd1a7f69c93b5380bc39cb9a52bb Mon Sep 17 00:00:00 2001 From: Sze Howe Koh Date: Wed, 19 Mar 2014 22:37:57 +0800 Subject: [PATCH 029/120] QDoc: Doc: Use correct terminology ("signal" vs. "signal handler") Change-Id: I0c6cdc77296b8a1a759671bac2c920bc05d0cbcb Reviewed-by: Jerome Pasion --- src/tools/qdoc/doc/qdoc-manual-topiccmds.qdoc | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/tools/qdoc/doc/qdoc-manual-topiccmds.qdoc b/src/tools/qdoc/doc/qdoc-manual-topiccmds.qdoc index 68f3f9652bb..b9667b7758e 100644 --- a/src/tools/qdoc/doc/qdoc-manual-topiccmds.qdoc +++ b/src/tools/qdoc/doc/qdoc-manual-topiccmds.qdoc @@ -1113,27 +1113,24 @@ \section1 \\qmlattachedsignal The \\qmlattachedsignal command is for documenting an attachable - \l{http://qt-project.org/doc/qt-4.7/qdeclarativeintroduction.html#signal-handlers} - {signal handler}. The \\qmlattachedsignal command is used just like - the \l{qmlsignal-command} {\\qmlsignal} command. + \l{Signal and Handler Event System}{signal}. The \\qmlattachedsignal + command is used just like the \l{qmlsignal-command} {\\qmlsignal} command. The argument is the rest of the line. It should be the name of the - QML type where the signal handler is declared, the \c{::} - qualifier, and finally the signal handler name. If we have a QML - attached signal handler named \c onAdd() in the \c GridView - element, the \\qmlattachedsignal for it would look like this: + QML type where the signal is declared, the \c{::} + qualifier, and finally the signal name. For example, a QML + attached signal named \c add() in the \c GridView + element is documented like this: \code / *! - \qmlattachedsignal GridView::onAdd() - This attached handler is called immediately after an item is - added to the view. + \qmlattachedsignal GridView::add() + This attached signal is emitted immediately after an item is added to the view. * / \endcode QDoc includes this documentation on the QML reference page for the - \l{http://qt-project.org/doc/qt-4.7/qml-gridview.html#onAdd-signal} - {GridView} element. + \l GridView element. \target qmlbasictype-command \section1 \\qmlbasictype From 5b00bb39f2f079e4745a0ca6f3a8c56e18bd2775 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Fri, 21 Mar 2014 10:35:09 +0100 Subject: [PATCH 030/120] Polish tst_qsslsocket a bit. Output the SSL library version, output socket error string on connection failure consistently, silence numerous warnings about QIODevice not being open in tst_QSslSocket::constructing. Change-Id: Ia23d42de5b2daca55b2f6f50af025d61e99c52a0 Reviewed-by: Peter Hartmann --- .../network/ssl/qsslsocket/tst_qsslsocket.cpp | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp index 6eb20dd1f5c..ded39669928 100644 --- a/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp +++ b/tests/auto/network/ssl/qsslsocket/tst_qsslsocket.cpp @@ -271,6 +271,9 @@ void tst_QSslSocket::initTestCase_data() void tst_QSslSocket::initTestCase() { + qDebug("Using SSL library %s (%ld)", + qPrintable(QSslSocket::sslLibraryVersionString()), + QSslSocket::sslLibraryVersionNumber()); QVERIFY(QtNetworkSettings::verifyTestNetworkSettings()); } @@ -347,6 +350,9 @@ void tst_QSslSocket::proxyAuthenticationRequired(const QNetworkProxy &, QAuthent void tst_QSslSocket::constructing() { + const char readNotOpenMessage[] = "QIODevice::read: device not open"; + const char writeNotOpenMessage[] = "QIODevice::write: device not open"; + if (!QSslSocket::supportsSsl()) return; @@ -363,6 +369,7 @@ void tst_QSslSocket::constructing() QCOMPARE(socket.sslConfiguration(), QSslConfiguration::defaultConfiguration()); QCOMPARE(socket.errorString(), QString("Unknown error")); char c = '\0'; + QTest::ignoreMessage(QtWarningMsg, readNotOpenMessage); QVERIFY(!socket.getChar(&c)); QCOMPARE(c, '\0'); QVERIFY(!socket.isOpen()); @@ -371,11 +378,16 @@ void tst_QSslSocket::constructing() QVERIFY(!socket.isTextModeEnabled()); QVERIFY(!socket.isWritable()); QCOMPARE(socket.openMode(), QIODevice::NotOpen); + QTest::ignoreMessage(QtWarningMsg, readNotOpenMessage); QVERIFY(socket.peek(2).isEmpty()); QCOMPARE(socket.pos(), qint64(0)); + QTest::ignoreMessage(QtWarningMsg, writeNotOpenMessage); QVERIFY(!socket.putChar('c')); + QTest::ignoreMessage(QtWarningMsg, readNotOpenMessage); QVERIFY(socket.read(2).isEmpty()); + QTest::ignoreMessage(QtWarningMsg, readNotOpenMessage); QCOMPARE(socket.read(0, 0), qint64(-1)); + QTest::ignoreMessage(QtWarningMsg, readNotOpenMessage); QVERIFY(socket.readAll().isEmpty()); QTest::ignoreMessage(QtWarningMsg, "QIODevice::readLine: Called with maxSize < 2"); QCOMPARE(socket.readLine(0, 0), qint64(-1)); @@ -388,7 +400,9 @@ void tst_QSslSocket::constructing() QCOMPARE(socket.size(), qint64(0)); QVERIFY(!socket.waitForBytesWritten(10)); QVERIFY(!socket.waitForReadyRead(10)); + QTest::ignoreMessage(QtWarningMsg, writeNotOpenMessage); QCOMPARE(socket.write(0, 0), qint64(-1)); + QTest::ignoreMessage(QtWarningMsg, writeNotOpenMessage); QCOMPARE(socket.write(QByteArray()), qint64(-1)); QCOMPARE(socket.error(), QAbstractSocket::UnknownSocketError); QVERIFY(!socket.flush()); @@ -672,7 +686,7 @@ void tst_QSslSocket::sessionCipher() connect(socket.data(), SIGNAL(sslErrors(QList)), this, SLOT(ignoreErrorSlot())); QVERIFY(socket->sessionCipher().isNull()); socket->connectToHost(QtNetworkSettings::serverName(), 443 /* https */); - QVERIFY(socket->waitForConnected(10000)); + QVERIFY2(socket->waitForConnected(10000), qPrintable(socket->errorString())); QVERIFY(socket->sessionCipher().isNull()); socket->startClientEncryption(); if (!socket->waitForEncrypted(5000)) @@ -775,7 +789,7 @@ void tst_QSslSocket::peerCertificateChain() socket->connectToHost(QtNetworkSettings::serverName(), 443); QCOMPARE(socket->mode(), QSslSocket::UnencryptedMode); QVERIFY(socket->peerCertificateChain().isEmpty()); - QVERIFY2(socket->waitForConnected(10000), "Network timeout"); + QVERIFY2(socket->waitForConnected(10000), qPrintable(socket->errorString())); socket->startClientEncryption(); if (setProxy && !socket->waitForEncrypted(10000)) @@ -1334,7 +1348,7 @@ void tst_QSslSocket::waitForConnectedEncryptedReadyRead() connect(this->socket, SIGNAL(sslErrors(QList)), this, SLOT(ignoreErrorSlot())); socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 993); - QVERIFY(socket->waitForConnected(10000)); + QVERIFY2(socket->waitForConnected(10000), qPrintable(socket->errorString())); QFETCH_GLOBAL(bool, setProxy); if (setProxy && !socket->waitForEncrypted(10000)) QSKIP("Skipping flaky test - See QTBUG-29941"); @@ -1679,7 +1693,7 @@ void tst_QSslSocket::setReadBufferSize_task_250027() socket->ignoreSslErrors(); socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); socket->ignoreSslErrors(); - QVERIFY(socket->waitForConnected(10*1000)); + QVERIFY2(socket->waitForConnected(10*1000), qPrintable(socket->errorString())); if (setProxy && !socket->waitForEncrypted(10*1000)) QSKIP("Skipping flaky test - See QTBUG-29941"); From 5279134935e858e6fa8565c936b17e88d7bded50 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Tue, 21 Jan 2014 10:35:01 +0100 Subject: [PATCH 031/120] Reuse one QCollator instance for QString::localeAwareCompare Constructing a QCollator is somewhat expensive, and made localeAwareCompare really slow. As QCollator (at least with the ICU implementation) is not thread safe, use one collator per thread. This speeds up collation of a long list of strings by a factor of 250 for the test case in the bug below. Task-number: QTBUG-36149 Change-Id: I645cdc3546347d1dcc7a03b7563b628c7f756944 Reviewed-by: Thiago Macieira Reviewed-by: Konstantin Ritt --- src/corelib/tools/qstring.cpp | 10 ++++++++-- tests/auto/corelib/tools/qstring/tst_qstring.cpp | 6 ++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index a8770e886b5..f14cdcedda5 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -78,6 +78,7 @@ #include "qchar.cpp" #include "qstringmatcher.cpp" #include "qstringiterator_p.h" +#include "qthreadstorage.h" #ifdef Q_OS_WIN # include @@ -5319,6 +5320,10 @@ int QString::localeAwareCompare(const QString &other) const return localeAwareCompare_helper(constData(), length(), other.constData(), other.length()); } +#if defined(QT_USE_ICU) +Q_GLOBAL_STATIC(QThreadStorage, defaultCollator) +#endif + /*! \internal \since 4.5 @@ -5362,8 +5367,9 @@ int QString::localeAwareCompare_helper(const QChar *data1, int length1, CFRelease(otherString); return result; #elif defined(QT_USE_ICU) - QCollator collator; - return collator.compare(data1, length1, data2, length2); + if (!defaultCollator()->hasLocalData()) + defaultCollator()->setLocalData(QCollator()); + return defaultCollator()->localData().compare(data1, length1, data2, length2); #elif defined(Q_OS_UNIX) // declared in int delta = strcoll(toLocal8Bit_helper(data1, length1).constData(), toLocal8Bit_helper(data2, length2).constData()); diff --git a/tests/auto/corelib/tools/qstring/tst_qstring.cpp b/tests/auto/corelib/tools/qstring/tst_qstring.cpp index 629a095f9db..5655d9f529e 100644 --- a/tests/auto/corelib/tools/qstring/tst_qstring.cpp +++ b/tests/auto/corelib/tools/qstring/tst_qstring.cpp @@ -4876,10 +4876,8 @@ void tst_QString::localeAwareCompare() DWORD oldLcid = GetUserDefaultLCID(); SetUserDefaultLCID(locale); QCOMPARE(locale, GetUserDefaultLCID()); -#elif defined (Q_OS_MAC) - QSKIP("Setting the locale is not supported on OS X (you can set the C locale, but that won't affect CFStringCompare which is used to compare strings)"); -#elif defined(QT_USE_ICU) - QLocale::setDefault(QLocale(locale)); +#elif defined (Q_OS_MAC) || defined(QT_USE_ICU) + QSKIP("Setting the locale is not supported on OS X or ICU (you can set the C locale, but that won't affect localeAwareCompare)"); #else if (!locale.isEmpty()) { const char *newLocale = setlocale(LC_ALL, locale.toLatin1()); From 071098b08b12fc1af6341ff6d7ba6713e5de1481 Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Fri, 21 Mar 2014 09:36:05 +0100 Subject: [PATCH 032/120] Make QWidget::render() work correctly with all paint devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure QWidget::render takes correct code paths with all kinds of paint devices. Correctly restore the inRenderWithPainter flag. The old code would not correctly restore the flag, likely leading to inconsistencies. Remove the unused last parameter in QWidgetPrivate::render. Remove the special handling for QPrinter in the same method. Task-number: QTBUG-26564 Change-Id: Iba43269b090abd8dd88c5225b75e1ee9239d58f9 Reviewed-by: Friedemann Kleint Reviewed-by: Morten Johan Sørvig Reviewed-by: Paul Olav Tvete --- src/widgets/kernel/qwidget.cpp | 29 +++++++---------------------- src/widgets/kernel/qwidget_p.h | 2 +- 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index 102e659fbf3..c2f7a9b184a 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -4677,7 +4677,8 @@ void QWidget::unsetCursor() void QWidget::render(QPaintDevice *target, const QPoint &targetOffset, const QRegion &sourceRegion, RenderFlags renderFlags) { - d_func()->render(target, targetOffset, sourceRegion, renderFlags, false); + QPainter p(target); + render(&p, targetOffset, sourceRegion, renderFlags); } /*! @@ -4721,9 +4722,6 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset, d->createExtra(); d->extra->inRenderWithPainter = true; -#ifdef Q_WS_MAC - d->render_helper(painter, targetOffset, toBePainted, renderFlags); -#else QPaintEngine *engine = painter->paintEngine(); Q_ASSERT(engine); QPaintEnginePrivate *enginePriv = engine->d_func(); @@ -4734,7 +4732,7 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset, // Render via a pixmap when dealing with non-opaque painters or printers. if (!inRenderWithPainter && (opacity < 1.0 || (target->devType() == QInternal::Printer))) { d->render_helper(painter, targetOffset, toBePainted, renderFlags); - d->extra->inRenderWithPainter = false; + d->extra->inRenderWithPainter = inRenderWithPainter; return; } @@ -4755,7 +4753,7 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset, enginePriv->setSystemViewport(oldSystemClip); } - render(target, targetOffset, toBePainted, renderFlags); + d->render(target, targetOffset, toBePainted, renderFlags); // Restore system clip, viewport and transform. enginePriv->systemClip = oldSystemClip; @@ -4764,9 +4762,8 @@ void QWidget::render(QPainter *painter, const QPoint &targetOffset, // Restore shared painter. d->setSharedPainter(oldPainter); -#endif - d->extra->inRenderWithPainter = false; + d->extra->inRenderWithPainter = inRenderWithPainter; } static void sendResizeEvents(QWidget *target) @@ -5204,8 +5201,7 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP } void QWidgetPrivate::render(QPaintDevice *target, const QPoint &targetOffset, - const QRegion &sourceRegion, QWidget::RenderFlags renderFlags, - bool readyToRender) + const QRegion &sourceRegion, QWidget::RenderFlags renderFlags) { if (!target) { qWarning("QWidget::render: null pointer to paint device"); @@ -5213,7 +5209,7 @@ void QWidgetPrivate::render(QPaintDevice *target, const QPoint &targetOffset, } const bool inRenderWithPainter = extra && extra->inRenderWithPainter; - QRegion paintRegion = !inRenderWithPainter && !readyToRender + QRegion paintRegion = !inRenderWithPainter ? prepareToRender(sourceRegion, renderFlags) : sourceRegion; if (paintRegion.isEmpty()) @@ -5272,23 +5268,12 @@ void QWidgetPrivate::render(QPaintDevice *target, const QPoint &targetOffset, flags |= DontSetCompositionMode; - if (target->devType() == QInternal::Printer) { - QPainter p(target); - render_helper(&p, targetOffset, paintRegion, renderFlags); - return; - } - -#ifndef Q_WS_MAC // Render via backingstore. drawWidget(target, paintRegion, offset, flags, sharedPainter()); // Restore shared painter. if (oldSharedPainter) setSharedPainter(oldSharedPainter); -#else - // Render via backingstore (no shared painter). - drawWidget(target, paintRegion, offset, flags, 0); -#endif } void QWidgetPrivate::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectList& siblings, int index, const QRegion &rgn, diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h index bdfc57f7c30..41e36ee6a50 100644 --- a/src/widgets/kernel/qwidget_p.h +++ b/src/widgets/kernel/qwidget_p.h @@ -389,7 +389,7 @@ public: void render_helper(QPainter *painter, const QPoint &targetOffset, const QRegion &sourceRegion, QWidget::RenderFlags renderFlags); void render(QPaintDevice *target, const QPoint &targetOffset, const QRegion &sourceRegion, - QWidget::RenderFlags renderFlags, bool readyToRender); + QWidget::RenderFlags renderFlags); void drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QPoint &offset, int flags, QPainter *sharedPainter = 0, QWidgetBackingStore *backingStore = 0); From 244e2ef7b9f078faecb9ec6f08c66864eb0ce399 Mon Sep 17 00:00:00 2001 From: Andrew Knight Date: Wed, 26 Mar 2014 13:22:00 +0200 Subject: [PATCH 033/120] WinRT: Use registerFontFamily to reduce font registration overhead Adopt to the new lazy font loading strategy in order to reduce memory and startup time associated with populating the entire font database. Change-Id: I0134cc123f73cb8485fe85c4a6b8e3b3a3a2cab0 Reviewed-by: Oliver Wolff --- .../platforms/winrt/qwinrtfontdatabase.cpp | 351 ++++++++++-------- .../platforms/winrt/qwinrtfontdatabase.h | 3 + 2 files changed, 192 insertions(+), 162 deletions(-) diff --git a/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp b/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp index 3da87de708a..70bb9469dbe 100644 --- a/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp +++ b/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp @@ -63,7 +63,7 @@ QString QWinRTFontDatabase::fontDir() const fontDirectory = applicationDirPath + QLatin1String("/fonts"); if (!QFile::exists(fontDirectory)) { #ifndef Q_OS_WINPHONE - if (m_fonts.isEmpty()) + if (m_fontFamilies.isEmpty()) #endif qWarning("No fonts directory found in application package."); fontDirectory = applicationDirPath; @@ -78,6 +78,9 @@ QWinRTFontDatabase::~QWinRTFontDatabase() { foreach (IDWriteFontFile *fontFile, m_fonts.keys()) fontFile->Release(); + + foreach (IDWriteFontFamily *fontFamily, m_fontFamilies) + fontFamily->Release(); } QFont QWinRTFontDatabase::defaultFont() const @@ -132,175 +135,196 @@ void QWinRTFontDatabase::populateFontDatabase() } QString familyName = QString::fromWCharArray(familyBuffer.data(), familyNameLength); - int fontCount = fontFamily->GetFontCount(); - for (int j = 0; j < fontCount; ++j) { - ComPtr font; - hr = fontFamily->GetFont(j, &font); - if (FAILED(hr)) { - qWarning("Unable to get base font: %s", qPrintable(qt_error_string(hr))); - continue; - } + m_fontFamilies.insert(familyName, fontFamily.Detach()); - ComPtr baseFontFace; - hr = font->CreateFontFace(&baseFontFace); - if (FAILED(hr)) { - qWarning("Unable to create base font face: %s", qPrintable(qt_error_string(hr))); - continue; - } - ComPtr fontFace; - hr = baseFontFace.As(&fontFace); - if (FAILED(hr)) { - qWarning("Unable to create font face: %s", qPrintable(qt_error_string(hr))); - continue; - } - - // Only try to load true-type fonts - DWRITE_FONT_FACE_TYPE type = fontFace->GetType(); - if (!(type == DWRITE_FONT_FACE_TYPE_TRUETYPE - || type == DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION)) { - continue; - } - - // We can't deal with multi-file fonts - quint32 fileCount; - hr = fontFace->GetFiles(&fileCount, NULL); - if (FAILED(hr)) { - qWarning("Unable to get font file count: %s", qPrintable(qt_error_string(hr))); - continue; - } - if (fileCount != 1) // Should not happen as we only look at TT fonts - continue; - - ComPtr informationalStrings; - BOOL exists; - hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_MANUFACTURER, - &informationalStrings, &exists); - if (FAILED(hr)) { - qWarning("Unable to get font foundry: %s", qPrintable(qt_error_string(hr))); - continue; - } - QString foundryName; - if (exists) { - quint32 length; - hr = informationalStrings->GetStringLength(0, &length); - if (FAILED(hr)) - qWarning("Unable to get foundry name length: %s", qPrintable(qt_error_string(hr))); - if (SUCCEEDED(hr)) { - QVector buffer(length + 1); - hr = informationalStrings->GetString(0, buffer.data(), buffer.size()); - if (FAILED(hr)) - qWarning("Unable to get foundry name: %s", qPrintable(qt_error_string(hr))); - if (SUCCEEDED(hr)) - foundryName = QString::fromWCharArray(buffer.data(), length); - } - } - - QFont::Weight weight; - switch (font->GetWeight()) { - case DWRITE_FONT_WEIGHT_THIN: - case DWRITE_FONT_WEIGHT_EXTRA_LIGHT: - case DWRITE_FONT_WEIGHT_LIGHT: - case DWRITE_FONT_WEIGHT_SEMI_LIGHT: - weight = QFont::Light; - break; - default: - case DWRITE_FONT_WEIGHT_NORMAL: - case DWRITE_FONT_WEIGHT_MEDIUM: - weight = QFont::Normal; - break; - case DWRITE_FONT_WEIGHT_DEMI_BOLD: - weight = QFont::DemiBold; - break; - case DWRITE_FONT_WEIGHT_BOLD: - case DWRITE_FONT_WEIGHT_EXTRA_BOLD: - weight = QFont::Bold; - break; - case DWRITE_FONT_WEIGHT_BLACK: - case DWRITE_FONT_WEIGHT_EXTRA_BLACK: - weight = QFont::Black; - break; - } - - QFont::Style style; - switch (font->GetStyle()) { - default: - case DWRITE_FONT_STYLE_NORMAL: - style = QFont::StyleNormal; - break; - case DWRITE_FONT_STYLE_OBLIQUE: - style = QFont::StyleOblique; - break; - case DWRITE_FONT_STYLE_ITALIC: - style = QFont::StyleItalic; - break; - } - - QFont::Stretch stretch; - switch (font->GetStretch()) { - default: - case DWRITE_FONT_STRETCH_UNDEFINED: - case DWRITE_FONT_STRETCH_NORMAL: - stretch = QFont::Unstretched; - break; - case DWRITE_FONT_STRETCH_ULTRA_CONDENSED: - stretch = QFont::UltraCondensed; - break; - case DWRITE_FONT_STRETCH_EXTRA_CONDENSED: - stretch = QFont::ExtraCondensed; - break; - case DWRITE_FONT_STRETCH_CONDENSED: - stretch = QFont::Condensed; - break; - case DWRITE_FONT_STRETCH_SEMI_CONDENSED: - stretch = QFont::SemiCondensed; - break; - case DWRITE_FONT_STRETCH_SEMI_EXPANDED: - stretch = QFont::SemiExpanded; - break; - case DWRITE_FONT_STRETCH_EXPANDED: - stretch = QFont::Expanded; - break; - case DWRITE_FONT_STRETCH_EXTRA_EXPANDED: - stretch = QFont::ExtraExpanded; - break; - case DWRITE_FONT_STRETCH_ULTRA_EXPANDED: - stretch = QFont::UltraExpanded; - break; - } - - const bool fixedPitch = fontFace->IsMonospacedFont(); - - quint32 unicodeRange[4]; - quint32 actualRangeCount; - hr = fontFace->GetUnicodeRanges( - 2, reinterpret_cast(unicodeRange), &actualRangeCount); - if (FAILED(hr) && hr != E_NOT_SUFFICIENT_BUFFER) { // Ignore insufficient buffer; we only need 4 indices - qWarning("Unable to get font unicode range: %s", qPrintable(qt_error_string(hr))); - continue; - } - quint32 codePageRange[2] = { 0, 0 }; - QSupportedWritingSystems writingSystems = - QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange); - - IDWriteFontFile *fontFile; - hr = fontFace->GetFiles(&fileCount, &fontFile); - if (FAILED(hr)) { - qWarning("Unable to get font file: %s", qPrintable(qt_error_string(hr))); - continue; - } - - FontDescription description = { fontFace->GetIndex(), QUuid::createUuid().toByteArray() }; - m_fonts.insert(fontFile, description); - registerFont(familyName, QString(), foundryName, weight, style, stretch, - true, true, 0, fixedPitch, writingSystems, fontFile); - } + registerFontFamily(familyName); } QBasicFontDatabase::populateFontDatabase(); } +void QWinRTFontDatabase::populateFamily(const QString &familyName) +{ + IDWriteFontFamily *fontFamily = m_fontFamilies.value(familyName); + if (!fontFamily) { + qWarning("The font family %s was not found.", qPrintable(familyName)); + return; + } + + bool fontRegistered = false; + const int fontCount = fontFamily->GetFontCount(); + for (int j = 0; j < fontCount; ++j) { + ComPtr font; + HRESULT hr = fontFamily->GetFont(j, &font); + if (FAILED(hr)) { + qWarning("Unable to get font: %s", qPrintable(qt_error_string(hr))); + continue; + } + + // Skip simulated faces + if (font->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE) + continue; + + ComPtr baseFontFace; + hr = font->CreateFontFace(&baseFontFace); + if (FAILED(hr)) { + qWarning("Unable to create base font face: %s", qPrintable(qt_error_string(hr))); + continue; + } + ComPtr fontFace; + hr = baseFontFace.As(&fontFace); + if (FAILED(hr)) { + qWarning("Unable to create font face: %s", qPrintable(qt_error_string(hr))); + continue; + } + + // We can't deal with multi-file fonts + quint32 fileCount; + hr = fontFace->GetFiles(&fileCount, NULL); + if (FAILED(hr)) { + qWarning("Unable to get font file count: %s", qPrintable(qt_error_string(hr))); + continue; + } + if (fileCount != 1) + continue; + + ComPtr informationalStrings; + BOOL exists; + hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_MANUFACTURER, + &informationalStrings, &exists); + if (FAILED(hr)) { + qWarning("Unable to get font foundry: %s", qPrintable(qt_error_string(hr))); + continue; + } + QString foundryName; + if (exists) { + quint32 length; + hr = informationalStrings->GetStringLength(0, &length); + if (FAILED(hr)) + qWarning("Unable to get foundry name length: %s", qPrintable(qt_error_string(hr))); + if (SUCCEEDED(hr)) { + QVector buffer(length + 1); + hr = informationalStrings->GetString(0, buffer.data(), buffer.size()); + if (FAILED(hr)) + qWarning("Unable to get foundry name: %s", qPrintable(qt_error_string(hr))); + if (SUCCEEDED(hr)) + foundryName = QString::fromWCharArray(buffer.data(), length); + } + } + + QFont::Weight weight; + switch (font->GetWeight()) { + case DWRITE_FONT_WEIGHT_THIN: + case DWRITE_FONT_WEIGHT_EXTRA_LIGHT: + case DWRITE_FONT_WEIGHT_LIGHT: + case DWRITE_FONT_WEIGHT_SEMI_LIGHT: + weight = QFont::Light; + break; + default: + case DWRITE_FONT_WEIGHT_NORMAL: + case DWRITE_FONT_WEIGHT_MEDIUM: + weight = QFont::Normal; + break; + case DWRITE_FONT_WEIGHT_DEMI_BOLD: + weight = QFont::DemiBold; + break; + case DWRITE_FONT_WEIGHT_BOLD: + case DWRITE_FONT_WEIGHT_EXTRA_BOLD: + weight = QFont::Bold; + break; + case DWRITE_FONT_WEIGHT_BLACK: + case DWRITE_FONT_WEIGHT_EXTRA_BLACK: + weight = QFont::Black; + break; + } + + QFont::Style style; + switch (font->GetStyle()) { + default: + case DWRITE_FONT_STYLE_NORMAL: + style = QFont::StyleNormal; + break; + case DWRITE_FONT_STYLE_OBLIQUE: + style = QFont::StyleOblique; + break; + case DWRITE_FONT_STYLE_ITALIC: + style = QFont::StyleItalic; + break; + } + + QFont::Stretch stretch; + switch (font->GetStretch()) { + default: + case DWRITE_FONT_STRETCH_UNDEFINED: + case DWRITE_FONT_STRETCH_NORMAL: + stretch = QFont::Unstretched; + break; + case DWRITE_FONT_STRETCH_ULTRA_CONDENSED: + stretch = QFont::UltraCondensed; + break; + case DWRITE_FONT_STRETCH_EXTRA_CONDENSED: + stretch = QFont::ExtraCondensed; + break; + case DWRITE_FONT_STRETCH_CONDENSED: + stretch = QFont::Condensed; + break; + case DWRITE_FONT_STRETCH_SEMI_CONDENSED: + stretch = QFont::SemiCondensed; + break; + case DWRITE_FONT_STRETCH_SEMI_EXPANDED: + stretch = QFont::SemiExpanded; + break; + case DWRITE_FONT_STRETCH_EXPANDED: + stretch = QFont::Expanded; + break; + case DWRITE_FONT_STRETCH_EXTRA_EXPANDED: + stretch = QFont::ExtraExpanded; + break; + case DWRITE_FONT_STRETCH_ULTRA_EXPANDED: + stretch = QFont::UltraExpanded; + break; + } + + const bool fixedPitch = fontFace->IsMonospacedFont(); + + quint32 unicodeRange[4]; + quint32 actualRangeCount; + hr = fontFace->GetUnicodeRanges( + 2, reinterpret_cast(unicodeRange), &actualRangeCount); + if (FAILED(hr) && hr != E_NOT_SUFFICIENT_BUFFER) { // Ignore insufficient buffer; we only need 4 indices + qWarning("Unable to get font unicode range: %s", qPrintable(qt_error_string(hr))); + continue; + } + quint32 codePageRange[2] = { 0, 0 }; + QSupportedWritingSystems writingSystems = + QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + + IDWriteFontFile *fontFile; + hr = fontFace->GetFiles(&fileCount, &fontFile); + if (FAILED(hr)) { + qWarning("Unable to get font file: %s", qPrintable(qt_error_string(hr))); + continue; + } + + FontDescription description = { fontFace->GetIndex(), QUuid::createUuid().toByteArray() }; + m_fonts.insert(fontFile, description); + registerFont(familyName, QString(), foundryName, weight, style, stretch, + true, true, 0, fixedPitch, writingSystems, fontFile); + fontRegistered = true; + } + + // Always populate something to avoid an assert + if (!fontRegistered) { + registerFont(familyName, QString(), QString(), QFont::Normal, QFont::StyleNormal, + QFont::Unstretched, false, false, 0, false, QSupportedWritingSystems(), 0); + } +} + QFontEngine *QWinRTFontDatabase::fontEngine(const QFontDef &fontDef, void *handle) { + if (!handle) // Happens if a font family population failed + return 0; + IDWriteFontFile *fontFile = reinterpret_cast(handle); if (!m_fonts.contains(fontFile)) return QBasicFontDatabase::fontEngine(fontDef, handle); @@ -361,6 +385,9 @@ QFontEngine *QWinRTFontDatabase::fontEngine(const QFontDef &fontDef, void *handl void QWinRTFontDatabase::releaseHandle(void *handle) { + if (!handle) + return; + IDWriteFontFile *fontFile = reinterpret_cast(handle); if (m_fonts.contains(fontFile)) { m_fonts.remove(fontFile); diff --git a/src/plugins/platforms/winrt/qwinrtfontdatabase.h b/src/plugins/platforms/winrt/qwinrtfontdatabase.h index 6f194a10cc7..b318a95502c 100644 --- a/src/plugins/platforms/winrt/qwinrtfontdatabase.h +++ b/src/plugins/platforms/winrt/qwinrtfontdatabase.h @@ -48,6 +48,7 @@ QT_BEGIN_NAMESPACE #ifndef Q_OS_WINPHONE struct IDWriteFontFile; +struct IDWriteFontFamily; struct FontDescription { @@ -64,10 +65,12 @@ public: ~QWinRTFontDatabase(); QFont defaultFont() const Q_DECL_OVERRIDE; void populateFontDatabase() Q_DECL_OVERRIDE; + void populateFamily(const QString &familyName) Q_DECL_OVERRIDE; QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) Q_DECL_OVERRIDE; void releaseHandle(void *handle) Q_DECL_OVERRIDE; private: QHash m_fonts; + QHash m_fontFamilies; #endif // !Q_OS_WINPHONE }; From c761d2721a0c4ade17acf43ca0aec774db2b2357 Mon Sep 17 00:00:00 2001 From: Sergio Ahumada Date: Tue, 25 Mar 2014 21:05:04 +0100 Subject: [PATCH 034/120] Doc: Remove empty and duplicated file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This example already exists under examples/dbus/remotecontrolledcar/doc/src/dbus-remotecontrolledcar.qdoc Change-Id: If50efa704fb29ed111d6d589ea74cd2575131372 Reviewed-by: Sze Howe Koh Reviewed-by: Topi Reiniö --- .../dbus/doc/src/remotecontrolledcar.qdoc | 31 ------------------- 1 file changed, 31 deletions(-) delete mode 100644 examples/dbus/doc/src/remotecontrolledcar.qdoc diff --git a/examples/dbus/doc/src/remotecontrolledcar.qdoc b/examples/dbus/doc/src/remotecontrolledcar.qdoc deleted file mode 100644 index b3b81ebba95..00000000000 --- a/examples/dbus/doc/src/remotecontrolledcar.qdoc +++ /dev/null @@ -1,31 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:FDL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information -** use the contact form at http://qt.digia.com/contact-us. -** -** GNU Free Documentation License Usage -** Alternatively, this file may be used under the terms of the GNU Free -** Documentation License version 1.3 as published by the Free Software -** Foundation and appearing in the file included in the packaging of -** this file. Please review the following information to ensure -** the GNU Free Documentation License version 1.3 requirements -** will be met: http://www.gnu.org/copyleft/fdl.html. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/*! - \example remotecontrolledcar - \title D-Bus Remote Controlled Car Example -*/ From 5ee07bf6919dda0c9a192adedc9fc4512b7bba36 Mon Sep 17 00:00:00 2001 From: Sergio Ahumada Date: Wed, 26 Mar 2014 13:52:09 +0100 Subject: [PATCH 035/120] Mark some tests as XFAIL on QNX Extending this to stock QNX as well since it is not BlackBerry 10 specific. - tst_QNumeric::floatDistance() - tst_QNumeric::floatDistance_double() - tst_QtJson::testNumbers_2() - tst_QtJson::toJsonLargeNumericValues() - tst_QtJson::parseNumbers() Task-number: QTBUG-37066 Change-Id: If0e5d4fbefac5e8a0efed8ef8b1b7655ff6e7766 Reviewed-by: Fabian Bumberger --- tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp | 4 ++-- tests/auto/corelib/json/tst_qtjson.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp b/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp index 79df4b7055b..0b4f0e3c4b4 100644 --- a/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp +++ b/tests/auto/corelib/global/qnumeric/tst_qnumeric.cpp @@ -167,7 +167,7 @@ void tst_QNumeric::floatDistance() QFETCH(float, val1); QFETCH(float, val2); QFETCH(quint32, expectedDistance); -#ifdef Q_OS_BLACKBERRY +#ifdef Q_OS_QNX QEXPECT_FAIL("denormal", "See QTBUG-37094", Continue); #endif QCOMPARE(qFloatDistance(val1, val2), expectedDistance); @@ -214,7 +214,7 @@ void tst_QNumeric::floatDistance_double() QFETCH(double, val1); QFETCH(double, val2); QFETCH(quint64, expectedDistance); -#ifdef Q_OS_BLACKBERRY +#ifdef Q_OS_QNX QEXPECT_FAIL("denormal", "See QTBUG-37094", Continue); #endif QCOMPARE(qFloatDistance(val1, val2), expectedDistance); diff --git a/tests/auto/corelib/json/tst_qtjson.cpp b/tests/auto/corelib/json/tst_qtjson.cpp index 2f75ad631f4..a17fe7561a6 100644 --- a/tests/auto/corelib/json/tst_qtjson.cpp +++ b/tests/auto/corelib/json/tst_qtjson.cpp @@ -347,7 +347,7 @@ void tst_QtJson::testNumbers_2() QJsonDocument jDocument2(QJsonDocument::fromJson(ba)); for (int power = 0; power <= 1075; power++) { floatValues_1[power] = jDocument2.object().value(QString::number(power)).toDouble(); -#ifdef Q_OS_BLACKBERRY +#ifdef Q_OS_QNX if (power >= 970) QEXPECT_FAIL("", "See QTBUG-37066", Abort); #endif @@ -1346,7 +1346,7 @@ void tst_QtJson::toJsonLargeNumericValues() " ]\n" "}\n"; -#ifdef Q_OS_BLACKBERRY +#ifdef Q_OS_QNX QEXPECT_FAIL("", "See QTBUG-37066", Continue); #endif QCOMPARE(json, expected); @@ -1354,7 +1354,7 @@ void tst_QtJson::toJsonLargeNumericValues() QJsonDocument doc; doc.setObject(object); json = doc.toJson(); -#ifdef Q_OS_BLACKBERRY +#ifdef Q_OS_QNX QEXPECT_FAIL("", "See QTBUG-37066", Continue); #endif QCOMPARE(json, expected); @@ -1758,7 +1758,7 @@ void tst_QtJson::parseNumbers() json += numbers[i].str; json += " ]"; QJsonDocument doc = QJsonDocument::fromJson(json); -#ifdef Q_OS_BLACKBERRY +#ifdef Q_OS_QNX if (0 == QString::compare(numbers[i].str, "1.1e-308")) QEXPECT_FAIL("", "See QTBUG-37066", Abort); #endif From eab7efd1ee0475fd331774ccc99ee92c816f588c Mon Sep 17 00:00:00 2001 From: Sergio Ahumada Date: Thu, 20 Mar 2014 17:47:25 +0100 Subject: [PATCH 036/120] Stabilize tst_QProcess::softExitInSlots() This test takes more than 5000ms to finish some times, so waiting for 10000ms should be enough to make it more stable on all platforms. ../tst_qprocess.cpp:1072 :: [gui app] QTestLib: This test case check ("proc.waitedForFinished") failed because the requested timeout (5000 ms) was too short, 6150 ms would have been sufficient this time. Change-Id: I266ad0e65bf3c84e73b7ca6543dc15335dad4c99 Reviewed-by: Fabian Bumberger --- tests/auto/corelib/io/qprocess/tst_qprocess.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp index f5aa2c2412d..b67166272bd 100644 --- a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp +++ b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp @@ -1069,7 +1069,7 @@ void tst_QProcess::softExitInSlots() SoftExitProcess proc(i); proc.writeAfterStart("OLEBOLE", 8); // include the \0 proc.start(appName); - QTRY_VERIFY(proc.waitedForFinished); + QTRY_VERIFY_WITH_TIMEOUT(proc.waitedForFinished, 10000); QCOMPARE(proc.state(), QProcess::NotRunning); } } From ad1c088a2a5c52a5c95075e1e24dfc31aa41b6c1 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 25 Mar 2014 15:27:05 +0100 Subject: [PATCH 037/120] Fix the QOpenGL autotest's offscreen surface handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Be more robust. Change-Id: I0e37612681140530c81cfd0082cca61f0f21958c Reviewed-by: Jørgen Lind --- tests/auto/gui/qopengl/tst_qopengl.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/auto/gui/qopengl/tst_qopengl.cpp b/tests/auto/gui/qopengl/tst_qopengl.cpp index 4018c00a389..f37602ef78e 100644 --- a/tests/auto/gui/qopengl/tst_qopengl.cpp +++ b/tests/auto/gui/qopengl/tst_qopengl.cpp @@ -157,7 +157,22 @@ static QSurface *createSurface(int surfaceClass) window->create(); return window; } else if (surfaceClass == int(QSurface::Offscreen)) { + // Create a window and get the format from that. For example, if an EGL + // implementation provides 565 and 888 configs for PBUFFER_BIT but only + // 888 for WINDOW_BIT, we may end up with a pbuffer surface that is + // incompatible with the context since it could choose the 565 while the + // window and the context uses a config with 888. + static QSurfaceFormat format; + if (format.redBufferSize() == -1) { + QWindow *window = new QWindow; + window->setSurfaceType(QWindow::OpenGLSurface); + window->setGeometry(0, 0, 10, 10); + window->create(); + format = window->format(); + delete window; + } QOffscreenSurface *offscreenSurface = new QOffscreenSurface; + offscreenSurface->setFormat(format); offscreenSurface->create(); return offscreenSurface; } From 75f9c75f0a56d4531b219775e3c79eee3b7a8d6d Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 25 Mar 2014 15:03:51 +0100 Subject: [PATCH 038/120] Enhance QOffscreenSurface docs wrt the format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Prevent nasty surprises on some EGL implementations. Change-Id: I0c6c8a6c631d4dcb979afd81a150491a42aa63f8 Reviewed-by: Jørgen Lind --- src/gui/kernel/qoffscreensurface.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/gui/kernel/qoffscreensurface.cpp b/src/gui/kernel/qoffscreensurface.cpp index ce913a98af8..16259098431 100644 --- a/src/gui/kernel/qoffscreensurface.cpp +++ b/src/gui/kernel/qoffscreensurface.cpp @@ -71,6 +71,14 @@ QT_BEGIN_NAMESPACE How the offscreen surface is implemented depends on the underlying platform, but it will typically use a pixel buffer (pbuffer). If the platform doesn't implement or support offscreen surfaces, QOffscreenSurface will use an invisible QWindow internally. + + \note In order to create an offscreen surface that is guaranteed to be compatible with + a given context and window, make sure to set the format to the context's or the + window's actual format, that is, the QSurfaceFormat returned from + QOpenGLContext::format() or QWindow::format() \e{after the context or window has been + created}. Passing the format returned from QWindow::requestedFormat() to setFormat() + may result in an incompatible offscreen surface since the underlying windowing system + interface may offer a different set of configurations for window and pbuffer surfaces. */ class Q_GUI_EXPORT QOffscreenSurfacePrivate : public QObjectPrivate { From 7aec099ca3cbc3f04562db027dc88f29e7ca28e4 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 25 Mar 2014 17:45:29 +0100 Subject: [PATCH 039/120] OSX: a window can be de-maximized by resizing After that, QWidget::isMaximized() should return false. Task-number: QTBUG-37703 Change-Id: Ic8b0de63ab007066cd277f511dfaa969404ff069 Reviewed-by: Gabriel de Dietrich --- src/plugins/platforms/cocoa/qcocoawindow.h | 1 + src/plugins/platforms/cocoa/qcocoawindow.mm | 8 ++++++++ src/plugins/platforms/cocoa/qnswindowdelegate.mm | 8 ++++++++ 3 files changed, 17 insertions(+) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 34ec142d900..b7a6a14d4a9 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -183,6 +183,7 @@ public: void windowWillMove(); void windowDidMove(); void windowDidResize(); + void windowDidEndLiveResize(); bool windowShouldClose(); bool windowIsPopupType(Qt::WindowType type = Qt::Widget) const; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index f25aea67fab..b27e1b03dbd 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1165,6 +1165,14 @@ void QCocoaWindow::windowDidResize() [m_qtView updateGeometry]; } +void QCocoaWindow::windowDidEndLiveResize() +{ + if (m_synchedWindowState == Qt::WindowMaximized && ![m_nsWindow isZoomed]) { + m_effectivelyMaximized = false; + [m_qtView notifyWindowStateChanged:Qt::WindowNoState]; + } +} + bool QCocoaWindow::windowShouldClose() { bool accepted = false; diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm index c9b3d69381e..d9509098c6b 100644 --- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm +++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm @@ -75,6 +75,14 @@ } } +- (void)windowDidEndLiveResize:(NSNotification *)notification +{ + Q_UNUSED(notification); + if (m_cocoaWindow) { + m_cocoaWindow->windowDidEndLiveResize(); + } +} + - (void)windowWillMove:(NSNotification *)notification { Q_UNUSED(notification); From f16d690a2f8c6ff1830a15794950c8564ae18a29 Mon Sep 17 00:00:00 2001 From: Frederik Gladhorn Date: Wed, 26 Mar 2014 10:14:45 +0100 Subject: [PATCH 040/120] Accessibility Mac: Fix handling of top level widget MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This simplifies how we handle QNSView for accessibility purposes. Instead of trying to half-merge the top level widget (window->accessibleRoot) into the view, just have the view always return it as child. This makes the accessibility implementation for QNSView simpler and makes applications that show a top level widget such as a button possible. (We would return accessibility ignored for the button before). As a side effect finding the active focus and hit-testing should be more reliable as well. Task-number: QTBUG-37794 Change-Id: Ib52037f88da8887a0bdc77204b0f3daddfe7709d Reviewed-by: Morten Johan Sørvig Reviewed-by: Jan Arve Sæther --- .../cocoa/qcocoaaccessibilityelement.mm | 18 +++- .../platforms/cocoa/qnsviewaccessibility.mm | 53 +++--------- .../tst_qaccessibilitymac.cpp | 20 ++++- .../tst_qaccessibilitymac_helpers.h | 3 +- .../tst_qaccessibilitymac_helpers.mm | 83 ++++++++++++++++--- 5 files changed, 121 insertions(+), 56 deletions(-) diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm index bc98d002f06..0b674b8d2f2 100644 --- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm +++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm @@ -417,7 +417,23 @@ } - (id)accessibilityFocusedUIElement { - return NSAccessibilityUnignoredAncestor(self); + QAccessibleInterface *iface = QAccessible::accessibleInterface(axid); + + if (!iface || !iface->isValid()) { + qWarning() << "FocusedUIElement for INVALID"; + return nil; + } + QAccessibleInterface *childInterface = iface->focusChild(); + if (childInterface) { + QAccessible::Id childAxid = QAccessible::uniqueId(childInterface); + // FIXME: parent could be wrong + QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement createElementWithId:childAxid parent:self]; + [accessibleElement autorelease]; + return accessibleElement; + } + + // no focus found + return nil; } @end diff --git a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm index a438950a557..31e3e343b9b 100644 --- a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm +++ b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm @@ -54,6 +54,15 @@ @implementation QNSView (QNSViewAccessibility) +- (id)childAccessibleElement { + if (!m_window->accessibleRoot()) + return nil; + + QAccessible::Id childId = QAccessible::uniqueId(m_window->accessibleRoot()); + QCocoaAccessibleElement *child = [QCocoaAccessibleElement createElementWithId: childId parent: self]; + return [child autorelease]; +} + // The QNSView is a container that the user does not interact directly with: // Remove it from the user-visible accessibility tree. - (BOOL)accessibilityIsIgnored { @@ -61,58 +70,22 @@ } - (id)accessibilityAttributeValue:(NSString *)attribute { - // activate accessibility updates QCocoaIntegration::instance()->accessibility()->setActive(true); - if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) { - if (m_window->accessibleRoot()) - return QCocoaAccessible::macRole(m_window->accessibleRoot()); - return NSAccessibilityUnknownRole; - } else if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) { - return NSAccessibilityRoleDescriptionForUIElement(self); - } else if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { - if (!m_window->accessibleRoot()) - return [super accessibilityAttributeValue:attribute]; - return QCocoaAccessible::unignoredChildren(self, m_window->accessibleRoot()); + if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) { + return NSAccessibilityUnignoredChildrenForOnlyChild([self childAccessibleElement]); } else { return [super accessibilityAttributeValue:attribute]; } } - (id)accessibilityHitTest:(NSPoint)point { - if (!m_window->accessibleRoot()) - return [super accessibilityHitTest:point]; - - QAccessibleInterface *childInterface = m_window->accessibleRoot()->childAt(point.x, qt_mac_flipYCoordinate(point.y)); - // No child found, meaning we hit the NSView - if (!childInterface) { - return [super accessibilityHitTest:point]; - } - - // Hit a child, forward to child accessible interface. - QAccessible::Id childAxid = QAccessible::uniqueId(childInterface); - // FIXME: parent could be wrong - QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement createElementWithId:childAxid parent:self ]; - [accessibleElement autorelease]; - return [accessibleElement accessibilityHitTest:point]; + return [[self childAccessibleElement] accessibilityHitTest: point]; } - (id)accessibilityFocusedUIElement { - if (!m_window->accessibleRoot()) - return [super accessibilityFocusedUIElement]; - - QAccessibleInterface *childInterface = m_window->accessibleRoot()->focusChild(); - if (childInterface) { - QAccessible::Id childAxid = QAccessible::uniqueId(childInterface); - // FIXME: parent could be wrong - QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement createElementWithId:childAxid parent:self]; - [accessibleElement autorelease]; - return accessibleElement; - } - - // should not happen - return nil; + return [[self childAccessibleElement] accessibilityFocusedUIElement]; } @end diff --git a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.cpp b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.cpp index 25dd0d39ddd..25b47ee836b 100644 --- a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.cpp +++ b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.cpp @@ -79,6 +79,7 @@ private slots: void init(); void cleanup(); + void singleWidgetTest(); void lineEditTest(); void hierarchyTest(); private: @@ -101,6 +102,16 @@ void tst_QAccessibilityMac::cleanup() delete m_window; } +void tst_QAccessibilityMac::singleWidgetTest() +{ + if (!macNativeAccessibilityEnabled()) + return; + + delete m_window; + m_window = 0; + + QVERIFY(singleWidget()); +} void tst_QAccessibilityMac::lineEditTest() { @@ -122,14 +133,19 @@ void tst_QAccessibilityMac::hierarchyTest() QWidget *w = new QWidget(m_window); m_window->addWidget(w); - QPushButton *b = new QPushButton(w); + w->setLayout(new QVBoxLayout()); + QPushButton *b = new QPushButton(w); w->layout()->addWidget(b); b->setText("I am a button"); + QPushButton *b2 = new QPushButton(w); + w->layout()->addWidget(b2); + b2->setText("Button 2"); + QVERIFY(QTest::qWaitForWindowExposed(m_window)); QCoreApplication::processEvents(); - QVERIFY(testHierarchy()); + QVERIFY(testHierarchy(w)); } QTEST_MAIN(tst_QAccessibilityMac) diff --git a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.h b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.h index ec5beab125d..635b6383ab1 100644 --- a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.h +++ b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.h @@ -48,4 +48,5 @@ bool macNativeAccessibilityEnabled(); bool trusted(); bool testLineEdit(); -bool testHierarchy(); +bool testHierarchy(QWidget *w); +bool singleWidget(); diff --git a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.mm b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.mm index 8620b7dd2fd..bc89ac858bd 100644 --- a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.mm +++ b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.mm @@ -43,8 +43,10 @@ #define QT_NO_KEYWORDS #include "tst_qaccessibilitymac_helpers.h" -#include -#include +#include +#include +#include +#include #include #import @@ -148,9 +150,41 @@ bool trusted() return p; } ++ (TestAXObject *) getApplicationAXObject +{ + pid_t pid = getpid(); + AXUIElementRef appRef = AXUIElementCreateApplication(pid); + TestAXObject *appObject = [[TestAXObject alloc] initWithAXUIElementRef: appRef]; + return appObject; +} + @end +bool singleWidget() +{ + QLineEdit le; + le.setText("button"); + le.show(); + EXPECT(QTest::qWaitForWindowExposed(&le)); + QCoreApplication::processEvents(); + + TestAXObject *appObject = [TestAXObject getApplicationAXObject]; + EXPECT(appObject); + + NSArray *windows = [appObject windowList]; + EXPECT([windows count] == 1); + + AXUIElementRef windowRef = (AXUIElementRef) [windows objectAtIndex: 0]; + EXPECT(windowRef != nil); + TestAXObject *window = [[TestAXObject alloc] initWithAXUIElementRef: windowRef]; + + AXUIElementRef lineEdit = [window findDirectChildByRole: kAXTextFieldRole]; + EXPECT(lineEdit != nil); + + return true; +} + bool testLineEdit() { // not sure if this is needed. on my machine the calls succeed. @@ -159,10 +193,8 @@ bool testLineEdit() // AXError e = AXMakeProcessTrusted((CFStringRef) path); // NSLog(@"error: %i", e); - pid_t pid = getpid(); - AXUIElementRef app = AXUIElementCreateApplication(pid); - EXPECT(app != nil); - TestAXObject *appObject = [[TestAXObject alloc] initWithAXUIElementRef: app]; + TestAXObject *appObject = [TestAXObject getApplicationAXObject]; + EXPECT(appObject); NSArray *windowList = [appObject windowList]; // one window @@ -184,12 +216,10 @@ bool testLineEdit() return true; } -bool testHierarchy() +bool testHierarchy(QWidget *w) { - pid_t pid = getpid(); - AXUIElementRef app = AXUIElementCreateApplication(pid); - EXPECT(app != nil); - TestAXObject *appObject = [[TestAXObject alloc] initWithAXUIElementRef: app]; + TestAXObject *appObject = [TestAXObject getApplicationAXObject]; + EXPECT(appObject); NSArray *windowList = [appObject windowList]; // one window @@ -207,7 +237,36 @@ bool testHierarchy() TestAXObject *parentObject = [[TestAXObject alloc] initWithAXUIElementRef: [buttonObject parent]]; // check that the parent is a window - EXPECT([[parentObject role] isEqualToString: (NSString *)kAXWindowRole]); + EXPECT([[parentObject role] isEqualToString: NSAccessibilityWindowRole]); + + // test the focus + // child 0 is the layout, then button1 and 2 + QPushButton *button1 = qobject_cast(w->children().at(1)); + EXPECT(button1); + QPushButton *button2 = qobject_cast(w->children().at(2)); + EXPECT(button2); + button2->setFocus(); + + AXUIElementRef systemWideElement = AXUIElementCreateSystemWide(); + AXUIElementRef focussedElement = NULL; + AXError error = AXUIElementCopyAttributeValue(systemWideElement, + (CFStringRef)NSAccessibilityFocusedUIElementAttribute, (CFTypeRef*)&focussedElement); + EXPECT(!error); + EXPECT(focussedElement); + TestAXObject *focusButton2 = [[TestAXObject alloc] initWithAXUIElementRef: focussedElement]; + + EXPECT([[focusButton2 role] isEqualToString: NSAccessibilityButtonRole]); + EXPECT([[focusButton2 description] isEqualToString: @"Button 2"]); + + + button1->setFocus(); + error = AXUIElementCopyAttributeValue(systemWideElement, + (CFStringRef)NSAccessibilityFocusedUIElementAttribute, (CFTypeRef*)&focussedElement); + EXPECT(!error); + EXPECT(focussedElement); + TestAXObject *focusButton1 = [[TestAXObject alloc] initWithAXUIElementRef: focussedElement]; + EXPECT([[focusButton1 role] isEqualToString: NSAccessibilityButtonRole]); + EXPECT([[focusButton1 description] isEqualToString: @"I am a button"]); return true; } From 38fc11b74bfb0aca467c1f240af30d4dfbfed642 Mon Sep 17 00:00:00 2001 From: Fabian Bumberger Date: Tue, 25 Mar 2014 14:30:18 +0100 Subject: [PATCH 041/120] QNX: Retrieve name of the display Task-number: QTBUG-34545 Change-Id: I51d36c7352351b0770a1a076bdcc738677d7fcb6 Reviewed-by: Bernd Weimer Reviewed-by: Sergio Ahumada --- src/plugins/platforms/qnx/qqnxscreen.cpp | 5 +++++ src/plugins/platforms/qnx/qqnxscreen.h | 3 +++ 2 files changed, 8 insertions(+) diff --git a/src/plugins/platforms/qnx/qqnxscreen.cpp b/src/plugins/platforms/qnx/qqnxscreen.cpp index a6c69164c73..2707f14db24 100644 --- a/src/plugins/platforms/qnx/qqnxscreen.cpp +++ b/src/plugins/platforms/qnx/qqnxscreen.cpp @@ -177,6 +177,11 @@ QQnxScreen::QQnxScreen(screen_context_t screenContext, screen_display_t display, m_currentGeometry = m_initialGeometry = QRect(0, 0, val[0], val[1]); + char name[100]; + Q_SCREEN_CHECKERROR(screen_get_display_property_cv(m_display, SCREEN_PROPERTY_ID_STRING, 100, + name), "Failed to query display name"); + m_name = QString::fromUtf8(name); + // Cache size of this display in millimeters. We have to take care of the orientation. // libscreen always reports the physical size dimensions as width and height in the // native orientation. Contrary to this, QPlatformScreen::physicalSize() expects the diff --git a/src/plugins/platforms/qnx/qqnxscreen.h b/src/plugins/platforms/qnx/qqnxscreen.h index d39a210d4b3..a0b760135f1 100644 --- a/src/plugins/platforms/qnx/qqnxscreen.h +++ b/src/plugins/platforms/qnx/qqnxscreen.h @@ -77,6 +77,8 @@ public: int rotation() const { return m_currentRotation; } + QString name() const { return m_name; } + int nativeFormat() const { return (depth() == 32) ? SCREEN_FORMAT_RGBA8888 : SCREEN_FORMAT_RGB565; } screen_display_t nativeDisplay() const { return m_display; } screen_context_t nativeContext() const { return m_screenContext; } @@ -132,6 +134,7 @@ private: int m_initialRotation; int m_currentRotation; int m_keyboardHeight; + QString m_name; QSize m_initialPhysicalSize; QSize m_currentPhysicalSize; Qt::ScreenOrientation m_nativeOrientation; From 3f4277c264db3ef19e7783c3daf1959ff662d04a Mon Sep 17 00:00:00 2001 From: Fabian Bumberger Date: Tue, 25 Mar 2014 12:12:11 +0100 Subject: [PATCH 042/120] QNX: Fix geometry changed event for non FS windows For non full screen windows the geometry change event was not sent. Change-Id: I982621d87fe248bbe13640dd3e17b31fb9f30120 Reviewed-by: Bernd Weimer Reviewed-by: Sergio Ahumada --- src/plugins/platforms/qnx/qqnxwindow.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp index f11a009bca6..42318729b14 100644 --- a/src/plugins/platforms/qnx/qqnxwindow.cpp +++ b/src/plugins/platforms/qnx/qqnxwindow.cpp @@ -709,12 +709,12 @@ void QQnxWindow::initWindow() if (window()->parent() && window()->parent()->handle()) setParent(window()->parent()->handle()); - if (shouldMakeFullScreen()) { + if (shouldMakeFullScreen()) setGeometryHelper(screen()->geometry()); - QWindowSystemInterface::handleGeometryChange(window(), screen()->geometry()); - } else { + else setGeometryHelper(window()->geometry()); - } + + QWindowSystemInterface::handleGeometryChange(window(), screen()->geometry()); } void QQnxWindow::createWindowGroup() From 7ca958eb61eec6c01d4fcc6720941ba37bd2924d Mon Sep 17 00:00:00 2001 From: Fabian Bumberger Date: Tue, 18 Mar 2014 17:18:04 +0100 Subject: [PATCH 043/120] QNX: Fix QWindow autotest On QNX a actual platform window is not created unless the window is explicitly postet (raster) or a swapBuffers (opengl) is executed. Change-Id: Ia06b97ea1a477d59e78d74d895c5d6ba6dd86edf Reviewed-by: Sergio Ahumada --- tests/auto/gui/kernel/qwindow/tst_qwindow.cpp | 54 ++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp index da142c80a64..eefa85a745d 100644 --- a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp +++ b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp @@ -49,6 +49,10 @@ #include #include +#if defined(Q_OS_QNX) +#include +#endif + // For QSignalSpy slot connections. Q_DECLARE_METATYPE(Qt::ScreenOrientation) Q_DECLARE_METATYPE(QWindow::Visibility) @@ -122,6 +126,9 @@ public: { reset(); setFlags(flags); +#if defined(Q_OS_QNX) + setSurfaceType(QSurface::OpenGLSurface); +#endif } void reset() @@ -187,7 +194,12 @@ void tst_QWindow::resizeEventAfterResize() // Make sure we get a resizeEvent after calling resize window.resize(400, 100); +#if defined(Q_OS_BLACKBERRY) // "window" is the "root" window and will always be shown fullscreen + // so we only expect one resize event + QTRY_COMPARE(window.received(QEvent::Resize), 1); +#else QTRY_COMPARE(window.received(QEvent::Resize), 2); +#endif } void tst_QWindow::positioning_data() @@ -244,13 +256,24 @@ void tst_QWindow::positioning() window.setWindowState(Qt::WindowFullScreen); QCoreApplication::processEvents(); +#if defined(Q_OS_BLACKBERRY) // "window" is the "root" window and will always be shown fullscreen + // so we only expect one resize event + Q_UNUSED(resizecount); + QTRY_COMPARE(window.received(QEvent::Resize), 1); +#else QTRY_COMPARE(window.received(QEvent::Resize), 2); +#endif QTest::qWait(2000); window.setWindowState(Qt::WindowNoState); QCoreApplication::processEvents(); +#if defined(Q_OS_BLACKBERRY) // "window" is the "root" window and will always be shown fullscreen + // so we only expect one resize event + QTRY_COMPARE(window.received(QEvent::Resize), 1); +#else QTRY_COMPARE(window.received(QEvent::Resize), resizecount); +#endif QTRY_COMPARE(originalPos, window.position()); QTRY_COMPARE(originalFramePos, window.framePosition()); @@ -309,6 +332,13 @@ void tst_QWindow::isActive() QCoreApplication::processEvents(); QTRY_VERIFY(window.isExposed()); +#if defined(Q_OS_QNX) // We either need to create a eglSurface or a create a backing store + // and then post the window in order for screen to show the window + QOpenGLContext context; + context.create(); + context.makeCurrent(&window); + context.swapBuffers(&window); +#endif QTRY_COMPARE(window.received(QEvent::Resize), 1); QTRY_VERIFY(QGuiApplication::focusWindow() == &window); QVERIFY(window.isActive()); @@ -511,7 +541,7 @@ void tst_QWindow::testInputEvents() // Now with null pointer as window. local param should not be utilized: // handleMouseEvent() with tlw == 0 means the event is in global coords only. window.mousePressButton = window.mouseReleaseButton = 0; - QPointF nonWindowGlobal(500, 500); // not inside the window + QPointF nonWindowGlobal(2000, 500); // not inside the window QWindowSystemInterface::handleMouseEvent(0, nonWindowGlobal, nonWindowGlobal, Qt::LeftButton); QWindowSystemInterface::handleMouseEvent(0, nonWindowGlobal, nonWindowGlobal, Qt::NoButton); QCoreApplication::processEvents(); @@ -913,10 +943,21 @@ void tst_QWindow::activateAndClose() { for (int i = 0; i < 10; ++i) { QWindow window; +#if defined(Q_OS_QNX) + window.setSurfaceType(QSurface::OpenGLSurface); +#endif // qWaitForWindowActive will block for the duration of // of the timeout if the window is at 0,0 window.setGeometry(QGuiApplication::primaryScreen()->availableGeometry().adjusted(1, 1, -1, -1)); window.showNormal(); +#if defined(Q_OS_QNX) // We either need to create a eglSurface or a create a backing store + // and then post the window in order for screen to show the window + QTest::qWaitForWindowExposed(&window); + QOpenGLContext context; + context.create(); + context.makeCurrent(&window); + context.swapBuffers(&window); +#endif window.requestActivate(); QVERIFY(QTest::qWaitForWindowActive(&window)); QCOMPARE(qGuiApp->focusWindow(), &window); @@ -1252,15 +1293,26 @@ void tst_QWindow::initialSize() Window w; w.setWidth(200); w.show(); +#if defined(Q_OS_BLACKBERRY) // "window" is the "root" window and will always be shown fullscreen + // so we only expect one resize event + QTRY_COMPARE(w.width(), qGuiApp->primaryScreen()->availableGeometry().width()); +#else QTRY_COMPARE(w.width(), 200); +#endif QTRY_VERIFY(w.height() > 0); } { Window w; w.resize(200, 42); w.show(); +#if defined(Q_OS_BLACKBERRY) // "window" is the "root" window and will always be shown fullscreen + // so we only expect one resize event + QTRY_COMPARE(w.width(), qGuiApp->primaryScreen()->availableGeometry().width()); + QTRY_COMPARE(w.height(), qGuiApp->primaryScreen()->availableGeometry().height()); +#else QTRY_COMPARE(w.width(), 200); QTRY_COMPARE(w.height(), 42); +#endif } } From 74cade1ee42dbe15d3242b08d5880e08e6294e2e Mon Sep 17 00:00:00 2001 From: Fabian Bumberger Date: Thu, 9 Jan 2014 01:57:41 +0100 Subject: [PATCH 044/120] Fix application font removal when using FontConfig This patch fixes an issue when a font that was added with QFontDatabase::addApplicationFont can not be removed any more. The reason for that is that QFontconfigDatabase::addApplicationFont adds the font to the FontConfig application set from where it cannot be removed any more and is picked up every time the font database is repopulated (e.g. after a call to QFontDatabase::removeApplicationFont). This also fixes the QFontDatabase autotest which unfortunately does not fail on linux, because it tries to add "FreeMono" (which in most cases is already there as a system font). So this patch removes FreeMono and adds LED_REAL as test font. Change-Id: I70fc823075923aa426da1eb3e052affcc416e399 Reviewed-by: Konstantin Ritt --- .../fontconfig/qfontconfigdatabase.cpp | 220 +++++++++--------- .../auto/gui/text/qfontdatabase/FreeMono.ttf | Bin 267400 -> 0 bytes .../auto/gui/text/qfontdatabase/LED_REAL.TTF | Bin 0 -> 4708 bytes .../text/qfontdatabase/LED_REAL_readme.txt | 34 +++ .../text/qfontdatabase/tst_qfontdatabase.cpp | 2 +- 5 files changed, 147 insertions(+), 109 deletions(-) delete mode 100644 tests/auto/gui/text/qfontdatabase/FreeMono.ttf create mode 100644 tests/auto/gui/text/qfontdatabase/LED_REAL.TTF create mode 100644 tests/auto/gui/text/qfontdatabase/LED_REAL_readme.txt diff --git a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp index 1a31400ea57..17717dd53cb 100644 --- a/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp +++ b/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp @@ -331,10 +331,8 @@ static const char *getFcFamilyForStyleHint(const QFont::StyleHint style) return stylehint; } -void QFontconfigDatabase::populateFontDatabase() +static void populateFromPattern(FcPattern *pattern) { - FcFontSet *fonts; - QString familyName; FcChar8 *value = 0; int weight_value; @@ -348,6 +346,110 @@ void QFontconfigDatabase::populateFontDatabase() FcBool scalable; FcBool antialias; + if (FcPatternGetString(pattern, FC_FAMILY, 0, &value) != FcResultMatch) + return; + + familyName = QString::fromUtf8((const char *)value); + + slant_value = FC_SLANT_ROMAN; + weight_value = FC_WEIGHT_REGULAR; + spacing_value = FC_PROPORTIONAL; + file_value = 0; + indexValue = 0; + scalable = FcTrue; + + + if (FcPatternGetInteger(pattern, FC_SLANT, 0, &slant_value) != FcResultMatch) + slant_value = FC_SLANT_ROMAN; + if (FcPatternGetInteger(pattern, FC_WEIGHT, 0, &weight_value) != FcResultMatch) + weight_value = FC_WEIGHT_REGULAR; + if (FcPatternGetInteger(pattern, FC_WIDTH, 0, &width_value) != FcResultMatch) + width_value = FC_WIDTH_NORMAL; + if (FcPatternGetInteger(pattern, FC_SPACING, 0, &spacing_value) != FcResultMatch) + spacing_value = FC_PROPORTIONAL; + if (FcPatternGetString(pattern, FC_FILE, 0, &file_value) != FcResultMatch) + file_value = 0; + if (FcPatternGetInteger(pattern, FC_INDEX, 0, &indexValue) != FcResultMatch) + indexValue = 0; + if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &scalable) != FcResultMatch) + scalable = FcTrue; + if (FcPatternGetString(pattern, FC_FOUNDRY, 0, &foundry_value) != FcResultMatch) + foundry_value = 0; + if (FcPatternGetString(pattern, FC_STYLE, 0, &style_value) != FcResultMatch) + style_value = 0; + if (FcPatternGetBool(pattern,FC_ANTIALIAS,0,&antialias) != FcResultMatch) + antialias = true; + + QSupportedWritingSystems writingSystems; + FcLangSet *langset = 0; + FcResult res = FcPatternGetLangSet(pattern, FC_LANG, 0, &langset); + if (res == FcResultMatch) { + bool hasLang = false; + for (int j = 1; j < QFontDatabase::WritingSystemsCount; ++j) { + const FcChar8 *lang = (const FcChar8*) languageForWritingSystem[j]; + if (lang) { + FcLangResult langRes = FcLangSetHasLang(langset, lang); + if (langRes != FcLangDifferentLang) { + writingSystems.setSupported(QFontDatabase::WritingSystem(j)); + hasLang = true; + } + } + } + if (!hasLang) + // none of our known languages, add it to the other set + writingSystems.setSupported(QFontDatabase::Other); + } else { + // we set Other to supported for symbol fonts. It makes no + // sense to merge these with other ones, as they are + // special in a way. + writingSystems.setSupported(QFontDatabase::Other); + } + +#if FC_VERSION >= 20297 + for (int j = 1; j < QFontDatabase::WritingSystemsCount; ++j) { + if (writingSystems.supported(QFontDatabase::WritingSystem(j)) + && requiresOpenType(j) && openType[j]) { + FcChar8 *cap; + res = FcPatternGetString (pattern, FC_CAPABILITY, 0, &cap); + if (res != FcResultMatch || !strstr((const char *)cap, openType[j])) + writingSystems.setSupported(QFontDatabase::WritingSystem(j),false); + } + } +#endif + + FontFile *fontFile = new FontFile; + fontFile->fileName = QLatin1String((const char *)file_value); + fontFile->indexValue = indexValue; + + QFont::Style style = (slant_value == FC_SLANT_ITALIC) + ? QFont::StyleItalic + : ((slant_value == FC_SLANT_OBLIQUE) + ? QFont::StyleOblique + : QFont::StyleNormal); + // Note: weight should really be an int but registerFont incorrectly uses an enum + QFont::Weight weight = QFont::Weight(weightFromFcWeight(weight_value)); + + double pixel_size = 0; + if (!scalable) + FcPatternGetDouble (pattern, FC_PIXEL_SIZE, 0, &pixel_size); + + bool fixedPitch = spacing_value >= FC_MONO; + // Note: stretch should really be an int but registerFont incorrectly uses an enum + QFont::Stretch stretch = QFont::Stretch(stretchFromFcWidth(width_value)); + QString styleName = style_value ? QString::fromUtf8((const char *) style_value) : QString(); + 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)); + +} + +void QFontconfigDatabase::populateFontDatabase() +{ + FcInitReinitialize(); + FcFontSet *fonts; + { FcObjectSet *os = FcObjectSetCreate(); FcPattern *pattern = FcPatternCreate(); @@ -371,103 +473,8 @@ void QFontconfigDatabase::populateFontDatabase() FcPatternDestroy(pattern); } - for (int i = 0; i < fonts->nfont; i++) { - if (FcPatternGetString(fonts->fonts[i], FC_FAMILY, 0, &value) != FcResultMatch) - continue; - // capitalize(value); - familyName = QString::fromUtf8((const char *)value); - slant_value = FC_SLANT_ROMAN; - weight_value = FC_WEIGHT_REGULAR; - spacing_value = FC_PROPORTIONAL; - file_value = 0; - indexValue = 0; - scalable = FcTrue; - - - if (FcPatternGetInteger (fonts->fonts[i], FC_SLANT, 0, &slant_value) != FcResultMatch) - slant_value = FC_SLANT_ROMAN; - if (FcPatternGetInteger (fonts->fonts[i], FC_WEIGHT, 0, &weight_value) != FcResultMatch) - weight_value = FC_WEIGHT_REGULAR; - if (FcPatternGetInteger (fonts->fonts[i], FC_WIDTH, 0, &width_value) != FcResultMatch) - width_value = FC_WIDTH_NORMAL; - if (FcPatternGetInteger (fonts->fonts[i], FC_SPACING, 0, &spacing_value) != FcResultMatch) - spacing_value = FC_PROPORTIONAL; - if (FcPatternGetString (fonts->fonts[i], FC_FILE, 0, &file_value) != FcResultMatch) - file_value = 0; - if (FcPatternGetInteger (fonts->fonts[i], FC_INDEX, 0, &indexValue) != FcResultMatch) - indexValue = 0; - if (FcPatternGetBool(fonts->fonts[i], FC_SCALABLE, 0, &scalable) != FcResultMatch) - scalable = FcTrue; - if (FcPatternGetString(fonts->fonts[i], FC_FOUNDRY, 0, &foundry_value) != FcResultMatch) - foundry_value = 0; - if (FcPatternGetString(fonts->fonts[i], FC_STYLE, 0, &style_value) != FcResultMatch) - style_value = 0; - if(FcPatternGetBool(fonts->fonts[i],FC_ANTIALIAS,0,&antialias) != FcResultMatch) - antialias = true; - - QSupportedWritingSystems writingSystems; - FcLangSet *langset = 0; - FcResult res = FcPatternGetLangSet(fonts->fonts[i], FC_LANG, 0, &langset); - if (res == FcResultMatch) { - bool hasLang = false; - for (int j = 1; j < QFontDatabase::WritingSystemsCount; ++j) { - const FcChar8 *lang = (const FcChar8*) languageForWritingSystem[j]; - if (lang) { - FcLangResult langRes = FcLangSetHasLang(langset, lang); - if (langRes != FcLangDifferentLang) { - writingSystems.setSupported(QFontDatabase::WritingSystem(j)); - hasLang = true; - } - } - } - if (!hasLang) - // none of our known languages, add it to the other set - writingSystems.setSupported(QFontDatabase::Other); - } else { - // we set Other to supported for symbol fonts. It makes no - // sense to merge these with other ones, as they are - // special in a way. - writingSystems.setSupported(QFontDatabase::Other); - } - -#if FC_VERSION >= 20297 - for (int j = 1; j < QFontDatabase::WritingSystemsCount; ++j) { - if (writingSystems.supported(QFontDatabase::WritingSystem(j)) - && requiresOpenType(j) && openType[j]) { - FcChar8 *cap; - res = FcPatternGetString (fonts->fonts[i], FC_CAPABILITY, 0, &cap); - if (res != FcResultMatch || !strstr((const char *)cap, openType[j])) - writingSystems.setSupported(QFontDatabase::WritingSystem(j),false); - } - } -#endif - - FontFile *fontFile = new FontFile; - fontFile->fileName = QLatin1String((const char *)file_value); - fontFile->indexValue = indexValue; - - QFont::Style style = (slant_value == FC_SLANT_ITALIC) - ? QFont::StyleItalic - : ((slant_value == FC_SLANT_OBLIQUE) - ? QFont::StyleOblique - : QFont::StyleNormal); - // Note: weight should really be an int but registerFont incorrectly uses an enum - QFont::Weight weight = QFont::Weight(weightFromFcWeight(weight_value)); - - double pixel_size = 0; - if (!scalable) - FcPatternGetDouble (fonts->fonts[i], FC_PIXEL_SIZE, 0, &pixel_size); - - bool fixedPitch = spacing_value >= FC_MONO; - // Note: stretch should really be an int but registerFont incorrectly uses an enum - QFont::Stretch stretch = QFont::Stretch(stretchFromFcWidth(width_value)); - QString styleName = style_value ? QString::fromUtf8((const char *) style_value) : QString(); - 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(fonts->fonts[i], FC_FAMILY, k, &value) == FcResultMatch; ++k) - QPlatformFontDatabase::registerAliasToFontFamily(familyName, QString::fromUtf8((const char *)value)); - } + for (int i = 0; i < fonts->nfont; i++) + populateFromPattern(fonts->fonts[i]); FcFontSetDestroy (fonts); @@ -802,6 +809,7 @@ static FcPattern *queryFont(const FcChar8 *file, const QByteArray &data, int id, QStringList QFontconfigDatabase::addApplicationFont(const QByteArray &fontData, const QString &fileName) { QStringList families; + FcFontSet *set = FcConfigGetFonts(0, FcSetApplication); if (!set) { FcConfigAppFontAddFile(0, (const FcChar8 *)":/non-existent"); @@ -814,28 +822,24 @@ QStringList QFontconfigDatabase::addApplicationFont(const QByteArray &fontData, FcBlanks *blanks = FcConfigGetBlanks(0); int count = 0; - FcPattern *pattern = 0; + FcPattern *pattern; do { pattern = queryFont((const FcChar8 *)QFile::encodeName(fileName).constData(), fontData, id, blanks, &count); if (!pattern) return families; - FcPatternDel(pattern, FC_FILE); - QByteArray cs = fileName.toUtf8(); - FcPatternAddString(pattern, FC_FILE, (const FcChar8 *) cs.constData()); - FcChar8 *fam = 0; if (FcPatternGetString(pattern, FC_FAMILY, 0, &fam) == FcResultMatch) { QString family = QString::fromUtf8(reinterpret_cast(fam)); families << family; } + populateFromPattern(pattern); - if (!FcFontSetAdd(set, pattern)) - return families; + FcFontSetAdd(set, pattern); ++id; - } while (pattern && id < count); + } while (id < count); return families; } diff --git a/tests/auto/gui/text/qfontdatabase/FreeMono.ttf b/tests/auto/gui/text/qfontdatabase/FreeMono.ttf deleted file mode 100644 index d7ce52ddc7c0de0dc51e5aec29609b7913c2e0d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 267400 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

r$IgOl7&LC%!v&av~+2kDZ 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 diff --git a/tests/auto/gui/text/qfontdatabase/LED_REAL.TTF b/tests/auto/gui/text/qfontdatabase/LED_REAL.TTF new file mode 100644 index 0000000000000000000000000000000000000000..f87ea95e0e80c72b0863b39fb6e308a169ba7763 GIT binary patch literal 4708 zcmeHKU2GIp6h8OPOm_>V-Lj>%fZA>gG(w=z0wRr~Na9a{u~slKMwaf<7W$XA(5;}Y zgrp{7(!@qEJZK^>8YIND(P$qG52T4P)Pxvf`k=8!6JG>NLLz1T&b@cKv)#6W&(3CN z&OPVc^Yfi^@7y6lM2o1OEUMi5;)YGfcb^yl=K}tF8d{?rmSv5AzC$EVHMaB~njZMB zmq_*#Ek4y0kH!w}diDlUt___nO<)91TAyKDgK>FNYj>g~xcohg4`6(urM)3~;`_b^ zqP!d)w?-2k)GZPie~EEPTeLO)_8-q(#P~XV#5>x%x)B$yr8{sdC$i3pL2{Tg&y_tl zzw1yp3reWZsZCxYa%#y{nvytwq5}8`s|i`Fu(T&>1EEBgqRfE@YrTVrBN z`CwgKE`HG6>chg*b-f_45NN`_BS%$Lh%ujFJe*n=l9(K&VIu+h0F4vpIb-s+7__hP zn&ldd0W|yC-EtD*JS0rGa$LoSEQjR~ORCTn!vK0nMMnuSDC?QO6`sc6D8YUp6XzkD(lReTSs^QPi=LPnFudkvRC}()omC_YWx0LSDua}XX#^2X1_llGDn`v)0F50_B zCo@*SrS_O6W2BehVaGi$8# z0G7N)k&^CgovF@)Gw{V^GS%75>C0d{8&z+2Vf6j$XKp0*Y~FvoohIecS4R_#Upu9z zJ0(-wUq`?8{dCmAHSk;g@7=2R)4A7!?ib$0y!_O@@9S!=UgjR??|}QO-s~MY(^6`6 zdNHMTb$=yU&+CS{G`y(CpypqvdPml?XWoWs9jjyVcT~E4&+F{HUe_zF{xfg$RJVBV zbhS>@yGuvmotY%R-LZ~1ZvQ&cx%=Xt=S{_SGxJT`i}<|cd-t$qsouo;WJvG)T=DyB zc{R649YP>YyUZ!w&%-?ZJ!PE*J7!h;g^CtRqS-hL;hMl6J%+PH5T~bf8WzlNg5^L0 zSn$4rXAD`#ls@ZVj2~ZYA@jE|m+i8JF*SRFN3hOwyz4Z5NF($uU8i5^CM89#SRpDz zwRlSG6|aiJqDPz*?}~F`L|hTq#Dw@w+>}`|Ulz+!xlZnsd*nfROb*C%@^kr({88SJ zcdSL$GHbQ9!`g4PS$)>~)~D9j)>Z2lYsz-)Lc84FZr9n(_8ayY`=Wi>9=9j$TTYJi zptIJgadtZ|JIzjy)8`C0XPu9oVdpZ=m_#q(7s6Lqz!cDnKY+UO_tq7q#oTPM($M&> z5ZQ*7_~M!}w1uV55=zuzn;;Y%_K57%IAY)okNaPrr_qo3f zZP8=&m7)2I@{FM!dVo$CIt$-}d_HG80eXhA>pP>dcx$xt2-VUqdK%N}D2|WK7Wx2m zJ#~VPfzyg-CmjK=oetr?8{=;Lnjq`Jct4&k)Id#p;yuQcXNaGTbQEHk*cb2YYHn{U z*|@&4lJ-H;NnO+oqiry<5#OtoRGBi7ibhj2X6``+Xv|~3F5Y;wCEBSnUC83j_Kx1p z=EkOO+KB)=s29ODBb6rPT|%FzfVa^$dKA<_NEbi_iIvckfS?7>x*027Y7_?q48$?q PW6+#+=~X?8nLhjnh|sa8 literal 0 HcmV?d00001 diff --git a/tests/auto/gui/text/qfontdatabase/LED_REAL_readme.txt b/tests/auto/gui/text/qfontdatabase/LED_REAL_readme.txt new file mode 100644 index 00000000000..06a5b403136 --- /dev/null +++ b/tests/auto/gui/text/qfontdatabase/LED_REAL_readme.txt @@ -0,0 +1,34 @@ +Font: LED Real (led_real.ttf) +Created By: Matthew Welch +E-Mail: daffy-duck@worldnet.att.net +Web Address: http://home.att.net/~daffy-duck + (PGP public key available here) + +LED Real, like all of my fonts, is free. You can use it for most +personal or business uses you'd like, and I ask for no money. I +would, however, like to hear from you. If you use my fonts for +something please send me a postcard or e-mail letting me know how +you used it. Send me a copy if you can or let me know where I can +find your work. + +You may use this font for graphical or printed work, but you may not +sell it or include it in a collection of fonts (on CD or otherwise) +being sold. You can redistribute this font as long as you charge +nothing to receive it. If you redistribute it include this text file +with it as is (without modifications). + +If you use this font for commercial purposes please credit me in +at least some little way. + +About the font: + +Unlike most LED/LCD style fonts mine could be recreated with an +actual LED. I created this font working from memories of the good +old Speak and Spell display. Since I don't have an actual Speak +and Spell to work from I had to just do as well as I could in its +spirit. Be warned that some characters look just like others. The +( and the <, for instance. Also C and [. Most of these will be +pretty clear in context. To see all the sections of the LED "lit +up" at once use character 127 (hold down alt and type 0127 on the +numeric keypad). This font is, of course, monospaced. + diff --git a/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp b/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp index fa5c81a2f07..28db0ba2911 100644 --- a/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp +++ b/tests/auto/gui/text/qfontdatabase/tst_qfontdatabase.cpp @@ -83,7 +83,7 @@ private: }; tst_QFontDatabase::tst_QFontDatabase() - : m_testFont(QFINDTESTDATA("FreeMono.ttf")) + : m_testFont(QFINDTESTDATA("LED_REAL.TTF")) { } From ad22303bff0dac7accc748e284bd1ffbf6b24cb3 Mon Sep 17 00:00:00 2001 From: Mark Brand Date: Wed, 26 Mar 2014 21:14:19 +0100 Subject: [PATCH 045/120] update bundled sqlite to 3.8.4.2 The "Fixed CE build of sqlite3" patch is preserved in this change. (ea70ec8711af45128d63634a01dfc4c1a51ac331) Change-Id: I7da6504a1d1bee7926a122d7c4ec3a2bf4035d03 Reviewed-by: Friedemann Kleint --- src/3rdparty/sqlite/sqlite3.c | 7 ++++--- src/3rdparty/sqlite/sqlite3.h | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/3rdparty/sqlite/sqlite3.c b/src/3rdparty/sqlite/sqlite3.c index a2e37dd48ee..f8a10149bc7 100644 --- a/src/3rdparty/sqlite/sqlite3.c +++ b/src/3rdparty/sqlite/sqlite3.c @@ -1,6 +1,6 @@ /****************************************************************************** ** This file is an amalgamation of many separate C source files from SQLite -** version 3.8.4.1. By combining all the individual C code files into this +** version 3.8.4.2. By combining all the individual C code files into this ** single large file, the entire code can be compiled as a single translation ** unit. This allows many compilers to do optimizations that would not be ** possible if the files were compiled separately. Performance improvements @@ -222,9 +222,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.8.4.1" +#define SQLITE_VERSION "3.8.4.2" #define SQLITE_VERSION_NUMBER 3008004 -#define SQLITE_SOURCE_ID "2014-03-11 15:27:36 018d317b1257ce68a92908b05c9c7cf1494050d0" +#define SQLITE_SOURCE_ID "2014-03-26 18:51:19 02ea166372bdb2ef9d8dfbb05e78a97609673a8e" /* ** CAPI3REF: Run-Time Library Version Numbers @@ -64786,6 +64786,7 @@ SQLITE_PRIVATE int sqlite3VdbeRecordCompare( }else{ idx1 = getVarint32(aKey1, szHdr1); d1 = szHdr1; + if( d1>(unsigned)nKey1 ) return 1; /* Corruption */ i = 0; } diff --git a/src/3rdparty/sqlite/sqlite3.h b/src/3rdparty/sqlite/sqlite3.h index 1f19ada4cbf..d0d676afaef 100644 --- a/src/3rdparty/sqlite/sqlite3.h +++ b/src/3rdparty/sqlite/sqlite3.h @@ -107,9 +107,9 @@ extern "C" { ** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite_version()] and [sqlite_source_id()]. */ -#define SQLITE_VERSION "3.8.4.1" +#define SQLITE_VERSION "3.8.4.2" #define SQLITE_VERSION_NUMBER 3008004 -#define SQLITE_SOURCE_ID "2014-03-11 15:27:36 018d317b1257ce68a92908b05c9c7cf1494050d0" +#define SQLITE_SOURCE_ID "2014-03-26 18:51:19 02ea166372bdb2ef9d8dfbb05e78a97609673a8e" /* ** CAPI3REF: Run-Time Library Version Numbers From ddf2e2367ccf651fc25f02a3e7975a8b57a4bc98 Mon Sep 17 00:00:00 2001 From: Topi Reinio Date: Fri, 21 Mar 2014 10:02:07 +0100 Subject: [PATCH 046/120] Doc: Move IPC example documentation Examples under examples/ipc were not part of any module documentation. This change adds the above folder to Qt Core documentation, and moves the corresponding files so that the example documentation is built correctly. Change-Id: If1f34ce7ef04a02df8a87f820bb2e68ffa723dd4 Reviewed-by: Friedemann Kleint Reviewed-by: Jerome Pasion --- .../doc}/images/localfortuneclient-example.png | Bin .../doc}/images/localfortuneserver-example.png | Bin .../ipc/doc}/images/sharedmemory-example_1.png | Bin .../ipc/doc}/images/sharedmemory-example_2.png | Bin .../ipc/doc/src}/localfortuneclient.qdoc | 4 ++-- .../ipc/doc/src}/localfortuneserver.qdoc | 4 ++-- .../ipc/doc/src}/sharedmemory.qdoc | 14 +++++++------- src/corelib/doc/qtcore.qdocconf | 1 + 8 files changed, 12 insertions(+), 11 deletions(-) rename {doc/src => examples/ipc/doc}/images/localfortuneclient-example.png (100%) rename {doc/src => examples/ipc/doc}/images/localfortuneserver-example.png (100%) rename {doc/src => examples/ipc/doc}/images/sharedmemory-example_1.png (100%) rename {doc/src => examples/ipc/doc}/images/sharedmemory-example_2.png (100%) rename {doc/src/examples => examples/ipc/doc/src}/localfortuneclient.qdoc (94%) rename {doc/src/examples => examples/ipc/doc/src}/localfortuneserver.qdoc (94%) rename {doc/src/examples => examples/ipc/doc/src}/sharedmemory.qdoc (94%) diff --git a/doc/src/images/localfortuneclient-example.png b/examples/ipc/doc/images/localfortuneclient-example.png similarity index 100% rename from doc/src/images/localfortuneclient-example.png rename to examples/ipc/doc/images/localfortuneclient-example.png diff --git a/doc/src/images/localfortuneserver-example.png b/examples/ipc/doc/images/localfortuneserver-example.png similarity index 100% rename from doc/src/images/localfortuneserver-example.png rename to examples/ipc/doc/images/localfortuneserver-example.png diff --git a/doc/src/images/sharedmemory-example_1.png b/examples/ipc/doc/images/sharedmemory-example_1.png similarity index 100% rename from doc/src/images/sharedmemory-example_1.png rename to examples/ipc/doc/images/sharedmemory-example_1.png diff --git a/doc/src/images/sharedmemory-example_2.png b/examples/ipc/doc/images/sharedmemory-example_2.png similarity index 100% rename from doc/src/images/sharedmemory-example_2.png rename to examples/ipc/doc/images/sharedmemory-example_2.png diff --git a/doc/src/examples/localfortuneclient.qdoc b/examples/ipc/doc/src/localfortuneclient.qdoc similarity index 94% rename from doc/src/examples/localfortuneclient.qdoc rename to examples/ipc/doc/src/localfortuneclient.qdoc index ec1306b10aa..a68f4bad0cc 100644 --- a/doc/src/examples/localfortuneclient.qdoc +++ b/examples/ipc/doc/src/localfortuneclient.qdoc @@ -26,14 +26,14 @@ ****************************************************************************/ /*! - \example ipc/localfortuneclient + \example localfortuneclient \title Local Fortune Client Example \ingroup examples-ipc \brief Demonstrates using QLocalSocket for a simple local service client. The Local Fortune Client example shows how to create a client for a simple local service using QLocalSocket. It is intended to be run alongside the - \l{ipc/localfortuneserver}{Local Fortune Server} example. + \l{Local Fortune Server Example}. \image localfortuneclient-example.png Screenshot of the Local Fortune Client example diff --git a/doc/src/examples/localfortuneserver.qdoc b/examples/ipc/doc/src/localfortuneserver.qdoc similarity index 94% rename from doc/src/examples/localfortuneserver.qdoc rename to examples/ipc/doc/src/localfortuneserver.qdoc index d9828d4145c..13f7f3ca744 100644 --- a/doc/src/examples/localfortuneserver.qdoc +++ b/examples/ipc/doc/src/localfortuneserver.qdoc @@ -26,14 +26,14 @@ ****************************************************************************/ /*! - \example ipc/localfortuneserver + \example localfortuneserver \title Local Fortune Server Example \ingroup examples-ipc \brief Demonstrates using QLocalServer and QLocalSocket for serving a simple local service. The Local Fortune Server example shows how to create a server for a simple local service. It is intended to be run alongside the - \l{ipc/localfortuneclient}{Local Fortune Client} example + \l{Local Fortune Client Example} \image localfortuneserver-example.png Screenshot of the Local Fortune Server example */ diff --git a/doc/src/examples/sharedmemory.qdoc b/examples/ipc/doc/src/sharedmemory.qdoc similarity index 94% rename from doc/src/examples/sharedmemory.qdoc rename to examples/ipc/doc/src/sharedmemory.qdoc index e8c3f00f260..b9f0c86d44f 100644 --- a/doc/src/examples/sharedmemory.qdoc +++ b/examples/ipc/doc/src/sharedmemory.qdoc @@ -26,7 +26,7 @@ ****************************************************************************/ /*! - \example ipc/sharedmemory + \example sharedmemory \title Shared Memory Example \ingroup examples-ipc \brief Demonstrates doing inter-process communication using shared memory with @@ -40,7 +40,7 @@ dialog is displayed and then control is passed to the application in the standard way. - \snippet examples/ipc/sharedmemory/main.cpp 0 + \snippet sharedmemory/main.cpp 0 Two instances of class Dialog appear. @@ -51,12 +51,12 @@ loadFromFile() and loadFromMemory() that correspond to the two buttons on the dialog. - \snippet examples/ipc/sharedmemory/dialog.h 0 + \snippet sharedmemory/dialog.h 0 The constructor builds the user interface widgets and connects the clicked() signal of each button to the corresponding slot function. - \snippet examples/ipc/sharedmemory/dialog.cpp 0 + \snippet sharedmemory/dialog.cpp 0 Note that "QSharedMemoryExample" is passed to the \l {QSharedMemory} {QSharedMemory()} constructor to be used as the key. This will be @@ -69,7 +69,7 @@ that segment is detached from the process, so we can be assured of starting off the example correctly. - \snippet examples/ipc/sharedmemory/dialog.cpp 1 + \snippet sharedmemory/dialog.cpp 1 The user is then asked to select an image file using QFileDialog::getOpenFileName(). The selected file is loaded into a @@ -85,7 +85,7 @@ to the image data, which we then use to do a memcopy() from the QBuffer into the shared memory segment. - \snippet examples/ipc/sharedmemory/dialog.cpp 2 + \snippet sharedmemory/dialog.cpp 2 Note that we \l {QSharedMemory::} {lock()} the shared memory segment before we copy into it, and we \l {QSharedMemory::} {unlock()} it @@ -117,7 +117,7 @@ then streams the data into a QImage and \l {QSharedMemory::unlock()} {unlocks} the segment. - \snippet examples/ipc/sharedmemory/dialog.cpp 3 + \snippet sharedmemory/dialog.cpp 3 In this case, the function does \l {QSharedMemory::} {detach()} from the segment, because now we are effectively finished using diff --git a/src/corelib/doc/qtcore.qdocconf b/src/corelib/doc/qtcore.qdocconf index 2ad24d33b12..18342d01381 100644 --- a/src/corelib/doc/qtcore.qdocconf +++ b/src/corelib/doc/qtcore.qdocconf @@ -37,6 +37,7 @@ exampledirs += \ snippets \ ../../../examples/threads/ \ ../../../examples/tools/ \ + ../../../examples/ipc/ \ ../../../examples/json/ \ ../../../examples/network/dnslookup From 76eefbe8af7655f8d6979069aea07e4cb32c6ee8 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 24 Mar 2014 15:08:58 +0100 Subject: [PATCH 047/120] Android: Fix missing data from some autotests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After a test ended, we would instantly try to fetch its output, but at this point, it might still not be available through the adb interface, probably due to some cache synchronization in the file system? Adding an arbitrary three second pause between finishing the test and requesting the file fixes this. If the error pops up later again, we could do something more robust, like going in a loop for X seconds until the file has been fetched. Especially if detecting task finish was successful. Task-number: QTBUG-37444 Change-Id: I5442e1e0181f489b0626834a390e46c15bc0b371 Reviewed-by: Simo Fält --- tests/auto/android/runtests_androiddeployqt.pl | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/auto/android/runtests_androiddeployqt.pl b/tests/auto/android/runtests_androiddeployqt.pl index 1cc52d0495c..3d57dcfd654 100755 --- a/tests/auto/android/runtests_androiddeployqt.pl +++ b/tests/auto/android/runtests_androiddeployqt.pl @@ -217,6 +217,10 @@ sub startTest print "Someone should kill $packageName\n"; return 1; } + + # Wait for three seconds to allow process to write all data + sleep(3); + system("$adb_tool $device_serial pull /data/data/$packageName/output.xml $output_dir/$output_file.xml") if ($get_xml); system("$adb_tool $device_serial pull /data/data/$packageName/output.txt $output_dir/$output_file.txt") if ($get_txt); return 1; From d1ed2dee51ce1843e53912e250bc75b34b5bb0da Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 26 Mar 2014 10:07:59 +0100 Subject: [PATCH 048/120] Android: REG: Fix launching intents When the launch mode is singleInstance, then intents will not be launched as activities inside the same task, but as separate tasks, and onActivityResult() is always called immediately without any data. This is documented in various stack overflows and google group messages if you search for it on the Internet, and the singleInstance launch mode is documented as "not recommended for normal use". This broke e.g. automatic downloads of Ministro. The singleTop launch mode seems more like what we're after, and fixes both the original issue as well as the current problem with intents. Change-Id: Iab24a654a4433f979064509b1ef721db9ef352af Reviewed-by: BogDan Vatra --- src/android/java/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/android/java/AndroidManifest.xml b/src/android/java/AndroidManifest.xml index 1741101bc12..8e551ba7acf 100644 --- a/src/android/java/AndroidManifest.xml +++ b/src/android/java/AndroidManifest.xml @@ -5,7 +5,7 @@ android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="@string/app_name" android:screenOrientation="unspecified" - android:launchMode="singleInstance"> + android:launchMode="singleTop"> From e7270b68fe36528ba064e0f371f00988b443d1c0 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 26 Mar 2014 13:00:26 +0100 Subject: [PATCH 049/120] Doc: Update year to 2014 Change-Id: Iae2f31232fb364b26aa4da99048d92c262b4fdec Reviewed-by: Sergio Ahumada Reviewed-by: Jerome Pasion --- doc/global/config.qdocconf | 2 +- doc/global/html-footer.qdocconf | 2 +- src/tools/qdoc/doc/qdoc-manual-markupcmds.qdoc | 2 +- src/tools/qdoc/doc/qdoc-manual-qdocconf.qdoc | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/global/config.qdocconf b/doc/global/config.qdocconf index 2b3ca1d6ba3..8629b89e7e4 100644 --- a/doc/global/config.qdocconf +++ b/doc/global/config.qdocconf @@ -3,7 +3,7 @@ dita.metadata.default.author = Qt Project dita.metadata.default.permissions = all dita.metadata.default.publisher = Qt Project -dita.metadata.default.copyryear = 2013 +dita.metadata.default.copyryear = 2014 dita.metadata.default.copyrholder = Digia Plc dita.metadata.default.audience = programmer diff --git a/doc/global/html-footer.qdocconf b/doc/global/html-footer.qdocconf index c53eb2f5999..a77950ff994 100644 --- a/doc/global/html-footer.qdocconf +++ b/doc/global/html-footer.qdocconf @@ -8,7 +8,7 @@ HTML.footer = \ "\n" \ "

\n" \ "

\n" \ - " © 2013 Digia Plc and/or its\n" \ + " © 2014 Digia Plc and/or its\n" \ " subsidiaries. Documentation contributions included herein are the copyrights of\n" \ " their respective owners.
" \ " The documentation provided herein is licensed under the terms of the" \ diff --git a/src/tools/qdoc/doc/qdoc-manual-markupcmds.qdoc b/src/tools/qdoc/doc/qdoc-manual-markupcmds.qdoc index ee0a7b41dba..fe439389683 100644 --- a/src/tools/qdoc/doc/qdoc-manual-markupcmds.qdoc +++ b/src/tools/qdoc/doc/qdoc-manual-markupcmds.qdoc @@ -3775,7 +3775,7 @@ Qt Development Frameworks Qt Project - + Qt Project diff --git a/src/tools/qdoc/doc/qdoc-manual-qdocconf.qdoc b/src/tools/qdoc/doc/qdoc-manual-qdocconf.qdoc index 3adcf9b2139..a28e65e9767 100644 --- a/src/tools/qdoc/doc/qdoc-manual-qdocconf.qdoc +++ b/src/tools/qdoc/doc/qdoc-manual-qdocconf.qdoc @@ -1569,7 +1569,7 @@ dita.metadata.default.author = Qt Development Frameworks dita.metadata.default.permissions = all dita.metadata.default.publisher = Qt Project - dita.metadata.default.copyryear = 2013 + dita.metadata.default.copyryear = 2014 dita.metadata.default.copyrholder = Qt Project dita.metadata.default.audience = programmer \endcode From b3f201b8afcf88015f5bff7b3f43e90b13f8a8f1 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Tue, 25 Mar 2014 17:31:09 +0100 Subject: [PATCH 050/120] Android: use fbo read back workaround with specific GPUs. Namely, the Mali 400 and the Adreno 200. We used to enable this workaround only for the Samsung Galaxy Tab 3, which has a Mali 400. The same problem was confirmed with the Samsung Galaxy Note N7000 (Mali 400) and the ZTE Blade (Adreno 200). Task-number: QTBUG-33951 Task-number: QTBUG-34984 Change-Id: Ic624962986f718285b98ab4ca48e22f9aa110753 Reviewed-by: Eskil Abrahamsen Blomfeldt Reviewed-by: Shawn Rutledge --- .../android/qandroidplatformintegration.cpp | 4 ++-- .../android/qandroidplatformintegration.h | 2 +- .../android/qandroidplatformopenglcontext.cpp | 18 +++++++++++++++++- .../android/qandroidplatformopenglcontext.h | 2 ++ 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp index 9adefd5b2c2..a06f69b8d58 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.cpp +++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp @@ -132,7 +132,7 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList ¶ m_androidSystemLocale = new QAndroidSystemLocale; } -bool QAndroidPlatformIntegration::needsWorkaround() +bool QAndroidPlatformIntegration::needsBasicRenderloopWorkaround() { static bool needsWorkaround = QtAndroid::deviceName().compare(QStringLiteral("samsung SM-T211"), Qt::CaseInsensitive) == 0 @@ -150,7 +150,7 @@ bool QAndroidPlatformIntegration::hasCapability(Capability cap) const case OpenGL: return true; case ForeignWindows: return true; case ThreadedOpenGL: - if (needsWorkaround()) + if (needsBasicRenderloopWorkaround()) return false; else return true; diff --git a/src/plugins/platforms/android/qandroidplatformintegration.h b/src/plugins/platforms/android/qandroidplatformintegration.h index 2d685bc567b..4a3fe6c766a 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.h +++ b/src/plugins/platforms/android/qandroidplatformintegration.h @@ -120,9 +120,9 @@ public: QTouchDevice *touchDevice() const { return m_touchDevice; } void setTouchDevice(QTouchDevice *touchDevice) { m_touchDevice = touchDevice; } - static bool needsWorkaround(); EGLDisplay m_eglDisplay; private: + static bool needsBasicRenderloopWorkaround(); QTouchDevice *m_touchDevice; diff --git a/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp b/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp index a0b3ae066cc..289480c6257 100644 --- a/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp +++ b/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp @@ -62,6 +62,22 @@ void QAndroidPlatformOpenGLContext::swapBuffers(QPlatformSurface *surface) static_cast(surface)->checkNativeSurface(eglConfig()); } +bool QAndroidPlatformOpenGLContext::needsFBOReadBackWorkaroud() +{ + static bool set = false; + static bool needsWorkaround = false; + + if (!set) { + const char *rendererString = reinterpret_cast(glGetString(GL_RENDERER)); + needsWorkaround = + qstrcmp(rendererString, "Mali-400 MP") == 0 + || qstrcmp(rendererString, "Adreno (TM) 200") == 0; + set = true; + } + + return needsWorkaround; +} + bool QAndroidPlatformOpenGLContext::makeCurrent(QPlatformSurface *surface) { bool ret = QEGLPlatformContext::makeCurrent(surface); @@ -71,7 +87,7 @@ bool QAndroidPlatformOpenGLContext::makeCurrent(QPlatformSurface *surface) if (rendererString != 0 && qstrncmp(rendererString, "Android Emulator", 16) == 0) ctx_d->workaround_missingPrecisionQualifiers = true; - if (!ctx_d->workaround_brokenFBOReadBack && QAndroidPlatformIntegration::needsWorkaround()) + if (!ctx_d->workaround_brokenFBOReadBack && needsFBOReadBackWorkaroud()) ctx_d->workaround_brokenFBOReadBack = true; return ret; diff --git a/src/plugins/platforms/android/qandroidplatformopenglcontext.h b/src/plugins/platforms/android/qandroidplatformopenglcontext.h index 29e5f596d5b..10a89d541b8 100644 --- a/src/plugins/platforms/android/qandroidplatformopenglcontext.h +++ b/src/plugins/platforms/android/qandroidplatformopenglcontext.h @@ -56,6 +56,8 @@ public: private: virtual EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface); + + static bool needsFBOReadBackWorkaroud(); }; QT_END_NAMESPACE From 3c68252bf58a80fcf75fffcc2e0c976b1aa172fb Mon Sep 17 00:00:00 2001 From: Jonathan Liu Date: Thu, 27 Mar 2014 01:50:11 +1100 Subject: [PATCH 051/120] Doc: Fix typos Change-Id: I720813b126f02d4813c88811316a0fa99961c6d8 Reviewed-by: Friedemann Kleint --- src/gui/opengl/qopenglpaintdevice.cpp | 2 +- src/opengl/doc/src/qtopengl-index.qdoc | 2 +- src/xml/doc/src/qtxml-index.qdoc | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/opengl/qopenglpaintdevice.cpp b/src/gui/opengl/qopenglpaintdevice.cpp index fa392d16aab..6750458f835 100644 --- a/src/gui/opengl/qopenglpaintdevice.cpp +++ b/src/gui/opengl/qopenglpaintdevice.cpp @@ -81,7 +81,7 @@ QT_BEGIN_NAMESPACE multisampling. Most hardware require significantly more memory to do multisampling and the resulting quality is not on par with the quality of the software paint engine. The OpenGL paint engine's - strenght lies in its performance, not its visual rendering + strength lies in its performance, not its visual rendering quality. \section1 State Changes diff --git a/src/opengl/doc/src/qtopengl-index.qdoc b/src/opengl/doc/src/qtopengl-index.qdoc index fc131c4b171..ff946c6e4ec 100644 --- a/src/opengl/doc/src/qtopengl-index.qdoc +++ b/src/opengl/doc/src/qtopengl-index.qdoc @@ -68,5 +68,5 @@ non-OpenGL-specific GUI functionality. The \l{Qt OpenGL C++ Classes} page gives an overview over the available classes - int this module. + in this module. */ diff --git a/src/xml/doc/src/qtxml-index.qdoc b/src/xml/doc/src/qtxml-index.qdoc index ded8f3de3cb..76866ad66bf 100644 --- a/src/xml/doc/src/qtxml-index.qdoc +++ b/src/xml/doc/src/qtxml-index.qdoc @@ -44,5 +44,5 @@ \snippet code/doc_src_qtxml.pro 1 The \l{Qt XML C++ Classes} page gives an overview over the available classes - int this module. + in this module. */ From bd9f490d4552fa4d41c308bf3ee285d26d2019b6 Mon Sep 17 00:00:00 2001 From: Maurice Kalinowski Date: Tue, 25 Mar 2014 15:01:16 +0100 Subject: [PATCH 052/120] Disable non-fullscreen windows for WinRT The integration seems to have been missing this flag. Hence we tried to open new windows in non-fullscreen mode causing lots of issues. For instance this resolves QCombobox popup problems. Task-number: QTBUG-37593 Change-Id: I3d3e3699dff91dcb95613893c2a5bdefc90131b7 Reviewed-by: Andrew Knight --- src/plugins/platforms/winrt/qwinrtintegration.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp index be823907234..b3a2cafa2ee 100644 --- a/src/plugins/platforms/winrt/qwinrtintegration.cpp +++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp @@ -124,6 +124,8 @@ bool QWinRTIntegration::hasCapability(QPlatformIntegration::Capability cap) cons case OpenGL: case ApplicationState: return true; + case NonFullScreenWindows: + return false; default: return QPlatformIntegration::hasCapability(cap); } From 18d031fb1896001a9edbd42edfa8b2b7a6ba9825 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Sat, 22 Mar 2014 08:22:25 +0200 Subject: [PATCH 053/120] Don't create screen surface if there are no raster windows. Change-Id: Idaf5df814bb087707654d7ad7046ba8799f99c0a Reviewed-by: Sean Harmer Reviewed-by: BogDan Vatra --- src/plugins/platforms/android/androidjnimain.cpp | 3 ++- .../platforms/android/qandroidplatformscreen.cpp | 13 +++++++++++-- .../platforms/android/qandroidplatformscreen.h | 2 ++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp index 784cc2e38ba..ff1a40bfc5e 100644 --- a/src/plugins/platforms/android/androidjnimain.cpp +++ b/src/plugins/platforms/android/androidjnimain.cpp @@ -576,7 +576,8 @@ static void updateWindow(JNIEnv */*env*/, jobject /*thiz*/) } QAndroidPlatformScreen *screen = static_cast(m_androidPlatformIntegration->screen()); - QMetaObject::invokeMethod(screen, "setDirty", Qt::QueuedConnection, Q_ARG(QRect,screen->geometry())); + if (screen->rasterSurfaces()) + QMetaObject::invokeMethod(screen, "setDirty", Qt::QueuedConnection, Q_ARG(QRect,screen->geometry())); } static void updateApplicationState(JNIEnv */*env*/, jobject /*thiz*/, jint state) diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp index dbf317696f3..678f4e6b5a5 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.cpp +++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp @@ -133,8 +133,10 @@ void QAndroidPlatformScreen::addWindow(QAndroidPlatformWindow *window) return; m_windowStack.prepend(window); - if (window->isRaster()) + if (window->isRaster()) { + m_rasterSurfaces.ref(); setDirty(window->geometry()); + } QWindow *w = topWindow(); QWindowSystemInterface::handleWindowActivated(w); @@ -148,8 +150,10 @@ void QAndroidPlatformScreen::removeWindow(QAndroidPlatformWindow *window) m_windowStack.removeOne(window); if (window->isRaster()) { + m_rasterSurfaces.deref(); setDirty(window->geometry()); } + QWindow *w = topWindow(); QWindowSystemInterface::handleWindowActivated(w); topWindowChanged(w); @@ -238,6 +242,11 @@ void QAndroidPlatformScreen::topWindowChanged(QWindow *w) } } +int QAndroidPlatformScreen::rasterSurfaces() +{ + return m_rasterSurfaces; +} + void QAndroidPlatformScreen::doRedraw() { PROFILE_SCOPE; @@ -246,7 +255,7 @@ void QAndroidPlatformScreen::doRedraw() return; QMutexLocker lock(&m_surfaceMutex); - if (m_id == -1) { + if (m_id == -1 && m_rasterSurfaces) { m_id = QtAndroid::createSurface(this, m_geometry, true, m_depth); m_surfaceWaitCondition.wait(&m_surfaceMutex); } diff --git a/src/plugins/platforms/android/qandroidplatformscreen.h b/src/plugins/platforms/android/qandroidplatformscreen.h index 625e77840ec..96a91fbf065 100644 --- a/src/plugins/platforms/android/qandroidplatformscreen.h +++ b/src/plugins/platforms/android/qandroidplatformscreen.h @@ -82,6 +82,7 @@ public: void scheduleUpdate(); void topWindowChanged(QWindow *w); + int rasterSurfaces(); public slots: void setDirty(const QRect &rect); @@ -110,6 +111,7 @@ private slots: private: int m_id = -1; + QAtomicInt m_rasterSurfaces = 0; ANativeWindow* m_nativeSurface = nullptr; QWaitCondition m_surfaceWaitCondition; }; From 13b38ac661f936c9cbd7af1f7851f82afb2634b9 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Thu, 27 Mar 2014 09:14:53 +0200 Subject: [PATCH 054/120] Android: registerTouchDevice at startup I'd like to keep registerTouchDevice from androidjniinput.cpp, touchEnd as a backup for buggy Android devices that are not setting Configurations.touchscreen field correctly. Task-number: QTBUG-36007 Change-Id: Ib8f107474baa278b2d82d9ca14913512dfff01c2 Reviewed-by: Shawn Rutledge --- .../android/qandroidplatformintegration.cpp | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp index a06f69b8d58..6395f713982 100644 --- a/src/plugins/platforms/android/qandroidplatformintegration.cpp +++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp @@ -41,6 +41,7 @@ #include "qandroidplatformintegration.h" +#include #include #include #include @@ -130,6 +131,38 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList ¶ #endif m_androidSystemLocale = new QAndroidSystemLocale; + + QJNIObjectPrivate javaActivity(QtAndroid::activity()); + if (javaActivity.isValid()) { + QJNIObjectPrivate resources = javaActivity.callObjectMethod("getResources", "()Landroid/content/res/Resources;"); + QJNIObjectPrivate configuration = resources.callObjectMethod("getConfiguration", "()Landroid/content/res/Configuration;"); + + int touchScreen = configuration.getField("touchscreen"); + if (touchScreen == QJNIObjectPrivate::getStaticField("android/content/res/Configuration", "TOUCHSCREEN_FINGER") + || touchScreen == QJNIObjectPrivate::getStaticField("android/content/res/Configuration", "TOUCHSCREEN_STYLUS")) + { + m_touchDevice = new QTouchDevice; + m_touchDevice->setType(QTouchDevice::TouchScreen); + m_touchDevice->setCapabilities(QTouchDevice::Position + | QTouchDevice::Area + | QTouchDevice::Pressure + | QTouchDevice::NormalizedPosition); + + QJNIObjectPrivate pm = javaActivity.callObjectMethod("getPackageManager", "()Landroid/content/pm/PackageManager;"); + Q_ASSERT(pm.isValid()); + if (pm.callMethod("hasSystemFeature","(Ljava/lang/String;)Z", + QJNIObjectPrivate::getStaticObjectField("android/content/pm/PackageManager", "FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND", "Ljava/lang/String;").object())) { + m_touchDevice->setMaximumTouchPoints(10); + } else if (pm.callMethod("hasSystemFeature","(Ljava/lang/String;)Z", + QJNIObjectPrivate::getStaticObjectField("android/content/pm/PackageManager", "FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT", "Ljava/lang/String;").object())) { + m_touchDevice->setMaximumTouchPoints(4); + } else if (pm.callMethod("hasSystemFeature","(Ljava/lang/String;)Z", + QJNIObjectPrivate::getStaticObjectField("android/content/pm/PackageManager", "FEATURE_TOUCHSCREEN_MULTITOUCH", "Ljava/lang/String;").object())) { + m_touchDevice->setMaximumTouchPoints(2); + } + QWindowSystemInterface::registerTouchDevice(m_touchDevice); + } + } } bool QAndroidPlatformIntegration::needsBasicRenderloopWorkaround() From bc2e7054ef10a25a9bdc11c66eacf9c118c232a6 Mon Sep 17 00:00:00 2001 From: BogDan Vatra Date: Thu, 27 Mar 2014 10:30:50 +0200 Subject: [PATCH 055/120] Android: Change Ministro's source to 5.3 Task-number: QTBUG-37879 Change-Id: If9a3f38a5dc267862a166ac4c8e6940739eab911 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/android/java/res/values/libs.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/android/java/res/values/libs.xml b/src/android/java/res/values/libs.xml index 797e6bb8c45..664ab0abecc 100644 --- a/src/android/java/res/values/libs.xml +++ b/src/android/java/res/values/libs.xml @@ -1,7 +1,7 @@ - https://download.qt-project.org/ministro/android/qt5/qt-5.2 + https://download.qt-project.org/ministro/android/qt5/qt-5.3