From d69788728ccd843e3d4a372680185fdf5e711c86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 5 Aug 2011 10:35:55 +0200 Subject: Encapsulate pointer manipulations to createFileTemplate function , where we actually control how we use the pointers. Reduce some code duplication in #ifdefs. --- src/corelib/io/qtemporaryfile.cpp | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index d457601..9228f94 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -96,18 +96,22 @@ QT_BEGIN_NAMESPACE \internal Generates a unique file path and returns a native handle to the open file. - \a path is used as a template when generating unique paths, - \a placeholderStart and \a placeholderEnd delimit the sub-string that will - be randomized. + \a path is used as a template when generating unique paths, \a pos + identifies the position of the first character that will be replaced in the + template and \a length the number of characters that may be substituted. Returns an open handle to the newly created file if successful, an invalid handle otherwise. In both cases, the string in \a path will be changed and contain the generated path name. */ -static int createFileFromTemplate(char *const path, - char *const placeholderStart, char *const placeholderEnd) +static int createFileFromTemplate(QByteArray &path, size_t pos, size_t length) { - Q_ASSERT(placeholderEnd > placeholderStart); + Q_ASSERT(length != 0); + Q_ASSERT(pos < size_t(path.length())); + Q_ASSERT(length < size_t(path.length()) - pos); + + char *const placeholderStart = path.data() + pos; + char *const placeholderEnd = placeholderStart + length; // Initialize placeholder with random chars + PID. { @@ -134,14 +138,16 @@ static int createFileFromTemplate(char *const path, // Atomically create file and obtain handle #ifndef Q_OS_WIN { - int fd = QT_OPEN(path, QT_OPEN_CREAT | O_EXCL | QT_OPEN_RDWR | QT_OPEN_LARGEFILE, 0600); + int fd = QT_OPEN(path.constData(), + QT_OPEN_CREAT | O_EXCL | QT_OPEN_RDWR | QT_OPEN_LARGEFILE, + 0600); if (fd != -1) return fd; if (errno != EEXIST) return -1; } #else - if (!QFileInfo(QString::fromLocal8Bit(path)).exists()) + if (!QFileInfo(QString::fromLocal8Bit(path.constData(), path.length())).exists()) return 1; #endif @@ -295,10 +301,9 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) else filename.insert(phPos + phLength, suffix.toLocal8Bit()); - char *path = filename.data(); + int fd = createFileFromTemplate(filename, phPos, phLength); #ifndef Q_OS_WIN - int fd = createFileFromTemplate(path, path + phPos, path + phPos + phLength); if (fd != -1) { // First open the fd as an external file descriptor to // initialize the engine properly. @@ -308,7 +313,7 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) d->closeFileHandle = true; // Restore the file names (open() resets them). - d->fileEntry = QFileSystemEntry(QString::fromLocal8Bit(path, filename.length())); //note that filename is NOT a native path + d->fileEntry = QFileSystemEntry(QString::fromLocal8Bit(filename.constData(), filename.length())); //note that filename is NOT a native path filePathIsTemplate = false; return true; } @@ -318,13 +323,11 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError, qt_error_string(errno)); return false; #else - if (createFileFromTemplate(path, path + phPos, path + phPos + phLength) == -1) { + if (fd == -1) return false; - } QString template_ = d->fileEntry.filePath(); - d->fileEntry = QFileSystemEntry(QString::fromLocal8Bit(path, filename.length())); - + d->fileEntry = QFileSystemEntry(QString::fromLocal8Bit(filename.constData(), filename.length())); if (QFSFileEngine::open(openMode)) { filePathIsTemplate = false; return true; -- cgit v0.12 From 63bb67d3107b03f399cddf4c9cca9c7eb347b62d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 5 Aug 2011 10:39:53 +0200 Subject: Make Symbian follow Windows code in temporary path generation On the one hand, we stop using OpenC here. On the other, we no longer use an atomic create and obtain file handle API -- just as we don't on Windows yet. This is a stepping stone to removing back and forth conversions of path names when generating unique names and also towards the use of native APIs for creating and obtaining a file handle atomically. Reviewed-by: Gareth Stockwell Reviewed-by: Shane Kearns --- src/corelib/io/qtemporaryfile.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index 9228f94..497faad 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -49,12 +49,9 @@ #include "private/qabstractfileengine_p.h" #include "private/qfsfileengine_p.h" -#if !defined(Q_OS_WINCE) -# include -#endif - -#if defined(Q_OS_UNIX) -# include "private/qcore_unix_p.h" // overrides QT_OPEN +#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) +#include "private/qcore_unix_p.h" // overrides QT_OPEN +#include #endif #if defined(QT_BUILD_CORE_LIB) @@ -136,7 +133,7 @@ static int createFileFromTemplate(QByteArray &path, size_t pos, size_t length) for (;;) { // Atomically create file and obtain handle -#ifndef Q_OS_WIN +#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) { int fd = QT_OPEN(path.constData(), QT_OPEN_CREAT | O_EXCL | QT_OPEN_RDWR | QT_OPEN_LARGEFILE, @@ -303,7 +300,7 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) int fd = createFileFromTemplate(filename, phPos, phLength); -#ifndef Q_OS_WIN +#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) if (fd != -1) { // First open the fd as an external file descriptor to // initialize the engine properly. -- cgit v0.12 From d71d3b1ce31ffc585258330d825ff8ea535254ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 5 Aug 2011 10:57:19 +0200 Subject: Use QStringBuilder when copying template for modification This avoids modifying the original string in the case where a placeholder marker is not found. By marking the variable const we further avoid checks on the reference count and detaches, also allowing us to safely reuse it later in the function. The new approach also fixes an issue where suffix wasn't empty, but the toLocal8Bit conversion would be. This resulted in a buffer overflow inside createFileFromTemplate. Reviewed-by: Shane Kearns --- src/corelib/io/qtemporaryfile.cpp | 62 +++++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 15 deletions(-) diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index 497faad..b079d3e 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -45,6 +45,7 @@ #include "qplatformdefs.h" #include "qabstractfileengine.h" +#include "qstringbuilder.h" #include "private/qfile_p.h" #include "private/qabstractfileengine_p.h" #include "private/qfsfileengine_p.h" @@ -60,6 +61,38 @@ QT_BEGIN_NAMESPACE +struct Placeholder +{ + Placeholder(int size) + : size_(size) + { + } + + int size() const + { + return size_; + } + +private: + int size_; +}; + +template <> +struct QConcatenable +{ + typedef Placeholder type; + typedef QByteArray ConvertTo; + enum { ExactSize = true }; + static int size(const Placeholder &p) { return p.size(); } + + template + static inline void appendTo(const Placeholder &p, CharT *&out) + { + // Uninitialized + out += p.size(); + } +}; + /* * Copyright (c) 1987, 1993 * The Regents of the University of California. All rights reserved. @@ -258,7 +291,7 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) if (!filePathIsTemplate) return QFSFileEngine::open(openMode); - QString qfilename = d->fileEntry.filePath(); + const QString qfilename = d->fileEntry.filePath(); // Find placeholder string. uint phPos = qfilename.length(); @@ -281,22 +314,22 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) phLength = 0; } - QStringRef prefix, suffix; + QByteArray filename; + if (phLength < 6) { - qfilename += QLatin1Char('.'); - prefix = QStringRef(&qfilename); + filename = qfilename.toLocal8Bit(); + + phPos = filename.length() + 1; // Account for added dot in prefix phLength = 6; + filename = filename % '.' % Placeholder(phLength); } else { - prefix = qfilename.leftRef(phPos); - suffix = qfilename.midRef(phPos + phLength); - } + QByteArray prefix, suffix; + prefix = qfilename.leftRef(phPos).toLocal8Bit(); + suffix = qfilename.midRef(phPos + phLength).toLocal8Bit(); - QByteArray filename = prefix.toLocal8Bit(); - phPos = filename.length(); - if (suffix.isEmpty()) - filename.resize(phPos + phLength); - else - filename.insert(phPos + phLength, suffix.toLocal8Bit()); + phPos = prefix.length(); + filename = prefix % Placeholder(phLength) % suffix; + } int fd = createFileFromTemplate(filename, phPos, phLength); @@ -323,14 +356,13 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) if (fd == -1) return false; - QString template_ = d->fileEntry.filePath(); d->fileEntry = QFileSystemEntry(QString::fromLocal8Bit(filename.constData(), filename.length())); if (QFSFileEngine::open(openMode)) { filePathIsTemplate = false; return true; } - d->fileEntry = QFileSystemEntry(template_, QFileSystemEntry::FromInternalPath()); + d->fileEntry = QFileSystemEntry(qfilename, QFileSystemEntry::FromInternalPath()); return false; #endif } -- cgit v0.12 From 9a76587363a2f37312326286e08cce502f7fe27e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 5 Aug 2011 10:58:08 +0200 Subject: Minimize encoding conversions when generating unique file name With minor adjustments, createFileFromTemplate is made to work directly on (UTF-16) QString data, which is already in the native encoding for Windows and Symbian. This is possible because the function only fills out the placeholder sub-string, without touching adjacent characters. This eliminates unnecessary conversions on those platforms. Reviewed-by: Gareth Stockwell Reviewed-by: Shane Kearns --- src/corelib/io/qtemporaryfile.cpp | 69 ++++++++++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 15 deletions(-) diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index b079d3e..e4c53aa 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -61,6 +61,33 @@ QT_BEGIN_NAMESPACE +#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN) +typedef ushort Char; + +static inline Char Latin1Char(char ch) +{ + return ushort(uchar(ch)); +} + +template <> +struct QConcatenable +{ + typedef Char type; + typedef QString ConvertTo; + enum { ExactSize = true }; + static int size(const Char &) { return 1; } + + static inline void appendTo(const Char &u16, QChar *&out) + { + *out++ = QChar(u16); + } +}; + +#else // POSIX +typedef char Char; +typedef char Latin1Char; +#endif + struct Placeholder { Placeholder(int size) @@ -134,23 +161,24 @@ struct QConcatenable handle otherwise. In both cases, the string in \a path will be changed and contain the generated path name. */ -static int createFileFromTemplate(QByteArray &path, size_t pos, size_t length) +static int createFileFromTemplate(QFileSystemEntry::NativePath &path, + size_t pos, size_t length) { Q_ASSERT(length != 0); Q_ASSERT(pos < size_t(path.length())); Q_ASSERT(length < size_t(path.length()) - pos); - char *const placeholderStart = path.data() + pos; - char *const placeholderEnd = placeholderStart + length; + Char *const placeholderStart = (Char *)path.data() + pos; + Char *const placeholderEnd = placeholderStart + length; // Initialize placeholder with random chars + PID. { - char *rIter = placeholderEnd; + Char *rIter = placeholderEnd; #if defined(QT_BUILD_CORE_LIB) quint64 pid = quint64(QCoreApplication::applicationPid()); do { - *--rIter = (pid % 10) + '0'; + *--rIter = Latin1Char((pid % 10) + '0'); pid /= 10; } while (rIter != placeholderStart && pid != 0); #endif @@ -158,9 +186,9 @@ static int createFileFromTemplate(QByteArray &path, size_t pos, size_t length) while (rIter != placeholderStart) { char ch = char((qrand() & 0xffff) % (26 + 26)); if (ch < 26) - *--rIter = ch + 'A'; + *--rIter = Latin1Char(ch + 'A'); else - *--rIter = ch - 26 + 'a'; + *--rIter = Latin1Char(ch - 26 + 'a'); } } @@ -177,18 +205,18 @@ static int createFileFromTemplate(QByteArray &path, size_t pos, size_t length) return -1; } #else - if (!QFileInfo(QString::fromLocal8Bit(path.constData(), path.length())).exists()) + if (!QFileInfo(path).exists()) return 1; #endif /* tricky little algorwwithm for backward compatibility */ - for (char *iter = placeholderStart;;) { + for (Char *iter = placeholderStart;;) { // Character progression: [0-9] => 'a' ... 'z' => 'A' .. 'Z' // String progression: "ZZaiC" => "aabiC" - switch (*iter) { + switch (char(*iter)) { case 'Z': // Rollover, advance next character - *iter = 'a'; + *iter = Latin1Char('a'); if (++iter == placeholderEnd) return -1; @@ -196,12 +224,12 @@ static int createFileFromTemplate(QByteArray &path, size_t pos, size_t length) case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - *iter = 'a'; + *iter = Latin1Char('a'); break; case 'z': // increment 'z' to 'A' - *iter = 'A'; + *iter = Latin1Char('A'); break; default: @@ -314,8 +342,9 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) phLength = 0; } - QByteArray filename; + QFileSystemEntry::NativePath filename; +#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) if (phLength < 6) { filename = qfilename.toLocal8Bit(); @@ -330,6 +359,16 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) phPos = prefix.length(); filename = prefix % Placeholder(phLength) % suffix; } +#else + if (phLength < 6) { + phPos = qfilename.length() + 1; // Account for added dot in prefix + phLength = 6; + filename = qfilename % Latin1Char('.') % Placeholder(phLength); + } else + filename = qfilename; + + // No native separators, not a "native path" +#endif int fd = createFileFromTemplate(filename, phPos, phLength); @@ -356,7 +395,7 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) if (fd == -1) return false; - d->fileEntry = QFileSystemEntry(QString::fromLocal8Bit(filename.constData(), filename.length())); + d->fileEntry = QFileSystemEntry(filename, QFileSystemEntry::FromInternalPath()); if (QFSFileEngine::open(openMode)) { filePathIsTemplate = false; return true; -- cgit v0.12 From ff9b69838ec146aeb43d4af8a03043f9c5f0454d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 5 Aug 2011 10:45:08 +0200 Subject: Atomic implementation of create file and obtain handle for Win/Symbian Besides generating a unique name, createFileFromTemplate now also acquires a file handle on all platforms. The file engine's native handle is passed by reference and modified in place. This fixes a long standing security issue on Windows. On Windows and Symbian platforms we directly use the "native" file path when processing the template and generating the unique name. Since the native encoding is known, conversions at this point are safe. Errors other than "file exists" are propagated to Q(Temporary)File, and result in a failure in open(). The changes also unify error handling and should give consistent behaviour across all platforms. Worthy of note, there's a change in behaviour on Windows and Symbian: fileNames returned by QTemporaryFile on Windows and Symbian are always absolute after open has been called. This has to do with how QFileSystemEntry::nativeFilePath works on these platforms. (Test was updated to reflect change in behaviour.) Reviewed-by: Gareth Stockwell Reviewed-by: Shane Kearns --- src/corelib/io/qtemporaryfile.cpp | 151 +++++++++++++++-------- tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp | 31 +++-- 2 files changed, 122 insertions(+), 60 deletions(-) diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index e4c53aa..cd6ab40 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -49,6 +49,11 @@ #include "private/qfile_p.h" #include "private/qabstractfileengine_p.h" #include "private/qfsfileengine_p.h" +#include "private/qsystemerror_p.h" + +#if defined(Q_OS_SYMBIAN) +#include "private/qcore_symbian_p.h" +#endif #if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) #include "private/qcore_unix_p.h" // overrides QT_OPEN @@ -83,9 +88,20 @@ struct QConcatenable } }; +# ifdef Q_OS_WIN +typedef HANDLE NativeFileHandle; +# else // Q_OS_SYMBIAN +# ifdef SYMBIAN_ENABLE_64_BIT_FILE_SERVER_API +typedef RFile64 NativeFileHandle; +# else +typedef RFile NativeFileHandle; +# endif +# endif + #else // POSIX typedef char Char; typedef char Latin1Char; +typedef int NativeFileHandle; #endif struct Placeholder @@ -161,8 +177,9 @@ struct QConcatenable handle otherwise. In both cases, the string in \a path will be changed and contain the generated path name. */ -static int createFileFromTemplate(QFileSystemEntry::NativePath &path, - size_t pos, size_t length) +static bool createFileFromTemplate(NativeFileHandle &file, + QFileSystemEntry::NativePath &path, size_t pos, size_t length, + QSystemError &error) { Q_ASSERT(length != 0); Q_ASSERT(pos < size_t(path.length())); @@ -192,21 +209,50 @@ static int createFileFromTemplate(QFileSystemEntry::NativePath &path, } } +#ifdef Q_OS_SYMBIAN + RFs& fs = qt_s60GetRFs(); +#endif + for (;;) { // Atomically create file and obtain handle -#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) - { - int fd = QT_OPEN(path.constData(), - QT_OPEN_CREAT | O_EXCL | QT_OPEN_RDWR | QT_OPEN_LARGEFILE, - 0600); - if (fd != -1) - return fd; - if (errno != EEXIST) - return -1; +#if defined(Q_OS_WIN) + file = CreateFile((const wchar_t *)path.constData(), + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, NULL); + + if (file != INVALID_HANDLE_VALUE) + return true; + + DWORD err = GetLastError(); + if (err != ERROR_FILE_EXISTS) { + error = QSystemError(err, QSystemError::NativeError); + return false; + } +#elif defined(Q_OS_SYMBIAN) + TInt err = file.Create(fs, qt_QString2TPtrC(path), + EFileRead | EFileWrite | EFileShareReadersOrWriters); + + if (err == KErrNone) + return true; + + if (err != KErrAlreadyExists) { + error = QSystemError(err, QSystemError::NativeError); + return false; + } +#else // POSIX + file = QT_OPEN(path.constData(), + QT_OPEN_CREAT | O_EXCL | QT_OPEN_RDWR | QT_OPEN_LARGEFILE, + 0600); + + if (file != -1) + return true; + + int err = errno; + if (err != EEXIST) { + error = QSystemError(err, QSystemError::NativeError); + return false; } -#else - if (!QFileInfo(path).exists()) - return 1; #endif /* tricky little algorwwithm for backward compatibility */ @@ -217,8 +263,11 @@ static int createFileFromTemplate(QFileSystemEntry::NativePath &path, case 'Z': // Rollover, advance next character *iter = Latin1Char('a'); - if (++iter == placeholderEnd) - return -1; + if (++iter == placeholderEnd) { + // Out of alternatives. Return file exists error, previously set. + error = QSystemError(err, QSystemError::NativeError); + return false; + } continue; @@ -319,7 +368,14 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) if (!filePathIsTemplate) return QFSFileEngine::open(openMode); - const QString qfilename = d->fileEntry.filePath(); + const QString qfilename = +#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) + // Since the native encoding is out of our control, we need to process + // the path as UTF-16 before doing any conversions + d->fileEntry.filePath(); +#else + d->fileEntry.nativeFilePath(); +#endif // Find placeholder string. uint phPos = qfilename.length(); @@ -333,8 +389,14 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) continue; } - if (qfilename[phPos] == QLatin1Char('/') - || phLength >= 6) { + if (phLength >= 6 + || qfilename[phPos] == +#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) + QLatin1Char('/') +#else + QLatin1Char('\\') +#endif + ) { ++phPos; break; } @@ -366,44 +428,35 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) filename = qfilename % Latin1Char('.') % Placeholder(phLength); } else filename = qfilename; - - // No native separators, not a "native path" #endif - int fd = createFileFromTemplate(filename, phPos, phLength); + QSystemError error; +#if defined(Q_OS_WIN) + NativeFileHandle &file = d->fileHandle; +#elif defined(Q_OS_SYMBIAN) + NativeFileHandle &file = d->symbianFile; +#else // POSIX + NativeFileHandle &file = d->fd; +#endif -#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) - if (fd != -1) { - // First open the fd as an external file descriptor to - // initialize the engine properly. - if (QFSFileEngine::open(openMode, fd)) { + if (!createFileFromTemplate(file, filename, phPos, phLength, error)) { + setError(QFile::OpenError, error.toString()); + return false; + } - // Allow the engine to close the handle even if it's "external". - d->closeFileHandle = true; + d->fileEntry = QFileSystemEntry(filename, QFileSystemEntry::FromNativePath()); - // Restore the file names (open() resets them). - d->fileEntry = QFileSystemEntry(QString::fromLocal8Bit(filename.constData(), filename.length())); //note that filename is NOT a native path - filePathIsTemplate = false; - return true; - } +#if !defined(Q_OS_WIN) + d->closeFileHandle = true; +#endif - QT_CLOSE(fd); - } - setError(errno == EMFILE ? QFile::ResourceError : QFile::OpenError, qt_error_string(errno)); - return false; -#else - if (fd == -1) - return false; + filePathIsTemplate = false; - d->fileEntry = QFileSystemEntry(filename, QFileSystemEntry::FromInternalPath()); - if (QFSFileEngine::open(openMode)) { - filePathIsTemplate = false; - return true; - } + d->openMode = openMode; + d->lastFlushFailed = false; + d->tried_stat = 0; - d->fileEntry = QFileSystemEntry(qfilename, QFileSystemEntry::FromInternalPath()); - return false; -#endif + return true; } bool QTemporaryFileEngine::remove() diff --git a/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp b/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp index 2edb93a..05fee95 100644 --- a/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp +++ b/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp @@ -201,11 +201,12 @@ void tst_QTemporaryFile::fileTemplate() QCOMPARE(file.open(), true); + QString fileName = QFileInfo(file).fileName(); if (prefix.length()) - QCOMPARE(file.fileName().left(prefix.length()), prefix); + QCOMPARE(fileName.left(prefix.length()), prefix); if (suffix.length()) - QCOMPARE(file.fileName().right(suffix.length()), suffix); + QCOMPARE(fileName.right(suffix.length()), suffix); } @@ -701,20 +702,28 @@ void tst_QTemporaryFile::QTBUG_4796() << file5.fileName() << file6.fileName(); - QVERIFY(file1.fileName().startsWith(fileTemplate1 + QLatin1Char('.'))); - QVERIFY(file2.fileName().startsWith(fileTemplate2 + QLatin1Char('.'))); - QVERIFY(file5.fileName().startsWith("test-XXXXXX/" + fileTemplate1 + QLatin1Char('.'))); - QVERIFY(file6.fileName().startsWith("test-XXXXXX/" + prefix)); + QDir currentDir; + QString fileName1 = currentDir.relativeFilePath(file1.fileName()); + QString fileName2 = currentDir.relativeFilePath(file2.fileName()); + QString fileName3 = currentDir.relativeFilePath(file3.fileName()); + QString fileName4 = currentDir.relativeFilePath(file4.fileName()); + QString fileName5 = currentDir.relativeFilePath(file5.fileName()); + QString fileName6 = currentDir.relativeFilePath(file6.fileName()); + + QVERIFY(fileName1.startsWith(fileTemplate1 + QLatin1Char('.'))); + QVERIFY(fileName2.startsWith(fileTemplate2 + QLatin1Char('.'))); + QVERIFY(fileName5.startsWith("test-XXXXXX/" + fileTemplate1 + QLatin1Char('.'))); + QVERIFY(fileName6.startsWith("test-XXXXXX/" + prefix)); if (!prefix.isEmpty()) { - QVERIFY(file3.fileName().startsWith(prefix)); - QVERIFY(file4.fileName().startsWith(prefix)); + QVERIFY(fileName3.startsWith(prefix)); + QVERIFY(fileName4.startsWith(prefix)); } if (!suffix.isEmpty()) { - QVERIFY(file3.fileName().endsWith(suffix)); - QVERIFY(file4.fileName().endsWith(suffix)); - QVERIFY(file6.fileName().endsWith(suffix)); + QVERIFY(fileName3.endsWith(suffix)); + QVERIFY(fileName4.endsWith(suffix)); + QVERIFY(fileName6.endsWith(suffix)); } } } -- cgit v0.12 From d95da2fc82cdd7e5157460157b0895c209852897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Tue, 16 Aug 2011 16:02:47 +0200 Subject: Add output on test failure Reviewed-by: Shane Kearns --- tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp | 43 ++++++++++++++---------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp b/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp index 05fee95..2db5c60 100644 --- a/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp +++ b/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp @@ -412,11 +412,11 @@ void tst_QTemporaryFile::rename() { QTemporaryFile file(dir.filePath("temporary-file.XXXXXX")); - QVERIFY(file.open()); + QVERIFY2(file.open(), qPrintable(file.errorString())); tempname = file.fileName(); QVERIFY(dir.exists(tempname)); - QVERIFY(file.rename("temporary-file.txt")); + QVERIFY2(file.rename("temporary-file.txt"), qPrintable(file.errorString())); QVERIFY(!dir.exists(tempname)); QVERIFY(dir.exists("temporary-file.txt")); QCOMPARE(file.fileName(), QString("temporary-file.txt")); @@ -679,12 +679,21 @@ void tst_QTemporaryFile::QTBUG_4796() QTemporaryFile file5("test-XXXXXX/" + fileTemplate1); QTemporaryFile file6("test-XXXXXX/" + fileTemplate3); - QCOMPARE(file1.open(), openResult); - QCOMPARE(file2.open(), openResult); - QCOMPARE(file3.open(), openResult); - QCOMPARE(file4.open(), openResult); - QCOMPARE(file5.open(), openResult); - QCOMPARE(file6.open(), openResult); + if (openResult) { + QVERIFY2(file1.open(), qPrintable(file1.errorString())); + QVERIFY2(file2.open(), qPrintable(file2.errorString())); + QVERIFY2(file3.open(), qPrintable(file3.errorString())); + QVERIFY2(file4.open(), qPrintable(file4.errorString())); + QVERIFY2(file5.open(), qPrintable(file5.errorString())); + QVERIFY2(file6.open(), qPrintable(file6.errorString())); + } else { + QVERIFY(!file1.open()); + QVERIFY(!file2.open()); + QVERIFY(!file3.open()); + QVERIFY(!file4.open()); + QVERIFY(!file5.open()); + QVERIFY(!file6.open()); + } QCOMPARE(file1.exists(), openResult); QCOMPARE(file2.exists(), openResult); @@ -710,20 +719,20 @@ void tst_QTemporaryFile::QTBUG_4796() QString fileName5 = currentDir.relativeFilePath(file5.fileName()); QString fileName6 = currentDir.relativeFilePath(file6.fileName()); - QVERIFY(fileName1.startsWith(fileTemplate1 + QLatin1Char('.'))); - QVERIFY(fileName2.startsWith(fileTemplate2 + QLatin1Char('.'))); - QVERIFY(fileName5.startsWith("test-XXXXXX/" + fileTemplate1 + QLatin1Char('.'))); - QVERIFY(fileName6.startsWith("test-XXXXXX/" + prefix)); + QVERIFY2(fileName1.startsWith(fileTemplate1 + QLatin1Char('.')), qPrintable(file1.fileName())); + QVERIFY2(fileName2.startsWith(fileTemplate2 + QLatin1Char('.')), qPrintable(file2.fileName())); + QVERIFY2(fileName5.startsWith("test-XXXXXX/" + fileTemplate1 + QLatin1Char('.')), qPrintable(file5.fileName())); + QVERIFY2(fileName6.startsWith("test-XXXXXX/" + prefix), qPrintable(file6.fileName())); if (!prefix.isEmpty()) { - QVERIFY(fileName3.startsWith(prefix)); - QVERIFY(fileName4.startsWith(prefix)); + QVERIFY2(fileName3.startsWith(prefix), qPrintable(file3.fileName())); + QVERIFY2(fileName4.startsWith(prefix), qPrintable(file4.fileName())); } if (!suffix.isEmpty()) { - QVERIFY(fileName3.endsWith(suffix)); - QVERIFY(fileName4.endsWith(suffix)); - QVERIFY(fileName6.endsWith(suffix)); + QVERIFY2(fileName3.endsWith(suffix), qPrintable(file3.fileName())); + QVERIFY2(fileName4.endsWith(suffix), qPrintable(file4.fileName())); + QVERIFY2(fileName6.endsWith(suffix), qPrintable(file6.fileName())); } } } -- cgit v0.12 From a153d50eea2dea0925695a90af2c12f1887a9020 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 5 Aug 2011 10:47:01 +0200 Subject: Cleanup #includes These are already required and included by qfsfileengine_p.h. --- src/corelib/io/qtemporaryfile.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index cd6ab40..9f7cde2 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -44,10 +44,8 @@ #ifndef QT_NO_TEMPORARYFILE #include "qplatformdefs.h" -#include "qabstractfileengine.h" #include "qstringbuilder.h" #include "private/qfile_p.h" -#include "private/qabstractfileengine_p.h" #include "private/qfsfileengine_p.h" #include "private/qsystemerror_p.h" -- cgit v0.12 From 0de701d01cb221464eed773fd3751aff73fe4d60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 5 Aug 2011 10:49:44 +0200 Subject: Use "native paths" on POSIX platforms as well And don't rely solely on "local8Bit" conversions. QFile defines an API for overriding how encoding conversions are done for filenames. In generating unique names, QTemporaryFile ignored that API and hardcoded the use of local 8-bit, implicitly assuming that that was appropriate. With this change, we switch that assumption to one where user supplied encoding function keeps the byte value of 'X' and '/', also assuming that encoded 'X' takes up a single-byte (i.e., the byte sequence for "XXXXXX" remains unchanged). There was also, and there still is an assumption in name generation that byte values for ASCII alpha-numeric characters are valid in the "native" encoding. In practice this change is compatible with UTF-8, Latin-1 and other ISO/IEC 8859 encodings. At any rate, it's very likely that only UTF-8 is relevant here. Reviewed-by: Denis Dzyubenko --- src/corelib/io/qtemporaryfile.cpp | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index 9f7cde2..ac5deac 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -366,14 +366,7 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) if (!filePathIsTemplate) return QFSFileEngine::open(openMode); - const QString qfilename = -#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) - // Since the native encoding is out of our control, we need to process - // the path as UTF-16 before doing any conversions - d->fileEntry.filePath(); -#else - d->fileEntry.nativeFilePath(); -#endif + const QFileSystemEntry::NativePath qfilename = d->fileEntry.nativeFilePath(); // Find placeholder string. uint phPos = qfilename.length(); @@ -382,7 +375,7 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) while (phPos != 0) { --phPos; - if (qfilename[phPos] == QLatin1Char('X')) { + if (qfilename[phPos] == Latin1Char('X')) { ++phLength; continue; } @@ -390,7 +383,7 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) if (phLength >= 6 || qfilename[phPos] == #if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) - QLatin1Char('/') + '/' #else QLatin1Char('\\') #endif @@ -404,29 +397,12 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) QFileSystemEntry::NativePath filename; -#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) - if (phLength < 6) { - filename = qfilename.toLocal8Bit(); - - phPos = filename.length() + 1; // Account for added dot in prefix - phLength = 6; - filename = filename % '.' % Placeholder(phLength); - } else { - QByteArray prefix, suffix; - prefix = qfilename.leftRef(phPos).toLocal8Bit(); - suffix = qfilename.midRef(phPos + phLength).toLocal8Bit(); - - phPos = prefix.length(); - filename = prefix % Placeholder(phLength) % suffix; - } -#else if (phLength < 6) { phPos = qfilename.length() + 1; // Account for added dot in prefix phLength = 6; filename = qfilename % Latin1Char('.') % Placeholder(phLength); } else filename = qfilename; -#endif QSystemError error; #if defined(Q_OS_WIN) -- cgit v0.12 From 401722ef9e6fe79bd41f9d5f79668f5c4997c8e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Tue, 16 Aug 2011 17:53:41 +0200 Subject: Fix QTemporaryFile regressions and new found issues With this change, the file template is always processed in original QString format. Trying to generate native paths before adding a missing placeholder mask could change the meaning of templates, such as "." and "..", which are now tested to mean "..XXXXXX" and "...XXXXXX", respectively. After ensuring the template includes a placeholder mask, the path is converted to a native *absolute* file path and the mask is sought for again. On Windows, native paths were already absolute. On Symbian, we'd need at least a clean path, as "." and ",," are not natively understood. There is a requirement that the placeholder mask /XXXXXX+/ makes it through this conversion unaltered, which relaxes prior requirements on *nix platforms. On Windows and Symbian the conversion is under Qt's control and not user-configurable. Reviewed-by: Shane Kearns --- src/corelib/io/qtemporaryfile.cpp | 84 ++++++++++-------------- tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp | 2 + 2 files changed, 36 insertions(+), 50 deletions(-) diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index ac5deac..375d07f 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -44,10 +44,10 @@ #ifndef QT_NO_TEMPORARYFILE #include "qplatformdefs.h" -#include "qstringbuilder.h" #include "private/qfile_p.h" #include "private/qfsfileengine_p.h" #include "private/qsystemerror_p.h" +#include "private/qfilesystemengine_p.h" #if defined(Q_OS_SYMBIAN) #include "private/qcore_symbian_p.h" @@ -102,38 +102,6 @@ typedef char Latin1Char; typedef int NativeFileHandle; #endif -struct Placeholder -{ - Placeholder(int size) - : size_(size) - { - } - - int size() const - { - return size_; - } - -private: - int size_; -}; - -template <> -struct QConcatenable -{ - typedef Placeholder type; - typedef QByteArray ConvertTo; - enum { ExactSize = true }; - static int size(const Placeholder &p) { return p.size(); } - - template - static inline void appendTo(const Placeholder &p, CharT *&out) - { - // Uninitialized - out += p.size(); - } -}; - /* * Copyright (c) 1987, 1993 * The Regents of the University of California. All rights reserved. @@ -366,43 +334,59 @@ bool QTemporaryFileEngine::open(QIODevice::OpenMode openMode) if (!filePathIsTemplate) return QFSFileEngine::open(openMode); - const QFileSystemEntry::NativePath qfilename = d->fileEntry.nativeFilePath(); + QString qfilename = d->fileEntry.filePath(); - // Find placeholder string. + // Ensure there is a placeholder mask uint phPos = qfilename.length(); uint phLength = 0; while (phPos != 0) { --phPos; - if (qfilename[phPos] == Latin1Char('X')) { + if (qfilename[phPos] == QLatin1Char('X')) { ++phLength; continue; } if (phLength >= 6 - || qfilename[phPos] == -#if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN) - '/' -#else - QLatin1Char('\\') -#endif - ) { + || qfilename[phPos] == QLatin1Char('/')) { ++phPos; break; } + // start over phLength = 0; } - QFileSystemEntry::NativePath filename; + if (phLength < 6) + qfilename.append(QLatin1String(".XXXXXX")); + + // "Nativify" :-) + QFileSystemEntry::NativePath filename = QFileSystemEngine::absoluteName( + QFileSystemEntry(qfilename, QFileSystemEntry::FromInternalPath())) + .nativeFilePath(); + + // Find mask in native path + phPos = filename.length(); + phLength = 0; + while (phPos != 0) { + --phPos; + + if (filename[phPos] == Latin1Char('X')) { + ++phLength; + continue; + } + + if (phLength >= 6) { + ++phPos; + break; + } + + // start over + phLength = 0; + } - if (phLength < 6) { - phPos = qfilename.length() + 1; // Account for added dot in prefix - phLength = 6; - filename = qfilename % Latin1Char('.') % Placeholder(phLength); - } else - filename = qfilename; + Q_ASSERT(phLength >= 6); QSystemError error; #if defined(Q_OS_WIN) diff --git a/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp b/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp index 2db5c60..18b9337 100644 --- a/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp +++ b/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp @@ -632,6 +632,8 @@ void tst_QTemporaryFile::QTBUG_4796_data() QString unicode = QString::fromUtf8("\xc3\xa5\xc3\xa6\xc3\xb8"); QTest::newRow("") << QString() << QString() << true; + QTest::newRow(".") << QString(".") << QString() << true; + QTest::newRow("..") << QString("..") << QString() << true; QTest::newRow("blaXXXXXX") << QString("bla") << QString() << true; QTest::newRow("XXXXXXbla") << QString() << QString("bla") << true; QTest::newRow("does-not-exist/qt_temp.XXXXXX") << QString("does-not-exist/qt_temp") << QString() << false; -- cgit v0.12 From 98f0e52547f6f840e386740dc6c2d99452965266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Wed, 17 Aug 2011 14:38:27 +0200 Subject: Cleanup code: removing empty stubs Reviewed-by: Shane Kearns --- tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp | 29 ------------------------ 1 file changed, 29 deletions(-) diff --git a/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp b/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp index 18b9337..11b2bb3 100644 --- a/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp +++ b/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp @@ -69,13 +69,7 @@ class tst_QTemporaryFile : public QObject { Q_OBJECT -public: - tst_QTemporaryFile(); - virtual ~tst_QTemporaryFile(); public slots: - void init(); - void cleanup(); - void initTestCase(); void cleanupTestCase(); @@ -103,8 +97,6 @@ private slots: void QTBUG_4796_data(); void QTBUG_4796(); - -public: }; void tst_QTemporaryFile::initTestCase() @@ -139,27 +131,6 @@ void tst_QTemporaryFile::getSetCheck() QCOMPARE(true, obj1.autoRemove()); } -tst_QTemporaryFile::tst_QTemporaryFile() -{ -} - -tst_QTemporaryFile::~tst_QTemporaryFile() -{ - -} - -void tst_QTemporaryFile::init() -{ -// TODO: Add initialization code here. -// This will be executed immediately before each test is run. -} - -void tst_QTemporaryFile::cleanup() -{ -// TODO: Add cleanup code here. -// This will be executed immediately after each test is run. -} - void tst_QTemporaryFile::fileTemplate_data() { QTest::addColumn("constructorTemplate"); -- cgit v0.12 From 4e2b245df03b79df272318092a63a4a3708ba3b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Wed, 17 Aug 2011 14:43:18 +0200 Subject: Merged fileTemplate test with QTBUG_4796 The latter was more thorough, but didn't test setting the file template after construction, while the former included some prefix/suffix combinations that weren't specifically tested in the latter. Reviewed-by: Shane Kearns --- tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp | 116 ++++++++++------------- 1 file changed, 48 insertions(+), 68 deletions(-) diff --git a/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp b/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp index 11b2bb3..c9d4ba4 100644 --- a/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp +++ b/tests/auto/qtemporaryfile/tst_qtemporaryfile.cpp @@ -94,20 +94,17 @@ private slots: void resetTemplateAfterError(); void setTemplateAfterOpen(); void autoRemoveAfterFailedRename(); - - void QTBUG_4796_data(); - void QTBUG_4796(); }; void tst_QTemporaryFile::initTestCase() { - // For QTBUG_4796 + // For fileTemplate tests QVERIFY(QDir("test-XXXXXX").exists() || QDir().mkdir("test-XXXXXX")); } void tst_QTemporaryFile::cleanupTestCase() { - // From QTBUG_4796 + // From fileTemplate tests QVERIFY(QDir().rmdir("test-XXXXXX")); } @@ -131,56 +128,6 @@ void tst_QTemporaryFile::getSetCheck() QCOMPARE(true, obj1.autoRemove()); } -void tst_QTemporaryFile::fileTemplate_data() -{ - QTest::addColumn("constructorTemplate"); - QTest::addColumn("prefix"); - QTest::addColumn("suffix"); - QTest::addColumn("fileTemplate"); - - QTest::newRow("constructor default") << "" << "." << "" << ""; - QTest::newRow("constructor with xxx sufix") << "qt_XXXXXXxxx" << "qt_" << "xxx" << ""; - QTest::newRow("constructor with xXx sufix") << "qt_XXXXXXxXx" << "qt_" << "xXx" << ""; - QTest::newRow("constructor with no sufix") << "qt_XXXXXX" << "qt_" << "" << ""; - QTest::newRow("constructor with >6 X's and xxx suffix") << "qt_XXXXXXXXXXxxx" << "qt_" << "xxx" << ""; - QTest::newRow("constructor with >6 X's, no suffix") << "qt_XXXXXXXXXX" << "qt_" << "" << ""; - - QTest::newRow("constructor with XXXX suffix") << "qt_XXXXXX_XXXX" << "qt_" << "_XXXX" << ""; - QTest::newRow("constructor with XXXXX suffix") << "qt_XXXXXX_XXXXX" << "qt_" << "_XXXXX" << ""; - QTest::newRow("constructor with XXXX prefix") << "qt_XXXX" << "qt_XXXX." << "" << ""; - QTest::newRow("constructor with XXXXX prefix") << "qt_XXXXX" << "qt_XXXXX." << "" << ""; - QTest::newRow("constructor with XXXX prefix and suffix") << "qt_XXXX_XXXXXX_XXXX" << "qt_XXXX_" << "_XXXX" << ""; - QTest::newRow("constructor with XXXXX prefix and suffix") << "qt_XXXXX_XXXXXX_XXXXX" << "qt_XXXXX_" << "_XXXXX" << ""; - - QTest::newRow("set template, no suffix") << "" << "foo" << "" << "foo"; - QTest::newRow("set template, with lowercase XXXXXX") << "" << "qt_" << "xxxxxx" << "qt_XXXXXXxxxxxx"; - QTest::newRow("set template, with xxx") << "" << "qt_" << ".xxx" << "qt_XXXXXX.xxx"; - QTest::newRow("set template, with >6 X's") << "" << "qt_" << ".xxx" << "qt_XXXXXXXXXXXXXX.xxx"; - QTest::newRow("set template, with >6 X's, no suffix") << "" << "qt_" << "" << "qt_XXXXXXXXXXXXXX"; -} - -void tst_QTemporaryFile::fileTemplate() -{ - QFETCH(QString, constructorTemplate); - QFETCH(QString, prefix); - QFETCH(QString, suffix); - QFETCH(QString, fileTemplate); - - QTemporaryFile file(constructorTemplate); - if (!fileTemplate.isEmpty()) - file.setFileTemplate(fileTemplate); - - QCOMPARE(file.open(), true); - - QString fileName = QFileInfo(file).fileName(); - if (prefix.length()) - QCOMPARE(fileName.left(prefix.length()), prefix); - - if (suffix.length()) - QCOMPARE(fileName.right(suffix.length()), suffix); -} - - /* This tests whether the temporary file really gets placed in QDir::tempPath */ @@ -594,7 +541,7 @@ void tst_QTemporaryFile::autoRemoveAfterFailedRename() cleaner.reset(); } -void tst_QTemporaryFile::QTBUG_4796_data() +void tst_QTemporaryFile::fileTemplate_data() { QTest::addColumn("prefix"); QTest::addColumn("suffix"); @@ -603,17 +550,33 @@ void tst_QTemporaryFile::QTBUG_4796_data() QString unicode = QString::fromUtf8("\xc3\xa5\xc3\xa6\xc3\xb8"); QTest::newRow("") << QString() << QString() << true; + QTest::newRow(".") << QString(".") << QString() << true; QTest::newRow("..") << QString("..") << QString() << true; + + QTest::newRow("foo") << QString("foo") << QString() << true; + QTest::newRow("qt_ ... xxxxxx") << QString("qt_") << QString("xxxxxx") << true; + QTest::newRow("qt_ ... xxx") << QString("qt_") << QString("xxx") << true; + QTest::newRow("qt_ ... xXx") << QString("qt_") << QString("xXx") << true; + QTest::newRow("qt_ ...") << QString("qt_") << QString() << true; + QTest::newRow("qt_ ... _XXXX") << QString("qt_") << QString("_XXXX") << true; + QTest::newRow("qt_ ... _XXXXX") << QString("qt_") << QString("_XXXXX") << true; + QTest::newRow("qt_XXXX_ ...") << QString("qt_XXXX_") << QString() << true; + QTest::newRow("qt_XXXXX_ ...") << QString("qt_XXXXX_") << QString() << true; + QTest::newRow("qt_XXXX_ ... _XXXX") << QString("qt_XXXX_") << QString("_XXXX") << true; + QTest::newRow("qt_XXXXX_ ... _XXXXX") << QString("qt_XXXXX_") << QString("_XXXXX") << true; + QTest::newRow("blaXXXXXX") << QString("bla") << QString() << true; QTest::newRow("XXXXXXbla") << QString() << QString("bla") << true; + QTest::newRow("does-not-exist/qt_temp.XXXXXX") << QString("does-not-exist/qt_temp") << QString() << false; + QTest::newRow("XXXXXX") << QString() << unicode << true; QTest::newRow("XXXXXX") << unicode << QString() << true; QTest::newRow("XXXXXX") << unicode << unicode << true; } -void tst_QTemporaryFile::QTBUG_4796() +void tst_QTemporaryFile::fileTemplate() { QVERIFY(QDir("test-XXXXXX").exists()); @@ -639,18 +602,40 @@ void tst_QTemporaryFile::QTBUG_4796() QFETCH(QString, suffix); QFETCH(bool, openResult); + enum IterationType { + UseConstructor, + UseSetFileTemplate, + Done + }; + + for (IterationType setFileTemplate = UseConstructor; setFileTemplate != Done; + setFileTemplate = IterationType(int(setFileTemplate) + 1)) { + Q_FOREACH(QString const &tempName, cleaner.tempNames) + QVERIFY( !QFile::exists(tempName) ); + + cleaner.reset(); + QString fileTemplate1 = prefix + QString("XX") + suffix; QString fileTemplate2 = prefix + QString("XXXX") + suffix; QString fileTemplate3 = prefix + QString("XXXXXX") + suffix; QString fileTemplate4 = prefix + QString("XXXXXXXX") + suffix; - QTemporaryFile file1(fileTemplate1); - QTemporaryFile file2(fileTemplate2); - QTemporaryFile file3(fileTemplate3); - QTemporaryFile file4(fileTemplate4); - QTemporaryFile file5("test-XXXXXX/" + fileTemplate1); - QTemporaryFile file6("test-XXXXXX/" + fileTemplate3); + QTemporaryFile file1(setFileTemplate ? QString() : fileTemplate1); + QTemporaryFile file2(setFileTemplate ? QString() : fileTemplate2); + QTemporaryFile file3(setFileTemplate ? QString() : fileTemplate3); + QTemporaryFile file4(setFileTemplate ? QString() : fileTemplate4); + QTemporaryFile file5(setFileTemplate ? QString() : "test-XXXXXX/" + fileTemplate1); + QTemporaryFile file6(setFileTemplate ? QString() : "test-XXXXXX/" + fileTemplate3); + + if (setFileTemplate) { + file1.setFileTemplate(fileTemplate1); + file2.setFileTemplate(fileTemplate2); + file3.setFileTemplate(fileTemplate3); + file4.setFileTemplate(fileTemplate4); + file5.setFileTemplate("test-XXXXXX/" + fileTemplate1); + file6.setFileTemplate("test-XXXXXX/" + fileTemplate3); + } if (openResult) { QVERIFY2(file1.open(), qPrintable(file1.errorString())); @@ -709,11 +694,6 @@ void tst_QTemporaryFile::QTBUG_4796() } } } - - Q_FOREACH(QString const &tempName, cleaner.tempNames) - QVERIFY( !QFile::exists(tempName) ); - - cleaner.reset(); } QTEST_MAIN(tst_QTemporaryFile) -- cgit v0.12 From 9e656ce0f7bda4bca4ae55a7aefe1617bc2805ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Thu, 18 Aug 2011 11:08:26 +0200 Subject: Leftovers from 401722ef9e6fe79bd41f9d5f79668f5c4997c8e6 This no longer necessary template specialization went unnoticed inside the Windows/Symbian #ifdef. It breaks compilation on those platforms, now that qstringbuilder.h is not included and QConcatenable is unknown to the compiler. --- src/corelib/io/qtemporaryfile.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index 375d07f..ea5f8a5 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -72,20 +72,6 @@ static inline Char Latin1Char(char ch) return ushort(uchar(ch)); } -template <> -struct QConcatenable -{ - typedef Char type; - typedef QString ConvertTo; - enum { ExactSize = true }; - static int size(const Char &) { return 1; } - - static inline void appendTo(const Char &u16, QChar *&out) - { - *out++ = QChar(u16); - } -}; - # ifdef Q_OS_WIN typedef HANDLE NativeFileHandle; # else // Q_OS_SYMBIAN -- cgit v0.12 From 7b693627ee2a17718cb6d8bee5e3deb5a97b307f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Mon, 22 Aug 2011 11:30:26 +0200 Subject: Off-by-one error in assert condition... While this was safe, it was also over-zealous, disallowing the path from ending with the placeholder... Incidentally, the default. Laughed-at-by: w00t_ --- src/corelib/io/qtemporaryfile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/io/qtemporaryfile.cpp b/src/corelib/io/qtemporaryfile.cpp index ea5f8a5..e80a8b6 100644 --- a/src/corelib/io/qtemporaryfile.cpp +++ b/src/corelib/io/qtemporaryfile.cpp @@ -135,7 +135,7 @@ static bool createFileFromTemplate(NativeFileHandle &file, { Q_ASSERT(length != 0); Q_ASSERT(pos < size_t(path.length())); - Q_ASSERT(length < size_t(path.length()) - pos); + Q_ASSERT(length <= size_t(path.length()) - pos); Char *const placeholderStart = (Char *)path.data() + pos; Char *const placeholderEnd = placeholderStart + length; -- cgit v0.12 From 2c198b3ace2fb09ed0eaa45aec6ce2c96a45aafb Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Mon, 22 Aug 2011 11:31:22 +1000 Subject: Fix left alignment of native RTL pre-edit text. If there is no committed text in a TextInput or TextEdit determine if the pre-edit text is right to left before falling back to the global keyboard settings. Change-Id: I7e5568e936341602b8faf7be120f9a770c115f48 Task-number: QMLNG-72 Reviewed-by: Michael Brasser --- src/declarative/graphicsitems/qdeclarativetextedit.cpp | 11 ++++++++++- src/declarative/graphicsitems/qdeclarativetextinput.cpp | 7 ++++++- .../data/horizontalAlignment_RightToLeft.qml | 1 + .../qdeclarativetextedit/tst_qdeclarativetextedit.cpp | 12 ++++++++++++ .../data/horizontalAlignment_RightToLeft.qml | 1 + .../qdeclarativetextinput/tst_qdeclarativetextinput.cpp | 13 +++++++++++++ 6 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/declarative/graphicsitems/qdeclarativetextedit.cpp b/src/declarative/graphicsitems/qdeclarativetextedit.cpp index 42c520c..cc5279a 100644 --- a/src/declarative/graphicsitems/qdeclarativetextedit.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextedit.cpp @@ -547,7 +547,15 @@ bool QDeclarativeTextEditPrivate::determineHorizontalAlignment() { Q_Q(QDeclarativeTextEdit); if (hAlignImplicit && q->isComponentComplete()) { - bool alignToRight = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText; + bool alignToRight; + if (text.isEmpty()) { + const QString preeditText = control->textCursor().block().layout()->preeditAreaText(); + alignToRight = preeditText.isEmpty() + ? QApplication::keyboardInputDirection() == Qt::RightToLeft + : preeditText.isRightToLeft(); + } else { + alignToRight = rightToLeftText; + } return setHAlign(alignToRight ? QDeclarativeTextEdit::AlignRight : QDeclarativeTextEdit::AlignLeft); } return false; @@ -1582,6 +1590,7 @@ void QDeclarativeTextEdit::q_textChanged() void QDeclarativeTextEdit::moveCursorDelegate() { Q_D(QDeclarativeTextEdit); + d->determineHorizontalAlignment(); updateMicroFocus(); emit cursorRectangleChanged(); if(!d->cursor) diff --git a/src/declarative/graphicsitems/qdeclarativetextinput.cpp b/src/declarative/graphicsitems/qdeclarativetextinput.cpp index f68f1c6..c5c9f5e 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextinput.cpp @@ -407,7 +407,11 @@ bool QDeclarativeTextInputPrivate::determineHorizontalAlignment() if (hAlignImplicit) { // if no explicit alignment has been set, follow the natural layout direction of the text QString text = control->text(); - bool isRightToLeft = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : text.isRightToLeft(); + if (text.isEmpty()) + text = control->preeditAreaText(); + bool isRightToLeft = text.isEmpty() + ? QApplication::keyboardInputDirection() == Qt::RightToLeft + : text.isRightToLeft(); return setHAlign(isRightToLeft ? QDeclarativeTextInput::AlignRight : QDeclarativeTextInput::AlignLeft); } return false; @@ -1909,6 +1913,7 @@ void QDeclarativeTextInput::cursorPosChanged() void QDeclarativeTextInput::updateCursorRectangle() { Q_D(QDeclarativeTextInput); + d->determineHorizontalAlignment(); d->updateHorizontalScroll(); updateRect();//TODO: Only update rect between pos's updateMicroFocus(); diff --git a/tests/auto/declarative/qdeclarativetextedit/data/horizontalAlignment_RightToLeft.qml b/tests/auto/declarative/qdeclarativetextedit/data/horizontalAlignment_RightToLeft.qml index 43ea8d8..6e739bf 100644 --- a/tests/auto/declarative/qdeclarativetextedit/data/horizontalAlignment_RightToLeft.qml +++ b/tests/auto/declarative/qdeclarativetextedit/data/horizontalAlignment_RightToLeft.qml @@ -18,6 +18,7 @@ Rectangle { objectName: "text" anchors.fill: parent text: top.text + focus: true } } } diff --git a/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp b/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp index 5d6f2a2..5c7f36f 100644 --- a/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp +++ b/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp @@ -454,6 +454,8 @@ void tst_qdeclarativetextedit::hAlign_RightToLeft() QVERIFY(textEdit != 0); canvas->show(); + const QString rtlText = textEdit->text(); + // implicit alignment should follow the reading direction of text QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignRight); QVERIFY(textEdit->positionToRectangle(0).x() > canvas->width()/2); @@ -530,6 +532,16 @@ void tst_qdeclarativetextedit::hAlign_RightToLeft() QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignLeft); QVERIFY(textEdit->positionToRectangle(0).x() < canvas->width()/2); + QApplication::setActiveWindow(canvas); + QTest::qWaitForWindowShown(canvas); + QTRY_COMPARE(QApplication::activeWindow(), static_cast(canvas)); + + textEdit->setText(QString()); + { QInputMethodEvent ev(rtlText, QList()); QApplication::sendEvent(canvas, &ev); } + QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignRight); + { QInputMethodEvent ev("Hello world!", QList()); QApplication::sendEvent(canvas, &ev); } + QCOMPARE(textEdit->hAlign(), QDeclarativeTextEdit::AlignLeft); + #ifndef Q_OS_MAC // QTBUG-18040 // empty text with implicit alignment follows the system locale-based // keyboard input direction from QApplication::keyboardInputDirection diff --git a/tests/auto/declarative/qdeclarativetextinput/data/horizontalAlignment_RightToLeft.qml b/tests/auto/declarative/qdeclarativetextinput/data/horizontalAlignment_RightToLeft.qml index b11535e..7f27bbe 100644 --- a/tests/auto/declarative/qdeclarativetextinput/data/horizontalAlignment_RightToLeft.qml +++ b/tests/auto/declarative/qdeclarativetextinput/data/horizontalAlignment_RightToLeft.qml @@ -18,6 +18,7 @@ Rectangle { objectName: "text" anchors.fill: parent text: top.text + focus: true } } } diff --git a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp index 280f952..7f3b8a2 100644 --- a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp +++ b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp @@ -1198,6 +1198,8 @@ void tst_qdeclarativetextinput::horizontalAlignment_RightToLeft() QVERIFY(textInput != 0); canvas->show(); + const QString rtlText = textInput->text(); + QDeclarativeTextInputPrivate *textInputPrivate = QDeclarativeTextInputPrivate::get(textInput); QVERIFY(textInputPrivate != 0); QVERIFY(-textInputPrivate->hscroll > canvas->width()/2); @@ -1262,6 +1264,17 @@ void tst_qdeclarativetextinput::horizontalAlignment_RightToLeft() QCOMPARE(textInput->hAlign(), QDeclarativeTextInput::AlignLeft); QVERIFY(-textInputPrivate->hscroll < canvas->width()/2); + QApplication::setActiveWindow(canvas); + QTest::qWaitForWindowShown(canvas); + QTRY_COMPARE(QApplication::activeWindow(), static_cast(canvas)); + + // If there is no commited text, the preedit text should determine the alignment. + textInput->setText(QString()); + { QInputMethodEvent ev(rtlText, QList()); QApplication::sendEvent(canvas, &ev); } + QCOMPARE(textInput->hAlign(), QDeclarativeTextInput::AlignRight); + { QInputMethodEvent ev("Hello world!", QList()); QApplication::sendEvent(canvas, &ev); } + QCOMPARE(textInput->hAlign(), QDeclarativeTextInput::AlignLeft); + #ifndef Q_OS_MAC // QTBUG-18040 // empty text with implicit alignment follows the system locale-based // keyboard input direction from QApplication::keyboardInputDirection -- cgit v0.12 From 0b19ee5ecabfc516256f0a6db0f2e7bc37e703a0 Mon Sep 17 00:00:00 2001 From: Sami Merila Date: Tue, 23 Aug 2011 14:55:46 +0300 Subject: In landscape mode QComboboBox popup can not be showed completely ComboBox popups have regressed in 4.7.4 lately. Combobox popup is shown as smallish square rectangle in landscape orientation. As a fix, let the width of the popup match the height of the screen (native dialogs most of the time have width matching the height of the screen). Task-number: QTBUG-20932 Reviewed-by: Miikka Heikkinen --- src/gui/widgets/qcombobox.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/widgets/qcombobox.cpp b/src/gui/widgets/qcombobox.cpp index f4a627b..8a69bdf 100644 --- a/src/gui/widgets/qcombobox.cpp +++ b/src/gui/widgets/qcombobox.cpp @@ -2473,7 +2473,7 @@ void QComboBox::showPopup() } else { TRect staConTopRect = TRect(); AknLayoutUtils::LayoutMetricsRect(AknLayoutUtils::EStaconTop, staConTopRect); - listRect.setWidth(listRect.height()); + listRect.setWidth(screen.height()); //by default popup is centered on screen in landscape listRect.moveCenter(screen.center()); if (staConTopRect.IsEmpty()) { -- cgit v0.12 From 1ee6ff9fab218a8fa02a3cad1614730eb716bf45 Mon Sep 17 00:00:00 2001 From: Sergio Ahumada Date: Tue, 23 Aug 2011 20:13:43 +0200 Subject: Doc: Fixing typo --- .../declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp index 7f3b8a2..bb895bf 100644 --- a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp +++ b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp @@ -1268,7 +1268,7 @@ void tst_qdeclarativetextinput::horizontalAlignment_RightToLeft() QTest::qWaitForWindowShown(canvas); QTRY_COMPARE(QApplication::activeWindow(), static_cast(canvas)); - // If there is no commited text, the preedit text should determine the alignment. + // If there is no committed text, the preedit text should determine the alignment. textInput->setText(QString()); { QInputMethodEvent ev(rtlText, QList()); QApplication::sendEvent(canvas, &ev); } QCOMPARE(textInput->hAlign(), QDeclarativeTextInput::AlignRight); -- cgit v0.12 From 33eb83565466d3dc31ea90dcf18dc3c7b16fd5b6 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Wed, 24 Aug 2011 11:26:29 +1000 Subject: Make it easier to select words at the start of a line. QTextControl's word selection will only include a word if the cursor position is past the mid point of the word. This can make it difficult to select words near the edges of the screen on touch devices. For the TextEdit word selection mode select a word ignore the relative position within a word. Change-Id: I2bc61376f663836fedd7e157448f0b565a64d485 Task-number: QT-5206 Reviewed-by: Martin Jones --- src/gui/text/qtextcontrol.cpp | 34 +++++++++------ .../data/mouseselection_false_words.qml | 5 ++- .../data/mouseselection_true_words.qml | 5 ++- .../tst_qdeclarativetextedit.cpp | 49 ++++++++++++---------- 4 files changed, 56 insertions(+), 37 deletions(-) diff --git a/src/gui/text/qtextcontrol.cpp b/src/gui/text/qtextcontrol.cpp index 9081ab7..f3d42f8 100644 --- a/src/gui/text/qtextcontrol.cpp +++ b/src/gui/text/qtextcontrol.cpp @@ -679,20 +679,30 @@ void QTextControlPrivate::extendWordwiseSelection(int suggestedNewPosition, qrea if (!wordSelectionEnabled && (mouseXPosition < wordStartX || mouseXPosition > wordEndX)) return; - // keep the already selected word even when moving to the left - // (#39164) - if (suggestedNewPosition < selectedWordOnDoubleClick.position()) - cursor.setPosition(selectedWordOnDoubleClick.selectionEnd()); - else - cursor.setPosition(selectedWordOnDoubleClick.selectionStart()); + if (wordSelectionEnabled) { + if (suggestedNewPosition < selectedWordOnDoubleClick.position()) { + cursor.setPosition(selectedWordOnDoubleClick.selectionEnd()); + setCursorPosition(wordStartPos, QTextCursor::KeepAnchor); + } else { + cursor.setPosition(selectedWordOnDoubleClick.selectionStart()); + setCursorPosition(wordEndPos, QTextCursor::KeepAnchor); + } + } else { + // keep the already selected word even when moving to the left + // (#39164) + if (suggestedNewPosition < selectedWordOnDoubleClick.position()) + cursor.setPosition(selectedWordOnDoubleClick.selectionEnd()); + else + cursor.setPosition(selectedWordOnDoubleClick.selectionStart()); - const qreal differenceToStart = mouseXPosition - wordStartX; - const qreal differenceToEnd = wordEndX - mouseXPosition; + const qreal differenceToStart = mouseXPosition - wordStartX; + const qreal differenceToEnd = wordEndX - mouseXPosition; - if (differenceToStart < differenceToEnd) - setCursorPosition(wordStartPos, QTextCursor::KeepAnchor); - else - setCursorPosition(wordEndPos, QTextCursor::KeepAnchor); + if (differenceToStart < differenceToEnd) + setCursorPosition(wordStartPos, QTextCursor::KeepAnchor); + else + setCursorPosition(wordEndPos, QTextCursor::KeepAnchor); + } if (interactionFlags & Qt::TextSelectableByMouse) { #ifndef QT_NO_CLIPBOARD diff --git a/tests/auto/declarative/qdeclarativetextedit/data/mouseselection_false_words.qml b/tests/auto/declarative/qdeclarativetextedit/data/mouseselection_false_words.qml index 22a9871..f8d2e4e 100644 --- a/tests/auto/declarative/qdeclarativetextedit/data/mouseselection_false_words.qml +++ b/tests/auto/declarative/qdeclarativetextedit/data/mouseselection_false_words.qml @@ -1,7 +1,8 @@ -import QtQuick 1.0 +import QtQuick 1.1 TextEdit { focus: true - text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" + text: "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" selectByMouse: false + mouseSelectionMode: TextEdit.SelectWords } diff --git a/tests/auto/declarative/qdeclarativetextedit/data/mouseselection_true_words.qml b/tests/auto/declarative/qdeclarativetextedit/data/mouseselection_true_words.qml index d61da46..f58fd45 100644 --- a/tests/auto/declarative/qdeclarativetextedit/data/mouseselection_true_words.qml +++ b/tests/auto/declarative/qdeclarativetextedit/data/mouseselection_true_words.qml @@ -1,7 +1,8 @@ -import QtQuick 1.0 +import QtQuick 1.1 TextEdit { focus: true - text: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" + text: "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ" selectByMouse: true + mouseSelectionMode: TextEdit.SelectWords } diff --git a/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp b/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp index 5c7f36f..fde0588 100644 --- a/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp +++ b/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp @@ -1327,20 +1327,32 @@ void tst_qdeclarativetextedit::moveCursorSelectionSequence() void tst_qdeclarativetextedit::mouseSelection_data() { QTest::addColumn("qmlfile"); - QTest::addColumn("expectSelection"); + QTest::addColumn("from"); + QTest::addColumn("to"); + QTest::addColumn("selectedText"); // import installed - QTest::newRow("on") << SRCDIR "/data/mouseselection_true.qml" << true; - QTest::newRow("off") << SRCDIR "/data/mouseselection_false.qml" << false; - QTest::newRow("default") << SRCDIR "/data/mouseselection_default.qml" << false; - QTest::newRow("on word selection") << SRCDIR "/data/mouseselection_true_words.qml" << true; - QTest::newRow("off word selection") << SRCDIR "/data/mouseselection_false_words.qml" << false; + QTest::newRow("on") << SRCDIR "/data/mouseselection_true.qml" << 4 << 9 << "45678"; + QTest::newRow("off") << SRCDIR "/data/mouseselection_false.qml" << 4 << 9 << QString(); + QTest::newRow("default") << SRCDIR "/data/mouseselection_default.qml" << 4 << 9 << QString(); + QTest::newRow("off word selection") << SRCDIR "/data/mouseselection_false_words.qml" << 4 << 9 << QString(); + QTest::newRow("on word selection (4,9)") << SRCDIR "/data/mouseselection_true_words.qml" << 4 << 9 << "0123456789"; + QTest::newRow("on word selection (2,13)") << SRCDIR "/data/mouseselection_true_words.qml" << 2 << 13 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + QTest::newRow("on word selection (2,30)") << SRCDIR "/data/mouseselection_true_words.qml" << 2 << 30 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + QTest::newRow("on word selection (9,13)") << SRCDIR "/data/mouseselection_true_words.qml" << 9 << 13 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + QTest::newRow("on word selection (9,30)") << SRCDIR "/data/mouseselection_true_words.qml" << 9 << 30 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + QTest::newRow("on word selection (13,2)") << SRCDIR "/data/mouseselection_true_words.qml" << 13 << 2 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + QTest::newRow("on word selection (20,2)") << SRCDIR "/data/mouseselection_true_words.qml" << 20 << 2 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + QTest::newRow("on word selection (12,9)") << SRCDIR "/data/mouseselection_true_words.qml" << 12 << 9 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + QTest::newRow("on word selection (30,9)") << SRCDIR "/data/mouseselection_true_words.qml" << 30 << 9 << "0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ"; } void tst_qdeclarativetextedit::mouseSelection() { QFETCH(QString, qmlfile); - QFETCH(bool, expectSelection); + QFETCH(int, from); + QFETCH(int, to); + QFETCH(QString, selectedText); QDeclarativeView *canvas = createView(qmlfile); @@ -1354,25 +1366,20 @@ void tst_qdeclarativetextedit::mouseSelection() QVERIFY(textEditObject != 0); // press-and-drag-and-release from x1 to x2 - int x1 = 10; - int x2 = 70; - int y = textEditObject->height()/2; - QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x1,y))); + QPoint p1 = canvas->mapFromScene(textEditObject->positionToRectangle(from).center()); + QPoint p2 = canvas->mapFromScene(textEditObject->positionToRectangle(to).center()); + QTest::mousePress(canvas->viewport(), Qt::LeftButton, 0, p1); //QTest::mouseMove(canvas->viewport(), canvas->mapFromScene(QPoint(x2,y))); // doesn't work - QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(QPoint(x2,y)), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); + QMouseEvent mv(QEvent::MouseMove, canvas->mapFromScene(p2), Qt::LeftButton, Qt::LeftButton,Qt::NoModifier); QApplication::sendEvent(canvas->viewport(), &mv); - QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, canvas->mapFromScene(QPoint(x2,y))); - QString str = textEditObject->selectedText(); - if (expectSelection) - QVERIFY(str.length() > 3); // don't reallly care *what* was selected (and it's too sensitive to platform) - else - QVERIFY(str.isEmpty()); + QTest::mouseRelease(canvas->viewport(), Qt::LeftButton, 0, p2); + QCOMPARE(textEditObject->selectedText(), selectedText); // Clicking and shift to clicking between the same points should select the same text. textEditObject->setCursorPosition(0); - QTest::mouseClick(canvas->viewport(), Qt::LeftButton, Qt::NoModifier, canvas->mapFromScene(QPoint(x1,y))); - QTest::mouseClick(canvas->viewport(), Qt::LeftButton, Qt::ShiftModifier, canvas->mapFromScene(QPoint(x2,y))); - QCOMPARE(textEditObject->selectedText(), str); + QTest::mouseClick(canvas->viewport(), Qt::LeftButton, Qt::NoModifier, p1); + QTest::mouseClick(canvas->viewport(), Qt::LeftButton, Qt::ShiftModifier, p2); + QCOMPARE(textEditObject->selectedText(), selectedText); delete canvas; } -- cgit v0.12 From 4eb50fbbf414103fb2f9dfb8260f4db5d61190c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Niemel=C3=A4?= Date: Wed, 24 Aug 2011 15:29:17 +0300 Subject: Fix for qml1shaderplugin GPU resource handling on Symbian qml1shaderplugin now automatically recovers from situations when GL context is destroyed and related FBOs and shaderprograms become invalid. Additionally the shaderprograms are created lazily so that no GPU memory is used if items are not visible. Task-number: QTBUG-20724 QTBUG-20736 Reviewed-by: Jani Hautakangas --- src/imports/shaders/shadereffectitem.cpp | 110 ++++++++++++++++++++++------- src/imports/shaders/shadereffectitem.h | 4 +- src/imports/shaders/shadereffectsource.cpp | 43 ++++++----- src/imports/shaders/shadereffectsource.h | 3 +- 4 files changed, 116 insertions(+), 44 deletions(-) mode change 100644 => 100755 src/imports/shaders/shadereffectitem.cpp diff --git a/src/imports/shaders/shadereffectitem.cpp b/src/imports/shaders/shadereffectitem.cpp old mode 100644 new mode 100755 index 056581c..04c81f5 --- a/src/imports/shaders/shadereffectitem.cpp +++ b/src/imports/shaders/shadereffectitem.cpp @@ -199,8 +199,13 @@ Rectangle { */ +#ifdef Q_OS_SYMBIAN +#define OBSERVE_GL_CONTEXT_LOSS 1 +#endif + ShaderEffectItem::ShaderEffectItem(QDeclarativeItem *parent) : QDeclarativeItem(parent) + , m_program(0) , m_meshResolution(1, 1) , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4) , m_blending(true) @@ -214,15 +219,21 @@ ShaderEffectItem::ShaderEffectItem(QDeclarativeItem *parent) , m_hasShaderPrograms(false) , m_mirrored(false) , m_defaultVertexShader(true) + , m_contextObserver(0) { setFlag(QGraphicsItem::ItemHasNoContents, false); connect(this, SIGNAL(visibleChanged()), this, SLOT(handleVisibilityChange())); m_active = isVisible(); + +#ifndef OBSERVE_GL_CONTEXT_LOSS + m_program = new QGLShaderProgram(this); +#endif } ShaderEffectItem::~ShaderEffectItem() { reset(); + delete m_contextObserver; } @@ -422,10 +433,38 @@ void ShaderEffectItem::renderEffect(QPainter *painter, const QMatrix4x4 &matrix) if (!painter || !painter->device()) return; - if (!m_program.isLinked() || m_program_dirty) +#ifdef OBSERVE_GL_CONTEXT_LOSS + QGLContext *context = const_cast (QGLContext::currentContext()); + if (!m_program || !m_contextObserver || !m_contextObserver->isValid()) { + // Context has changed, re-create QGLShaderProgram + if (context) { + delete m_program; + m_program = 0; + + delete m_contextObserver; + m_contextObserver = 0; + + m_program = new QGLShaderProgram(this); + m_contextObserver = new QGLFramebufferObject(QSize(2,2)); + + if (!m_contextObserver || !m_program) { + delete m_program; + m_program = 0; + delete m_contextObserver; + m_contextObserver = 0; + qWarning() << "ShaderEffectItem::renderEffect - Creating QGLShaderProgram or QGLFrameBufferObject failed!"; + } + } + } +#endif + + if (!m_program) + return; + + if (!m_program->isLinked() || m_program_dirty) updateShaderProgram(); - m_program.bind(); + m_program->bind(); QMatrix4x4 combinedMatrix; combinedMatrix.scale(2.0 / painter->device()->width(), -2.0 / painter->device()->height(), 1.0); @@ -434,7 +473,7 @@ void ShaderEffectItem::renderEffect(QPainter *painter, const QMatrix4x4 &matrix) updateEffectState(combinedMatrix); for (int i = 0; i < m_attributeNames.size(); ++i) { - m_program.enableAttributeArray(m_geometry.attributes()[i].position); + m_program->enableAttributeArray(m_geometry.attributes()[i].position); } bindGeometry(); @@ -472,11 +511,14 @@ void ShaderEffectItem::renderEffect(QPainter *painter, const QMatrix4x4 &matrix) glDisable(GL_DEPTH_TEST); for (int i = 0; i < m_attributeNames.size(); ++i) - m_program.disableAttributeArray(m_geometry.attributes()[i].position); + m_program->disableAttributeArray(m_geometry.attributes()[i].position); } void ShaderEffectItem::updateEffectState(const QMatrix4x4 &matrix) { + if (!m_program) + return; + for (int i = m_sources.size() - 1; i >= 0; --i) { const ShaderEffectItem::SourceData &source = m_sources.at(i); if (!source.source) @@ -487,10 +529,10 @@ void ShaderEffectItem::updateEffectState(const QMatrix4x4 &matrix) } if (m_respectsOpacity) - m_program.setUniformValue("qt_Opacity", static_cast (effectiveOpacity())); + m_program->setUniformValue("qt_Opacity", static_cast (effectiveOpacity())); if (m_respectsMatrix){ - m_program.setUniformValue("qt_ModelViewProjectionMatrix", matrix); + m_program->setUniformValue("qt_ModelViewProjectionMatrix", matrix); } QSet::const_iterator it; @@ -500,37 +542,37 @@ void ShaderEffectItem::updateEffectState(const QMatrix4x4 &matrix) switch (v.type()) { case QVariant::Color: - m_program.setUniformValue(name.constData(), qvariant_cast(v)); + m_program->setUniformValue(name.constData(), qvariant_cast(v)); break; case QVariant::Double: - m_program.setUniformValue(name.constData(), (float) qvariant_cast(v)); + m_program->setUniformValue(name.constData(), (float) qvariant_cast(v)); break; case QVariant::Transform: - m_program.setUniformValue(name.constData(), qvariant_cast(v)); + m_program->setUniformValue(name.constData(), qvariant_cast(v)); break; case QVariant::Int: - m_program.setUniformValue(name.constData(), v.toInt()); + m_program->setUniformValue(name.constData(), GLint(v.toInt())); break; case QVariant::Bool: - m_program.setUniformValue(name.constData(), GLint(v.toBool())); + m_program->setUniformValue(name.constData(), GLint(v.toBool())); break; case QVariant::Size: case QVariant::SizeF: - m_program.setUniformValue(name.constData(), v.toSizeF()); + m_program->setUniformValue(name.constData(), v.toSizeF()); break; case QVariant::Point: case QVariant::PointF: - m_program.setUniformValue(name.constData(), v.toPointF()); + m_program->setUniformValue(name.constData(), v.toPointF()); break; case QVariant::Rect: case QVariant::RectF: { QRectF r = v.toRectF(); - m_program.setUniformValue(name.constData(), r.x(), r.y(), r.width(), r.height()); + m_program->setUniformValue(name.constData(), r.x(), r.y(), r.width(), r.height()); } break; case QVariant::Vector3D: - m_program.setUniformValue(name.constData(), qvariant_cast(v)); + m_program->setUniformValue(name.constData(), qvariant_cast(v)); break; default: break; @@ -558,6 +600,9 @@ static inline int size_of_type(GLenum type) void ShaderEffectItem::bindGeometry() { + if (!m_program) + return; + char const *const *attrNames = m_attributeNames.constData(); int offset = 0; for (int j = 0; j < m_attributeNames.size(); ++j) { @@ -574,7 +619,7 @@ void ShaderEffectItem::bindGeometry() if (normalize) qWarning() << "ShaderEffectItem::bindGeometry() - non supported attribute type!"; - m_program.setAttributeArray(a.position, (GLfloat*) (((char*) m_geometry.vertexData()) + offset), a.tupleSize, m_geometry.stride()); + m_program->setAttributeArray(a.position, (GLfloat*) (((char*) m_geometry.vertexData()) + offset), a.tupleSize, m_geometry.stride()); //glVertexAttribPointer(a.position, a.tupleSize, a.type, normalize, m_geometry.stride(), (char *) m_geometry.vertexData() + offset); offset += a.tupleSize * size_of_type(a.type); } @@ -657,6 +702,16 @@ void ShaderEffectItem::setActive(bool enable) } } + // QGLShaderProgram is deleted when not active (to minimize GPU memory usage). +#ifdef OBSERVE_GL_CONTEXT_LOSS + if (!m_active && m_program) { + delete m_program; + m_program = 0; + delete m_contextObserver; + m_contextObserver = 0; + } +#endif + emit activeChanged(); markDirty(); } @@ -776,7 +831,9 @@ void ShaderEffectItem::reset() { disconnectPropertySignals(); - m_program.removeAllShaders(); + if (m_program) + m_program->removeAllShaders(); + m_attributeNames.clear(); m_uniformNames.clear(); for (int i = 0; i < m_sources.size(); ++i) { @@ -821,6 +878,9 @@ void ShaderEffectItem::updateProperties() void ShaderEffectItem::updateShaderProgram() { + if (!m_program) + return; + QString vertexCode = m_vertex_code; QString fragmentCode = m_fragment_code; @@ -830,16 +890,16 @@ void ShaderEffectItem::updateShaderProgram() if (fragmentCode.isEmpty()) fragmentCode = QString::fromLatin1(qt_default_fragment_code); - m_program.addShaderFromSourceCode(QGLShader::Vertex, vertexCode); - m_program.addShaderFromSourceCode(QGLShader::Fragment, fragmentCode); + m_program->addShaderFromSourceCode(QGLShader::Vertex, vertexCode); + m_program->addShaderFromSourceCode(QGLShader::Fragment, fragmentCode); for (int i = 0; i < m_attributeNames.size(); ++i) { - m_program.bindAttributeLocation(m_attributeNames.at(i), m_geometry.attributes()[i].position); + m_program->bindAttributeLocation(m_attributeNames.at(i), m_geometry.attributes()[i].position); } - if (!m_program.link()) { + if (!m_program->link()) { qWarning("ShaderEffectItem: Shader compilation failed:"); - qWarning() << m_program.log(); + qWarning() << m_program->log(); } if (!m_attributeNames.contains(qt_postion_attribute_name)) @@ -849,10 +909,10 @@ void ShaderEffectItem::updateShaderProgram() if (!m_respectsMatrix) qWarning("ShaderEffectItem: Missing reference to \'qt_ModelViewProjectionMatrix\'."); - if (m_program.isLinked()) { - m_program.bind(); + if (m_program->isLinked()) { + m_program->bind(); for (int i = 0; i < m_sources.size(); ++i) - m_program.setUniformValue(m_sources.at(i).name.constData(), i); + m_program->setUniformValue(m_sources.at(i).name.constData(), (GLint) i); } m_program_dirty = false; diff --git a/src/imports/shaders/shadereffectitem.h b/src/imports/shaders/shadereffectitem.h index aebe897..6c225a2 100644 --- a/src/imports/shaders/shadereffectitem.h +++ b/src/imports/shaders/shadereffectitem.h @@ -115,7 +115,7 @@ private: private: QString m_fragment_code; QString m_vertex_code; - QGLShaderProgram m_program; + QGLShaderProgram* m_program; QVector m_attributeNames; QSet m_uniformNames; QSize m_meshResolution; @@ -143,6 +143,8 @@ private: bool m_hasShaderPrograms : 1; bool m_mirrored : 1; bool m_defaultVertexShader : 1; + + QGLFramebufferObject* m_contextObserver; }; QT_END_HEADER diff --git a/src/imports/shaders/shadereffectsource.cpp b/src/imports/shaders/shadereffectsource.cpp index 6210c41..21d814a 100644 --- a/src/imports/shaders/shadereffectsource.cpp +++ b/src/imports/shaders/shadereffectsource.cpp @@ -170,15 +170,11 @@ void ShaderEffectSource::setSourceRect(const QRectF &rect) return; m_sourceRect = rect; updateSizeAndTexture(); - updateBackbuffer(); emit sourceRectChanged(); emit repaintRequired(); - if (m_sourceItem) { - ShaderEffect* effect = qobject_cast (m_sourceItem->graphicsEffect()); - if (effect) - effect->m_changed = true; - } + m_dirtyTexture = true; + markSourceItemDirty(); } /*! @@ -207,11 +203,8 @@ void ShaderEffectSource::setTextureSize(const QSize &size) emit textureSizeChanged(); emit repaintRequired(); - if (m_sourceItem) { - ShaderEffect* effect = qobject_cast (m_sourceItem->graphicsEffect()); - if (effect) - effect->m_changed = true; - } + m_dirtyTexture = true; + markSourceItemDirty(); } /*! @@ -294,8 +287,10 @@ void ShaderEffectSource::setWrapMode(WrapMode mode) return; m_wrapMode = mode; - updateBackbuffer(); emit wrapModeChanged(); + + m_dirtyTexture = true; + markSourceItemDirty(); } /*! @@ -314,7 +309,7 @@ void ShaderEffectSource::grab() emit repaintRequired(); } -void ShaderEffectSource::bind() const +void ShaderEffectSource::bind() { GLint filtering = smooth() ? GL_LINEAR : GL_NEAREST; GLuint hwrap = (m_wrapMode == Repeat || m_wrapMode == RepeatHorizontally) ? GL_REPEAT : GL_CLAMP_TO_EDGE; @@ -323,9 +318,13 @@ void ShaderEffectSource::bind() const #if !defined(QT_OPENGL_ES_2) glEnable(GL_TEXTURE_2D); #endif - if (m_fbo) { + + if (m_fbo && m_fbo->isValid()) { glBindTexture(GL_TEXTURE_2D, m_fbo->texture()); } else { + m_dirtyTexture = true; + emit repaintRequired(); + markSourceItemDirty(); glBindTexture(GL_TEXTURE_2D, 0); } @@ -354,7 +353,7 @@ void ShaderEffectSource::derefFromEffectItem() void ShaderEffectSource::updateBackbuffer() { - if (!m_sourceItem) + if (!m_sourceItem || !QGLContext::currentContext()) return; // Multisampling is not (for now) supported. @@ -370,7 +369,7 @@ void ShaderEffectSource::updateBackbuffer() if (!m_fbo) { m_fbo = new ShaderEffectBuffer(size, format); } else { - if (m_fbo->size() != size || m_fbo->format().internalTextureFormat() != GLenum(m_format)) { + if (!m_fbo->isValid() || m_fbo->size() != size || m_fbo->format().internalTextureFormat() != GLenum(m_format)) { delete m_fbo; m_fbo = 0; m_fbo = new ShaderEffectBuffer(size, format); @@ -397,6 +396,16 @@ void ShaderEffectSource::markSourceSizeDirty() emit repaintRequired(); } +void ShaderEffectSource::markSourceItemDirty() +{ + m_dirtyTexture = true; + if (m_sourceItem) { + ShaderEffect* effect = qobject_cast (m_sourceItem->graphicsEffect()); + if (effect) + effect->m_changed = true; + } +} + void ShaderEffectSource::updateSizeAndTexture() { if (m_sourceItem) { @@ -407,7 +416,7 @@ void ShaderEffectSource::updateSizeAndTexture() size.setWidth(1); if (size.height() < 1) size.setHeight(1); - if (m_fbo && m_fbo->size() != size) { + if (m_fbo && (m_fbo->size() != size || !m_fbo->isValid())) { delete m_fbo; m_fbo = 0; delete m_multisampledFbo; diff --git a/src/imports/shaders/shadereffectsource.h b/src/imports/shaders/shadereffectsource.h index 0f03a6a..af8a815 100644 --- a/src/imports/shaders/shadereffectsource.h +++ b/src/imports/shaders/shadereffectsource.h @@ -99,7 +99,7 @@ public: void setWrapMode(WrapMode mode); bool isActive() const { return m_refs; } - void bind() const; + void bind(); void refFromEffectItem(); void derefFromEffectItem(); void updateBackbuffer(); @@ -124,6 +124,7 @@ Q_SIGNALS: public Q_SLOTS: void markSceneGraphDirty(); void markSourceSizeDirty(); + void markSourceItemDirty(); private: void updateSizeAndTexture(); -- cgit v0.12 From c691fc126a61a6153628a176d4375dd7ac76c0e1 Mon Sep 17 00:00:00 2001 From: Sami Merila Date: Thu, 25 Aug 2011 11:11:28 +0300 Subject: QS60Style omits drawing theme background in some Symbian SDKs Latest internal RnD releases have upgraded Symbian version to 5.4. As QS60Style was not aware of this, all the textures that didn't define any version information (i.e. available in all versions) were not drawn at all. Task-number: QT-5176 Reviewed-by: Miikka Heikkinen --- src/gui/styles/qs60style_s60.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/gui/styles/qs60style_s60.cpp b/src/gui/styles/qs60style_s60.cpp index 67181af..f1cf2f6 100644 --- a/src/gui/styles/qs60style_s60.cpp +++ b/src/gui/styles/qs60style_s60.cpp @@ -91,6 +91,7 @@ enum TSupportRelease { ES60_5_1 = 0x0008, ES60_5_2 = 0x0010, ES60_5_3 = 0x0020, + ES60_5_4 = 0x0040, ES60_3_X = ES60_3_1 | ES60_3_2, // Releases before Symbian Foundation ES60_PreSF = ES60_3_1 | ES60_3_2 | ES60_5_0, @@ -98,8 +99,10 @@ enum TSupportRelease { ES60_Pre52 = ES60_3_1 | ES60_3_2 | ES60_5_0 | ES60_5_1, // Releases before S60 5.3 ES60_Pre53 = ES60_3_1 | ES60_3_2 | ES60_5_0 | ES60_5_1 | ES60_5_2, + // Releases before S60 5.4 + ES60_Pre54 = ES60_3_1 | ES60_3_2 | ES60_5_0 | ES60_5_1 | ES60_5_2 | ES60_5_3, // Add all new releases here - ES60_All = ES60_3_1 | ES60_3_2 | ES60_5_0 | ES60_5_1 | ES60_5_2 | ES60_5_3 + ES60_All = ES60_3_1 | ES60_3_2 | ES60_5_0 | ES60_5_1 | ES60_5_2 | ES60_5_3 | ES60_5_4 }; typedef struct { @@ -1264,7 +1267,8 @@ bool QS60StyleModeSpecifics::checkSupport(const int supportedRelease) (currentRelease == QSysInfo::SV_S60_5_0 && supportedRelease & ES60_5_0) || (currentRelease == QSysInfo::SV_S60_5_1 && supportedRelease & ES60_5_1) || (currentRelease == QSysInfo::SV_S60_5_2 && supportedRelease & ES60_5_2) || - (currentRelease == QSysInfo::SV_S60_5_3 && supportedRelease & ES60_5_3) ); + (currentRelease == QSysInfo::SV_S60_5_3 && supportedRelease & ES60_5_3) || + (currentRelease == QSysInfo::SV_S60_5_4 && supportedRelease & ES60_5_4) ); } TAknsItemID QS60StyleModeSpecifics::partSpecificThemeId(int part) -- cgit v0.12 From 338346ceae99ec0d8f7227af12333d63393992be Mon Sep 17 00:00:00 2001 From: Sami Merila Date: Thu, 25 Aug 2011 14:21:30 +0300 Subject: Crash when creating scroll bar skin graphics on S60 (debug only) When fetching bitmap graphics from native without fallback information, do not define fallback-mif file, since native side uses ASSERT_DEBUG to crash the client if file info exists, but bitmap ID is not defined. This started crashing when root theme removed default scrollbar graphics from its content for Belle release. Task-number: QTBUG-15993 Reviewed-by: Miikka Heikkinen --- src/gui/styles/qs60style_s60.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/styles/qs60style_s60.cpp b/src/gui/styles/qs60style_s60.cpp index f1cf2f6..2051362 100644 --- a/src/gui/styles/qs60style_s60.cpp +++ b/src/gui/styles/qs60style_s60.cpp @@ -711,7 +711,7 @@ QPixmap QS60StyleModeSpecifics::colorSkinnedGraphicsLX( colorIndex, icon, iconMask, - AknIconUtils::AvkonIconFileName(), + (fallbackGraphicID != KErrNotFound ? AknIconUtils::AvkonIconFileName() : KNullDesC), fallbackGraphicID, fallbackGraphicsMaskID, defaultColor); @@ -949,7 +949,7 @@ QPixmap QS60StyleModeSpecifics::createSkinnedGraphicsLX( skinId, icon, iconMask, - AknIconUtils::AvkonIconFileName(), + (fallbackGraphicID != KErrNotFound ? AknIconUtils::AvkonIconFileName() : KNullDesC), fallbackGraphicID , fallbackGraphicsMaskID); @@ -1043,7 +1043,7 @@ QPixmap QS60StyleModeSpecifics::createSkinnedGraphicsLX( KAknsIIDDefault, //animation is not themed, lets force fallback graphics animationFrame, frameMask, - AknIconUtils::AvkonIconFileName(), + (fallbackGraphicID != KErrNotFound ? AknIconUtils::AvkonIconFileName() : KNullDesC), fallbackGraphicID , fallbackGraphicsMaskID); } -- cgit v0.12 From a4eae8a44ca38739755ba8994251e2b120878ec8 Mon Sep 17 00:00:00 2001 From: mread Date: Fri, 26 Aug 2011 12:07:31 +0100 Subject: Fixed use of deleted object in XmlPatterns EvaluationCache This problem was shown up by the Ilta-Sanomat QML app on Symbian. Changes to the EvaluationCache class in 23267553627ac3c4cbcd918283bee8e665deeff9 meant that it was now trying to access the declaration object after it had been deleted. This change takes the data needed from the declaration object (1 bool) and stores that instead Task-number: QTTH-1492 Reviewed-by: Honglei Zhang --- src/xmlpatterns/expr/qevaluationcache.cpp | 5 ++--- src/xmlpatterns/expr/qevaluationcache_p.h | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/xmlpatterns/expr/qevaluationcache.cpp b/src/xmlpatterns/expr/qevaluationcache.cpp index 67109eb..3b6fc92 100644 --- a/src/xmlpatterns/expr/qevaluationcache.cpp +++ b/src/xmlpatterns/expr/qevaluationcache.cpp @@ -49,10 +49,9 @@ template EvaluationCache::EvaluationCache(const Expression::Ptr &op, const VariableDeclaration *varDecl, const VariableSlotID aSlot) : SingleContainer(op) - , m_declaration(varDecl) + , m_declarationUsedByMany(varDecl->usedByMany()) , m_varSlot(aSlot) { - Q_ASSERT(m_declaration); Q_ASSERT(m_varSlot > -1); } @@ -199,7 +198,7 @@ Expression::Ptr EvaluationCache::compress(const StaticContext::Ptr if(m_operand->is(IDRangeVariableReference)) return m_operand; - if(m_declaration->usedByMany()) + if (m_declarationUsedByMany) { /* If it's only an atomic value an EvaluationCache is overkill. However, * it's still needed for functions like fn:current-time() that must adhere to diff --git a/src/xmlpatterns/expr/qevaluationcache_p.h b/src/xmlpatterns/expr/qevaluationcache_p.h index 6080157..77d9c11 100644 --- a/src/xmlpatterns/expr/qevaluationcache_p.h +++ b/src/xmlpatterns/expr/qevaluationcache_p.h @@ -124,7 +124,7 @@ namespace QPatternist private: static DynamicContext::Ptr topFocusContext(const DynamicContext::Ptr &context); - const VariableDeclaration *m_declaration; + bool m_declarationUsedByMany; /** * This variable must not be called m_slot. If it so, a compiler bug on * HP-UX-aCC-64 is triggered in the constructor initializor. See the -- cgit v0.12 From dcee6e1371d899eb79717b8e3f3eec08b765db82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Thu, 11 Aug 2011 15:49:37 +0200 Subject: Fix QDir::operator==(const QDir &) const We can't rely on absolute paths when comparing directories for equality as these don't take into account symbolic links and may also bypass ../ and ./ simplification. Instead, canonical paths must be computed and can then be compared according to the case sensitivity rules for the platform or file engine, as is done in QFileInfo. Task-number: QTBUG-20495 Reviewed-by: Prasanth Ullattil --- src/corelib/io/qdir.cpp | 6 +++--- src/corelib/io/qfileinfo.cpp | 1 + tests/auto/qdir/tst_qdir.cpp | 6 ++++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index f9196e0..6e25d91 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -1633,9 +1633,9 @@ bool QDir::operator==(const QDir &dir) const if (d->filters == other->filters && d->sort == other->sort && d->nameFilters == other->nameFilters) { - d->resolveAbsoluteEntry(); - other->resolveAbsoluteEntry(); - return d->absoluteDirEntry.filePath().compare(other->absoluteDirEntry.filePath(), sensitive) == 0; + + // Fallback to expensive canonical path computation + return canonicalPath().compare(dir.canonicalPath(), sensitive) == 0; } return false; } diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index ca42c87..6e25206 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -406,6 +406,7 @@ bool QFileInfo::operator==(const QFileInfo &fileinfo) const if (fileinfo.size() != size()) //if the size isn't the same... return false; + // Fallback to expensive canonical path computation return canonicalFilePath().compare(fileinfo.canonicalFilePath(), sensitive) == 0; } diff --git a/tests/auto/qdir/tst_qdir.cpp b/tests/auto/qdir/tst_qdir.cpp index 0a42a97..419eaae 100644 --- a/tests/auto/qdir/tst_qdir.cpp +++ b/tests/auto/qdir/tst_qdir.cpp @@ -444,9 +444,15 @@ void tst_QDir::QDir_default() void tst_QDir::compare() { // operator== + + // Not using QCOMPARE to test result of QDir::operator== + QDir dir; dir.makeAbsolute(); QVERIFY(dir == QDir::currentPath()); + + QVERIFY(QDir() == QDir(QDir::currentPath())); + QVERIFY(QDir("../") == QDir(QDir::currentPath() + "/..")); } static QStringList filterLinks(const QStringList &list) -- cgit v0.12 From 664abe11efdbf582a5433abccf0d8c6fdbe2b040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Thu, 11 Aug 2011 16:17:40 +0200 Subject: Compare non-canonical paths before falling back on expensive computation Reviewed-by: Prasanth Ullattil --- src/corelib/io/qdir.cpp | 4 ++++ src/corelib/io/qfileinfo.cpp | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index 6e25d91..c0c62e1 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -1634,6 +1634,10 @@ bool QDir::operator==(const QDir &dir) const && d->sort == other->sort && d->nameFilters == other->nameFilters) { + // Assume directories are the same if path is the same + if (d->dirEntry.filePath() == other->dirEntry.filePath()) + return true; + // Fallback to expensive canonical path computation return canonicalPath().compare(dir.canonicalPath(), sensitive) == 0; } diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index 6e25206..ff328da 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -391,6 +391,11 @@ bool QFileInfo::operator==(const QFileInfo &fileinfo) const return true; if (d->isDefaultConstructed || fileinfo.d_ptr->isDefaultConstructed) return false; + + // Assume files are the same if path is the same + if (d->fileEntry.filePath() == fileinfo.d_ptr->fileEntry.filePath()) + return true; + Qt::CaseSensitivity sensitive; if (d->fileEngine == 0 || fileinfo.d_ptr->fileEngine == 0) { if (d->fileEngine != fileinfo.d_ptr->fileEngine) // one is native, the other is a custom file-engine -- cgit v0.12 From 07afddbf4bc029f776810381c7317fffa100eb60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 26 Aug 2011 10:39:52 +0200 Subject: Don't second-guess the "engine"; call cleanPath on absolutePaths This ensures there is a single definition of what constitutes an absolute path in Qt. Task-number: QTBUG-19995 Reviewed-by: Prasanth Ullattil --- src/corelib/io/qdir.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index c0c62e1..cbe635f 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -197,16 +197,10 @@ inline void QDirPrivate::resolveAbsoluteEntry() const return; QString absoluteName; - if (fileEngine.isNull()) { - if (!dirEntry.isRelative()) { - absoluteDirEntry = dirEntry; - return; - } - + if (fileEngine.isNull()) absoluteName = QFileSystemEngine::absoluteName(dirEntry).filePath(); - } else { + else absoluteName = fileEngine->fileName(QAbstractFileEngine::AbsoluteName); - } absoluteDirEntry = QFileSystemEntry(QDir::cleanPath(absoluteName), QFileSystemEntry::FromInternalPath()); } -- cgit v0.12 From 13899108ed57548d3c4f40e595481f8ee76e4fcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 26 Aug 2011 11:03:55 +0200 Subject: We prefer capitalized drive letters, make it so sooner Reviewed-by: Prasanth Ullattil --- src/corelib/io/qfilesystemengine_win.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp index f704fc3..993c946 100644 --- a/src/corelib/io/qfilesystemengine_win.cpp +++ b/src/corelib/io/qfilesystemengine_win.cpp @@ -1052,11 +1052,12 @@ QString QFileSystemEngine::tempPath() } if (ret.isEmpty()) { #if !defined(Q_OS_WINCE) - ret = QLatin1String("c:/tmp"); + ret = QLatin1String("C:/tmp"); #else ret = QLatin1String("/Temp"); #endif - } + } else if (ret.length() >= 2 && ret[1] == QLatin1Char(':')) + ret[0] = ret.at(0).toUpper(); // Force uppercase drive letters. return ret; } -- cgit v0.12 From d4aa1777389f41da60a862a8c371d13839938d43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 26 Aug 2011 11:01:48 +0200 Subject: ret is an "internal" path, no need to re-process it Where "internal" means that it uses Qt's separator '/', regardless of the native one. --- src/corelib/io/qfilesystemengine_win.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/io/qfilesystemengine_win.cpp b/src/corelib/io/qfilesystemengine_win.cpp index 993c946..764ee6d 100644 --- a/src/corelib/io/qfilesystemengine_win.cpp +++ b/src/corelib/io/qfilesystemengine_win.cpp @@ -536,7 +536,7 @@ QFileSystemEntry QFileSystemEngine::absoluteName(const QFileSystemEntry &entry) // Force uppercase drive letters. ret[0] = ret.at(0).toUpper(); } - return QFileSystemEntry(ret); + return QFileSystemEntry(ret, QFileSystemEntry::FromInternalPath()); } //static -- cgit v0.12 From 2e32fca2c0f5252864d348df929d9858486763b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 26 Aug 2011 17:09:01 +0200 Subject: In 4.7 QFileInfo::absolute(File)Path returned clean paths Let's play nice and keep that "feature". Task-number: QTBUG-19995 --- src/corelib/io/qfileinfo.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index ff328da..e317d1e 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -76,7 +76,9 @@ QString QFileInfoPrivate::getFileName(QAbstractFileEngine::FileName name) const break; case QAbstractFileEngine::AbsoluteName: case QAbstractFileEngine::AbsolutePathName: { - QFileSystemEntry entry = QFileSystemEngine::absoluteName(fileEntry); + QFileSystemEntry entry = QFileSystemEntry( + QDir::cleanPath(QFileSystemEngine::absoluteName(fileEntry).filePath()), + QFileSystemEntry::FromInternalPath()); if (cache_enabled) { // be smart and store both fileNames[QAbstractFileEngine::AbsoluteName] = entry.filePath(); fileNames[QAbstractFileEngine::AbsolutePathName] = entry.path(); -- cgit v0.12 From c0278760008efa18a068c6b5b2634b6cdb473dbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 26 Aug 2011 17:33:47 +0200 Subject: Revert "In 4.7 QFileInfo::absolute(File)Path returned clean paths" This reverts commit 2e32fca2c0f5252864d348df929d9858486763b1. The fix there is incorrect as it breaks QFileInfo autotests. --- src/corelib/io/qfileinfo.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/corelib/io/qfileinfo.cpp b/src/corelib/io/qfileinfo.cpp index e317d1e..ff328da 100644 --- a/src/corelib/io/qfileinfo.cpp +++ b/src/corelib/io/qfileinfo.cpp @@ -76,9 +76,7 @@ QString QFileInfoPrivate::getFileName(QAbstractFileEngine::FileName name) const break; case QAbstractFileEngine::AbsoluteName: case QAbstractFileEngine::AbsolutePathName: { - QFileSystemEntry entry = QFileSystemEntry( - QDir::cleanPath(QFileSystemEngine::absoluteName(fileEntry).filePath()), - QFileSystemEntry::FromInternalPath()); + QFileSystemEntry entry = QFileSystemEngine::absoluteName(fileEntry); if (cache_enabled) { // be smart and store both fileNames[QAbstractFileEngine::AbsoluteName] = entry.filePath(); fileNames[QAbstractFileEngine::AbsolutePathName] = entry.path(); -- cgit v0.12 From 7b45a4cbf7593c8d7a837d826d9827fee243c46c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Abecasis?= Date: Fri, 26 Aug 2011 17:58:27 +0200 Subject: Revert "Don't second-guess the "engine"; call cleanPath on absolutePaths" This reverts commit 07afddbf4bc029f776810381c7317fffa100eb60. This breaks QDir autotests on windows. --- src/corelib/io/qdir.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/corelib/io/qdir.cpp b/src/corelib/io/qdir.cpp index cbe635f..c0c62e1 100644 --- a/src/corelib/io/qdir.cpp +++ b/src/corelib/io/qdir.cpp @@ -197,10 +197,16 @@ inline void QDirPrivate::resolveAbsoluteEntry() const return; QString absoluteName; - if (fileEngine.isNull()) + if (fileEngine.isNull()) { + if (!dirEntry.isRelative()) { + absoluteDirEntry = dirEntry; + return; + } + absoluteName = QFileSystemEngine::absoluteName(dirEntry).filePath(); - else + } else { absoluteName = fileEngine->fileName(QAbstractFileEngine::AbsoluteName); + } absoluteDirEntry = QFileSystemEntry(QDir::cleanPath(absoluteName), QFileSystemEntry::FromInternalPath()); } -- cgit v0.12