diff options
author | Thierry Bastian <thierry.bastian@nokia.com> | 2011-04-20 08:59:13 (GMT) |
---|---|---|
committer | Thierry Bastian <thierry.bastian@nokia.com> | 2011-04-20 08:59:13 (GMT) |
commit | 97d57498481598d0d4babfa77f816761dead29b8 (patch) | |
tree | 8709b1f70c8ad75e225acf476e827cf4e15b85f3 /src | |
parent | 0edbaca5e7b718bb9bbbeaccc9e322b525b4327e (diff) | |
parent | 6037cb7f68fe0dec52f922d9e2f18c8e12a396cb (diff) | |
download | Qt-97d57498481598d0d4babfa77f816761dead29b8.zip Qt-97d57498481598d0d4babfa77f816761dead29b8.tar.gz Qt-97d57498481598d0d4babfa77f816761dead29b8.tar.bz2 |
Merge branch '4.7-upstream' into 4.7
Diffstat (limited to 'src')
236 files changed, 7050 insertions, 2069 deletions
diff --git a/src/3rdparty/webkit/JavaScriptCore/wtf/MathExtras.h b/src/3rdparty/webkit/JavaScriptCore/wtf/MathExtras.h index f8bace4..9349b48 100644 --- a/src/3rdparty/webkit/JavaScriptCore/wtf/MathExtras.h +++ b/src/3rdparty/webkit/JavaScriptCore/wtf/MathExtras.h @@ -190,7 +190,7 @@ inline float deg2turn(float d) { return d / 360.0f; } inline float rad2grad(float r) { return r * 200.0f / piFloat; } inline float grad2rad(float g) { return g * piFloat / 200.0f; } -#if !COMPILER(MSVC) && !COMPILER(RVCT) && !OS(ANDROID) && !COMPILER(WINSCW) +#if !COMPILER(MSVC) && !OS(ANDROID) && !OS(SYMBIAN) using std::isfinite; using std::isinf; using std::isnan; diff --git a/src/3rdparty/webkit/WebCore/WebCore.pro b/src/3rdparty/webkit/WebCore/WebCore.pro index 37d216d..c70a168 100644 --- a/src/3rdparty/webkit/WebCore/WebCore.pro +++ b/src/3rdparty/webkit/WebCore/WebCore.pro @@ -37,15 +37,14 @@ symbian: { # Need to guarantee that these come before system includes of /epoc32/include MMP_RULES += "USERINCLUDE rendering" MMP_RULES += "USERINCLUDE platform/text" - symbian-abld|symbian-sbsv2 { - # RO text (code) section in qtwebkit.dll exceeds allocated space for gcce udeb target. - # Move RW-section base address to start from 0xE00000 instead of the toolchain default 0x400000. - QMAKE_LFLAGS.ARMCC += --rw-base 0xE00000 - MMP_RULES += ALWAYS_BUILD_AS_ARM - } else { - QMAKE_CFLAGS -= --thumb - QMAKE_CXXFLAGS -= --thumb - } + + # RO text (code) section in qtwebkit.dll exceeds allocated space for gcce udeb target. + # Move RW-section base address to start from 0xE00000 instead of the toolchain default 0x400000. + QMAKE_LFLAGS.ARMCC += --rw-base 0xE00000 + QMAKE_LFLAGS.GCCE += -Tdata 0x1000000 + + CONFIG += do_not_build_as_thumb + CONFIG(release, debug|release): QMAKE_CXXFLAGS.ARMCC += -OTime -O3 } diff --git a/src/3rdparty/webkit/WebKit/qt/qt_webkit_version.pri b/src/3rdparty/webkit/WebKit/qt/qt_webkit_version.pri index 07754a7..3ec3e97 100644 --- a/src/3rdparty/webkit/WebKit/qt/qt_webkit_version.pri +++ b/src/3rdparty/webkit/WebKit/qt/qt_webkit_version.pri @@ -1,5 +1,5 @@ -QT_WEBKIT_VERSION = 4.7.3 +QT_WEBKIT_VERSION = 4.7.4 QT_WEBKIT_MAJOR_VERSION = 4 QT_WEBKIT_MINOR_VERSION = 7 -QT_WEBKIT_PATCH_VERSION = 3 +QT_WEBKIT_PATCH_VERSION = 4 QT_CONFIG += webkit diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index 5e6110f..a9bb129 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -167,7 +167,7 @@ Q_GLOBAL_STATIC(QThreadStorage<QUnifiedTimer *>, unifiedTimer) QUnifiedTimer::QUnifiedTimer() : QObject(), lastTick(0), timingInterval(DEFAULT_TIMER_INTERVAL), - currentAnimationIdx(0), consistentTiming(false), slowMode(false), + insideTick(false), currentAnimationIdx(0), consistentTiming(false), slowMode(false), slowdownFactor(5.0f), isPauseTimerActive(false), runningLeafAnimations(0) { time.invalidate(); @@ -205,6 +205,10 @@ void QUnifiedTimer::ensureTimerUpdate() void QUnifiedTimer::updateAnimationsTime() { + //setCurrentTime can get this called again while we're the for loop. At least with pauseAnimations + if(insideTick) + return; + qint64 totalElapsed = time.elapsed(); // ignore consistentTiming in case the pause timer is active int delta = (consistentTiming && !isPauseTimerActive) ? @@ -222,12 +226,14 @@ void QUnifiedTimer::updateAnimationsTime() //it might happen in some cases that the time doesn't change because events are delayed //when the CPU load is high if (delta) { + insideTick = true; for (currentAnimationIdx = 0; currentAnimationIdx < animations.count(); ++currentAnimationIdx) { QAbstractAnimation *animation = animations.at(currentAnimationIdx); int elapsed = QAbstractAnimationPrivate::get(animation)->totalCurrentTime + (animation->direction() == QAbstractAnimation::Forward ? delta : -delta); animation->setCurrentTime(elapsed); } + insideTick = false; currentAnimationIdx = 0; } } diff --git a/src/corelib/animation/qabstractanimation_p.h b/src/corelib/animation/qabstractanimation_p.h index c0488c8..aeee1f2 100644 --- a/src/corelib/animation/qabstractanimation_p.h +++ b/src/corelib/animation/qabstractanimation_p.h @@ -175,6 +175,7 @@ private: qint64 lastTick; int timingInterval; int currentAnimationIdx; + bool insideTick; bool consistentTiming; bool slowMode; diff --git a/src/corelib/concurrent/qfutureinterface.cpp b/src/corelib/concurrent/qfutureinterface.cpp index 627d0c7..c5bd802 100644 --- a/src/corelib/concurrent/qfutureinterface.cpp +++ b/src/corelib/concurrent/qfutureinterface.cpp @@ -219,7 +219,7 @@ QString QFutureInterfaceBase::progressText() const bool QFutureInterfaceBase::isProgressUpdateNeeded() const { QMutexLocker locker(&d->m_mutex); - return (d->progressTime.elapsed() > (1000 / MaxProgressEmitsPerSecond)); + return !d->progressTime.isValid() || (d->progressTime.elapsed() > (1000 / MaxProgressEmitsPerSecond)); } void QFutureInterfaceBase::reportStarted() diff --git a/src/corelib/global/global.pri b/src/corelib/global/global.pri index 86800ef..8ff423e 100644 --- a/src/corelib/global/global.pri +++ b/src/corelib/global/global.pri @@ -19,13 +19,16 @@ INCLUDEPATH += $$QT_BUILD_TREE/src/corelib/global # Only used on platforms with CONFIG += precompile_header PRECOMPILED_HEADER = global/qt_pch.h -linux*:!static:!linux-armcc:!linux-gcce { +linux*:!static:!symbian-armcc:!symbian-gcce { QMAKE_LFLAGS += -Wl,-e,qt_core_boilerplate prog=$$quote(if (/program interpreter: (.*)]/) { print $1; }) DEFINES += ELF_INTERPRETER=\\\"$$system(readelf -l /bin/ls | perl -n -e \'$$prog\')\\\" } # Compensate for lack of platform defines in Symbian3 and Symbian4 -symbian: DEFINES += SYMBIAN_VERSION_$$upper($$replace(SYMBIAN_VERSION,\\.,_)) +symbian { + DEFINES += SYMBIAN_VERSION_$$upper($$replace(SYMBIAN_VERSION,\\.,_)) \ + S60_VERSION_$$upper($$replace(S60_VERSION,\\.,_)) +} include(../../../tools/shared/symbian/epocroot.pri) diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index 62d83cc..2cfd9cc 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -86,7 +86,6 @@ # include "private/qcore_symbian_p.h" _LIT(qt_S60Filter, "Series60v?.*.sis"); -_LIT(qt_symbianFilter, "Symbianv*.sis"); _LIT(qt_symbianSystemInstallDir, "z:\\system\\install\\"); #endif @@ -1198,10 +1197,12 @@ bool qSharedBuild() \value SV_9_2 Symbian OS v9.2 \value SV_9_3 Symbian OS v9.3 \value SV_9_4 Symbian OS v9.4 - \value SV_SF_1 Symbian^1 + \value SV_SF_1 S60 5th Edition (Symbian^1) \value SV_SF_2 Symbian^2 - \value SV_SF_3 Symbian^3 - \value SV_SF_4 Symbian^4 + \value SV_SF_3 Symbian^3 or Symbian Anna + \value SV_SF_4 \e{This enum value is deprecated.} + \value SV_API_5_3 Symbian/S60 API version 5.3 release + \value SV_API_5_4 Symbian/S60 API version 5.4 release \value SV_Unknown An unknown and currently unsupported platform \sa S60Version, WinVersion, MacVersion @@ -1218,8 +1219,10 @@ bool qSharedBuild() \value SV_S60_3_1 S60 3rd Edition Feature Pack 1 \value SV_S60_3_2 S60 3rd Edition Feature Pack 2 \value SV_S60_5_0 S60 5th Edition - \value SV_S60_5_1 S60 5th Edition Feature Pack 1 - \value SV_S60_5_2 S60 5th Edition Feature Pack 2 + \value SV_S60_5_1 \e{This enum value is deprecated.} + \value SV_S60_5_2 Symbian^3 and Symbian Anna + \value SV_S60_5_3 Symbian/S60 API version 5.3 release + \value SV_S60_5_4 Symbian/S60 API version 5.4 release \value SV_S60_Unknown An unknown and currently unsupported platform \omitvalue SV_S60_None @@ -1815,12 +1818,10 @@ const QSysInfo::WinVersion QSysInfo::WindowsVersion = QSysInfo::windowsVersion() #ifdef Q_OS_SYMBIAN static QSysInfo::SymbianVersion cachedSymbianVersion = QSysInfo::SymbianVersion(-1); +static QSysInfo::S60Version cachedS60Version = QSysInfo::S60Version(-1); -QSysInfo::SymbianVersion QSysInfo::symbianVersion() +static void symbianInitVersions() { - if (cachedSymbianVersion != -1) - return cachedSymbianVersion; - // Use pure Symbian code, because if done using QDir, there will be a call back // to this method, resulting doing this expensive operation twice before the cache kicks in. // Pure Symbian code also makes this method ~10x faster, speeding up the application launch. @@ -1828,21 +1829,8 @@ QSysInfo::SymbianVersion QSysInfo::symbianVersion() TFindFile fileFinder(rfs); CDir* contents; - // Check for Symbian4 - TInt err = fileFinder.FindWildByDir(qt_symbianFilter, qt_symbianSystemInstallDir, contents); - if (err == KErrNone) { - QScopedPointer<CDir> contentsDeleter(contents); - err = contents->Sort(EDescending|ESortByName); - if (err == KErrNone && contents->Count() > 0 && (*contents)[0].iName.Length() >= 9) { - TInt major = (*contents)[0].iName[8] - '0'; - if (major == 4) { - return cachedSymbianVersion = SV_SF_4; - } - } - } - - // Check for S60 and Symbian3 platforms, which use older .sis naming scheme - err = fileFinder.FindWildByDir(qt_S60Filter, qt_symbianSystemInstallDir, contents); + // Check for platform version + TInt err = fileFinder.FindWildByDir(qt_S60Filter, qt_symbianSystemInstallDir, contents); if (err == KErrNone) { QScopedPointer<CDir> contentsDeleter(contents); err = contents->Sort(EDescending|ESortByName); @@ -1851,61 +1839,82 @@ QSysInfo::SymbianVersion QSysInfo::symbianVersion() TInt minor = (*contents)[0].iName[11] - '0'; if (major == 3) { if (minor == 1) { - return cachedSymbianVersion = SV_9_2; + cachedS60Version = QSysInfo::SV_S60_3_1; + cachedSymbianVersion = QSysInfo::SV_9_2; } else if (minor == 2) { - return cachedSymbianVersion = SV_9_3; + cachedS60Version = QSysInfo::SV_S60_3_2; + cachedSymbianVersion = QSysInfo::SV_9_3; } } else if (major == 5) { if (minor == 0) { - return cachedSymbianVersion = SV_9_4; - } - else if (minor == 1) { - return cachedSymbianVersion = SV_SF_2; - } - else if (minor == 2) { - return cachedSymbianVersion = SV_SF_3; + cachedS60Version = QSysInfo::SV_S60_5_0; + cachedSymbianVersion = QSysInfo::SV_9_4; + } else if (minor == 1) { + cachedS60Version = QSysInfo::SV_S60_5_1; + cachedSymbianVersion = QSysInfo::SV_SF_2; + } else if (minor == 2) { + cachedS60Version = QSysInfo::SV_S60_5_2; + cachedSymbianVersion = QSysInfo::SV_SF_3; + } else if (minor == 3) { + cachedS60Version = QSysInfo::SV_S60_5_3; + cachedSymbianVersion = QSysInfo::SV_API_5_3; + } else if (minor >= 4) { + cachedS60Version = QSysInfo::SV_S60_5_4; + cachedSymbianVersion = QSysInfo::SV_API_5_4; } } } } # ifdef Q_CC_NOKIAX86 - // Some emulator environments may not contain the version specific .sis files, so - // simply hardcode the version on those environments. Note that can't use - // SYMBIAN_VERSION_* defines for S60 3.x/5.0 platforms, as they do not define them - // right anyway in case .sis files are not found. + if (cachedS60Version == -1) { + // Some emulator environments may not contain the version specific .sis files, so + // simply hardcode the version on those environments. Note that can't use + // S60_VERSION_* defines for S60 3.x/5.0 platforms, as they do not define them + // right anyway in case .sis files are not found. # if defined(__SERIES60_31__) - return cachedSymbianVersion = SV_9_2; + cachedS60Version = QSysInfo::SV_S60_3_1; + cachedSymbianVersion = QSysInfo::SV_9_2; # elif defined(__S60_32__) - return cachedSymbianVersion = SV_9_3; + cachedS60Version = QSysInfo::SV_S60_3_2; + cachedSymbianVersion = QSysInfo::SV_9_3; # elif defined(__S60_50__) - return cachedSymbianVersion = SV_9_4; -# elif defined(SYMBIAN_VERSION_SYMBIAN3) - return cachedSymbianVersion = SV_SF_3; -# elif defined(SYMBIAN_VERSION_SYMBIAN4) - return cachedSymbianVersion = SV_SF_4; + cachedS60Version = QSysInfo::SV_S60_5_0; + cachedSymbianVersion = QSysInfo::SV_9_4; +# elif defined(S60_VERSION_5_2) + cachedS60Version = QSysInfo::SV_S60_5_2; + cachedSymbianVersion = QSysInfo::SV_SF_3; +# elif defined(S60_VERSION_5_3) + cachedS60Version = QSysInfo::SV_S60_5_3; + cachedSymbianVersion = QSysInfo::SV_API_5_3; +# elif defined(S60_VERSION_5_4) + cachedS60Version = QSysInfo::SV_S60_5_4; + cachedSymbianVersion = QSysInfo::SV_API_5_4; # endif + } # endif - //If reaching here, it was not possible to determine the version - return cachedSymbianVersion = SV_Unknown; + + if (cachedS60Version == -1) { + //If reaching here, it was not possible to determine the version + cachedS60Version = QSysInfo::SV_S60_Unknown; + cachedSymbianVersion = QSysInfo::SV_Unknown; + } +} + +QSysInfo::SymbianVersion QSysInfo::symbianVersion() +{ + if (cachedSymbianVersion == -1) + symbianInitVersions(); + + return cachedSymbianVersion; } QSysInfo::S60Version QSysInfo::s60Version() { - switch (symbianVersion()) { - case SV_9_2: - return SV_S60_3_1; - case SV_9_3: - return SV_S60_3_2; - case SV_9_4: - return SV_S60_5_0; - case SV_SF_2: - return SV_S60_5_1; - case SV_SF_3: - return SV_S60_5_2; - default: - return SV_S60_Unknown; - } + if (cachedS60Version == -1) + symbianInitVersions(); + + return cachedS60Version; } #endif // ifdef Q_OS_SYMBIAN diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index d0fc753..e5109e6 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -44,11 +44,11 @@ #include <stddef.h> -#define QT_VERSION_STR "4.7.3" +#define QT_VERSION_STR "4.7.4" /* QT_VERSION is (major << 16) + (minor << 8) + patch. */ -#define QT_VERSION 0x040703 +#define QT_VERSION 0x040704 /* can be used like #if (QT_VERSION >= QT_VERSION_CHECK(4, 4, 0)) */ @@ -284,7 +284,7 @@ namespace QT_NAMESPACE {} # endif #endif -#if defined(Q_OS_MAC64) && !defined(QT_MAC_USE_COCOA) && !defined(QT_BUILD_QMAKE) +#if defined(Q_OS_MAC64) && !defined(QT_MAC_USE_COCOA) && !defined(QT_BUILD_QMAKE) && !defined(QT_BOOTSTRAPPED) #error "You are building a 64-bit application, but using a 32-bit version of Qt. Check your build configuration." #endif @@ -1524,7 +1524,9 @@ public: SV_SF_1 = SV_9_4, SV_SF_2 = 40, SV_SF_3 = 50, - SV_SF_4 = 60 + SV_SF_4 = 60, // Deprecated + SV_API_5_3 = 70, + SV_API_5_4 = 80 }; static SymbianVersion symbianVersion(); enum S60Version { @@ -1533,9 +1535,10 @@ public: SV_S60_3_1 = SV_9_2, SV_S60_3_2 = SV_9_3, SV_S60_5_0 = SV_9_4, - //versions beyond 5.0 are to be confirmed - it is better to use symbian version - SV_S60_5_1 = SV_SF_2, - SV_S60_5_2 = SV_SF_3 + SV_S60_5_1 = SV_SF_2, // Deprecated + SV_S60_5_2 = SV_SF_3, + SV_S60_5_3 = SV_API_5_3, + SV_S60_5_4 = SV_API_5_4 }; static S60Version s60Version(); #endif @@ -2459,6 +2462,10 @@ QT3_SUPPORT Q_CORE_EXPORT const char *qInstallPathSysconf(); #define Q_SYMBIAN_SUPPORTS_MULTIPLE_SCREENS #endif +#ifdef SYMBIAN_GRAPHICS_FIXNATIVEORIENTATION +#define Q_SYMBIAN_SUPPORTS_FIXNATIVEORIENTATION +#endif + //Symbian does not support data imports from a DLL #define Q_NO_DATA_RELOCATION diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index 4d70744..15cc809 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -526,6 +526,8 @@ public: WA_X11DoNotAcceptFocus = 132, + WA_SymbianNoSystemRotation = 133, + // Add new attributes before this line WA_AttributeCount }; diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index a79411b..f03fb25 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -238,81 +238,25 @@ /*! \enum Qt::GlobalColor - \raw HTML - <style type="text/css" id="colorstyles"> - #white { background-color: #ffffff; color: #000000 } - #black { background-color: #000000; color: #ffffff } - #red { background-color: #ff0000; color: #000000 } - #darkRed { background-color: #800000; color: #ffffff } - #green { background-color: #00ff00; color: #000000 } - #darkGreen { background-color: #008000; color: #ffffff } - #blue { background-color: #0000ff; color: #ffffff } - #darkBlue { background-color: #000080; color: #ffffff } - #cyan { background-color: #00ffff; color: #000000 } - #darkCyan { background-color: #008080; color: #ffffff } - #magenta { background-color: #ff00ff; color: #000000 } - #darkMagenta { background-color: #800080; color: #ffffff } - #yellow { background-color: #ffff00; color: #000000 } - #darkYellow { background-color: #808000; color: #ffffff } - #gray { background-color: #a0a0a4; color: #000000 } - #darkGray { background-color: #808080; color: #ffffff } - #lightGray { background-color: #c0c0c0; color: #000000 } - </style> - \endraw - Qt's predefined QColor objects: - \value white \raw HTML - White <tt id="white">(#ffffff)</tt> - \endraw - \value black \raw HTML - Black <tt id="black">(#000000)</tt> - \endraw - \value red \raw HTML - Red <tt id="red">(#ff0000)</tt> - \endraw - \value darkRed \raw HTML - Dark red <tt id="darkRed">(#800000)</tt> - \endraw - \value green \raw HTML - Green <tt id="green">(#00ff00)</tt> - \endraw - \value darkGreen \raw HTML - Dark green <tt id="darkGreen">(#008000)</tt> - \endraw - \value blue \raw HTML - Blue <tt id="blue">(#0000ff)</tt> - \endraw - \value darkBlue \raw HTML - Dark blue <tt id="darkBlue">(#000080)</tt> - \endraw - \value cyan \raw HTML - Cyan <tt id="cyan">(#00ffff)</tt> - \endraw - \value darkCyan \raw HTML - Dark cyan <tt id="darkCyan">(#008080)</tt> - \endraw - \value magenta \raw HTML - Magenta <tt id="magenta">(#ff00ff)</tt> - \endraw - \value darkMagenta \raw HTML - Dark magenta <tt id="darkMagenta">(#800080)</tt> - \endraw - \value yellow \raw HTML - Yellow <tt id="yellow">(#ffff00)</tt> - \endraw - \value darkYellow \raw HTML - Dark yellow <tt id="darkYellow">(#808000)</tt> - \endraw - \value gray \raw HTML - Gray <tt id="gray">(#a0a0a4)</tt> - \endraw - \value darkGray \raw HTML - Dark gray <tt id="darkGray">(#808080)</tt> - \endraw - \value lightGray \raw HTML - Light gray <tt id="lightGray">(#c0c0c0)</tt> - \endraw + \value white \span {id="color-white"} {White (#ffffff) } + \value black \span {id="color-black"} {Black (#000000) } + \value red \span {id="color-red"} {Red (#ff0000) } + \value darkRed \span {id="color-darkRed"} {Dark red (#800000) } + \value green \span {id="color-green"} {Green (#00ff00) } + \value darkGreen \span {id="color-darkGreen"} {Dark green (#008000) } + \value blue \span {id="color-blue"} {Blue (#0000ff) } + \value darkBlue \span {id="color-darkBlue"} {Dark blue (#000080) } + \value cyan \span {id="color-cyan"} {Cyan (#00ffff) } + \value darkCyan \span {id="color-darkCyan"} {Dark cyan (#008080) } + \value magenta \span {id="color-magenta"} {Magenta (#ff00ff) } + \value darkMagenta \span {id="color-darkMagenta"} {Dark magenta (#800080) } + \value yellow \span {id="color-yellow"} {Yellow (#ffff00) } + \value darkYellow \span {id="color-darkYellow"} {Dark yellow (#808000) } + \value gray \span {id="color-gray"} {Gray (#a0a0a4) } + \value darkGray \span {id="color-darkGray"} {Dark gray (#808080) } + \value lightGray \span {id="color-lightGray"} {Light gray (#c0c0c0) } \value transparent a transparent black value (i.e., QColor(0, 0, 0, 0)) \value color0 0 pixel value (for bitmaps) \value color1 1 pixel value (for bitmaps) @@ -1300,6 +1244,7 @@ \omitvalue WA_SetWindowModality \omitvalue WA_WState_WindowOpacitySet \omitvalue WA_WState_AcceptedTouchBeginEvent + \omitvalue WA_SymbianNoSystemRotation */ /*! \typedef Qt::HANDLE @@ -2872,7 +2817,7 @@ INT_MIN, inclusive. For example, you can define custom priorities as being relative to each other: - \snippet doc/src/snippets/code/doc_src_qnamespace.qdoc 1 + \snippet doc/src/snippets/code/doc_src_qnamespace.cpp 1 \sa QCoreApplication::postEvent() */ diff --git a/src/corelib/io/qdiriterator.cpp b/src/corelib/io/qdiriterator.cpp index 3b4adc3..4d3f50b 100644 --- a/src/corelib/io/qdiriterator.cpp +++ b/src/corelib/io/qdiriterator.cpp @@ -278,6 +278,7 @@ void QDirIteratorPrivate::checkAndPushDirectory(const QFileInfo &fileInfo) current entry will be returned as part of the directory iteration); otherwise, false is returned. */ + bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInfo &fi) const { Q_ASSERT(!fileName.isEmpty()); @@ -312,6 +313,14 @@ bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInf return false; } #endif + // skip symlinks + const bool skipSymlinks = (filters & QDir::NoSymLinks); + const bool includeSystem = (filters & QDir::System); + if(skipSymlinks && fi.isSymLink()) { + // The only reason to save this file is if it is a broken link and we are requesting system files. + if(!includeSystem || fi.exists()) + return false; + } // filter hidden const bool includeHidden = (filters & QDir::Hidden); @@ -319,27 +328,20 @@ bool QDirIteratorPrivate::matchesFilters(const QString &fileName, const QFileInf return false; // filter system files - const bool includeSystem = (filters & QDir::System); - if (!includeSystem && ((!fi.isFile() && !fi.isDir() && !fi.isSymLink()) + if (!includeSystem && (!(fi.isFile() || fi.isDir() || fi.isSymLink()) || (!fi.exists() && fi.isSymLink()))) return false; // skip directories const bool skipDirs = !(filters & (QDir::Dirs | QDir::AllDirs)); - if (skipDirs && fi.isDir()) { - if (!((includeHidden && !dotOrDotDot && fi.isHidden()) - || (includeSystem && !fi.exists() && fi.isSymLink()))) - return false; - } + if (skipDirs && fi.isDir()) + return false; // skip files const bool skipFiles = !(filters & QDir::Files); - const bool skipSymlinks = (filters & QDir::NoSymLinks); - if ((skipFiles && (fi.isFile() || !fi.exists())) || (skipSymlinks && fi.isSymLink())) { - if (!((includeHidden && !dotOrDotDot && fi.isHidden()) - || (includeSystem && !fi.exists() && fi.isSymLink()))) - return false; - } + if (skipFiles && fi.isFile()) + // Basically we need a reason not to exclude this file otherwise we just eliminate it. + return false; // filter permissions const bool filterPermissions = ((filters & QDir::PermissionMask) diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp index 43e0f0d..7134ae9 100644 --- a/src/corelib/io/qiodevice.cpp +++ b/src/corelib/io/qiodevice.cpp @@ -1628,10 +1628,11 @@ QString QIODevice::errorString() const \fn qint64 QIODevice::readData(char *data, qint64 maxSize) Reads up to \a maxSize bytes from the device into \a data, and - returns the number of bytes read or -1 if an error occurred. If - there are no bytes to be read, this function should return -1 if - there can never be more bytes available (for example: socket - closed, pipe closed, sub-process finished). + returns the number of bytes read or -1 if an error occurred. + + If there are no bytes to be read and there can never be more bytes + available (examples include socket closed, pipe closed, sub-process + finished), this function returns -1. This function is called by QIODevice. Reimplement this function when creating a subclass of QIODevice. diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp index d35d68e..207cda3 100644 --- a/src/corelib/io/qresource.cpp +++ b/src/corelib/io/qresource.cpp @@ -373,7 +373,7 @@ QResourcePrivate::ensureChildren() const Constructs a QResource pointing to \a file. \a locale is used to load a specific localization of a resource data. - \sa QFileInfo, searchPaths(), setFileName(), setLocale() + \sa QFileInfo, QDir::searchPaths(), setFileName(), setLocale() */ QResource::QResource(const QString &file, const QLocale &locale) : d_ptr(new QResourcePrivate(this)) @@ -418,7 +418,7 @@ QLocale QResource::locale() const /*! Sets a QResource to point to \a file. \a file can either be absolute, in which case it is opened directly, if relative then the file will be - tried to be found in searchPaths(). + tried to be found in QDir::searchPaths(). \sa absoluteFilePath() */ @@ -446,7 +446,7 @@ QString QResource::fileName() const /*! Returns the real path that this QResource represents, if the resource - was found via the searchPaths() it will be indicated in the path. + was found via the QDir::searchPaths() it will be indicated in the path. \sa fileName() */ diff --git a/src/corelib/kernel/qtranslator.cpp b/src/corelib/kernel/qtranslator.cpp index d72c1ab..73a32c4 100644 --- a/src/corelib/kernel/qtranslator.cpp +++ b/src/corelib/kernel/qtranslator.cpp @@ -354,10 +354,15 @@ QTranslator::~QTranslator() } /*! - Loads \a filename + \a suffix (".qm" if the \a suffix is - not specified), which may be an absolute file name or relative - to \a directory. Returns true if the translation is successfully - loaded; otherwise returns false. + + Loads \a filename + \a suffix (".qm" if the \a suffix is not + specified), which may be an absolute file name or relative to \a + directory. Returns true if the translation is successfully loaded; + otherwise returns false. + + If \a directory is not specified, the directory of the + application's executable is used (i.e., as + \l{QCoreApplication::}{applicationDirPath()}). The previous contents of this translator object are discarded. diff --git a/src/corelib/plugin/qplugin.qdoc b/src/corelib/plugin/qplugin.qdoc index 54b2b38..7043fa0 100644 --- a/src/corelib/plugin/qplugin.qdoc +++ b/src/corelib/plugin/qplugin.qdoc @@ -51,7 +51,7 @@ If you want to use Q_DECLARE_INTERFACE with interface classes declared in a namespace then you have to make sure the Q_DECLARE_INTERFACE is not inside a namespace though. For example: - \snippet doc/src/snippets/code/doc_src_qplugin.qdoc 0 + \snippet doc/src/snippets/code/doc_src_qplugin.cpp 0 \sa Q_INTERFACES(), Q_EXPORT_PLUGIN2(), {How to Create Qt Plugins} */ @@ -82,7 +82,7 @@ Example: - \snippet doc/src/snippets/code/doc_src_qplugin.qdoc 1 + \snippet doc/src/snippets/code/doc_src_qplugin.cpp 1 See the \l{tools/plugandpaint}{Plug & Paint} example for details. @@ -102,14 +102,14 @@ Example: - \snippet doc/src/snippets/code/doc_src_qplugin.qdoc 2 + \snippet doc/src/snippets/code/doc_src_qplugin.cpp 2 Static plugins must also be included by the linker when your application is built. For Qt's predefined plugins, you can use the \c QTPLUGIN to add the required plugins to your build. For example: - \snippet doc/src/snippets/code/doc_src_qplugin.qdoc 3 + \snippet doc/src/snippets/code/doc_src_qplugin.pro 3 \sa {Static Plugins}, {How to Create Qt Plugins}, {Using qmake} */ diff --git a/src/corelib/statemachine/qhistorystate.cpp b/src/corelib/statemachine/qhistorystate.cpp index 350c1a0..7093c32 100644 --- a/src/corelib/statemachine/qhistorystate.cpp +++ b/src/corelib/statemachine/qhistorystate.cpp @@ -168,6 +168,9 @@ QAbstractState *QHistoryState::defaultState() const /*! Sets this history state's default state to be the given \a state. \a state must be a sibling of this history state. + + Note that this function does not set \a state as the initial state + of its parent. */ void QHistoryState::setDefaultState(QAbstractState *state) { diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 5177339..c2bc895 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -54,6 +54,11 @@ #include <private/qeventdispatcher_unix_p.h> #endif +#ifdef Q_OS_SYMBIAN +#include <hal.h> +#include <hal_data.h> +#endif + #include "qthreadstorage.h" #include "qthread_p.h" @@ -63,6 +68,12 @@ #include <sched.h> #include <errno.h> +// You only find these enumerations on Symbian^3 onwards, so we need to provide our own +// to remain compatible with older releases. They won't be called by pre-Sym^3 SDKs. + +// HALData::ENumCpus +#define QT_HALData_ENumCpus 119 + #ifdef Q_OS_BSD4 #include <sys/sysctl.h> #endif @@ -422,8 +433,20 @@ int QThread::idealThreadCount() // as of aug 2008 Integrity only supports one single core CPU cores = 1; #elif defined(Q_OS_SYMBIAN) - // ### TODO - Get the number of cores from HAL? when multicore architectures (SMP) are supported - cores = 1; + if (QSysInfo::symbianVersion() >= QSysInfo::SV_SF_3) { + TInt inumcpus; + TInt err; + err = HAL::Get((HALData::TAttribute)QT_HALData_ENumCpus, inumcpus); + if (err != KErrNone) { + cores = 1; + } else if ( inumcpus <= 0 ) { + cores = 1; + } else { + cores = inumcpus; + } + } else { + cores = 1; + } #elif defined(Q_OS_VXWORKS) // VxWorks # if defined(QT_VXWORKS_HAS_CPUSET) diff --git a/src/corelib/tools/qalgorithms.qdoc b/src/corelib/tools/qalgorithms.qdoc index 34918a3..a9b7ddc 100644 --- a/src/corelib/tools/qalgorithms.qdoc +++ b/src/corelib/tools/qalgorithms.qdoc @@ -60,14 +60,14 @@ a particular value. If you need that functionality, you can use qFill(): - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 0 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 0 qFill() takes a begin iterator, an end iterator, and a value. In the example above, we pass \c list.begin() and \c list.end() as the begin and end iterators, but this doesn't have to be the case: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 1 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 1 Different algorithms can have different requirements for the iterators they accept. For example, qFill() accepts two @@ -98,13 +98,13 @@ name_table array and return the corresponding Unicode value from the \c value_table if the entity is recognized: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 2 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 2 This kind of code is for advanced users only; for most applications, a QMap- or QHash-based approach would work just as well: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 3 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 3 \section1 Types of Iterators @@ -185,7 +185,7 @@ position \a begin2 + 1; and so on. Example: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 4 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 4 \sa qCopyBackward(), {input iterators}, {output iterators} */ @@ -201,7 +201,7 @@ at position \a end2 - 2; and so on. Example: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 5 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 5 \sa qCopy(), {bidirectional iterators} */ @@ -214,7 +214,7 @@ items compare equal; otherwise returns false. Example: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 6 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 6 This function requires the item type (in the example above, QString) to implement \c operator==(). @@ -228,7 +228,7 @@ Fills the range [\a begin, \a end) with \a value. Example: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 7 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 7 \sa qCopy(), {forward iterators} */ @@ -249,7 +249,7 @@ value isn't found. Example: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 8 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 8 This function requires the item type (in the example above, QString) to implement \c operator==(). @@ -278,7 +278,7 @@ Example: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 9 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 9 This function requires the item type (in the example above, \c int) to implement \c operator==(). @@ -302,7 +302,7 @@ of \a value in the variable passed as a reference in argument \a n. Exchanges the values of variables \a var1 and \a var2. Example: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 10 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 10 */ /*! \fn void qSort(RandomAccessIterator begin, RandomAccessIterator end) @@ -312,7 +312,7 @@ of \a value in the variable passed as a reference in argument \a n. using the quicksort algorithm. Example: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 11 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 11 The sort algorithm is efficient on large data sets. It operates in \l {linear-logarithmic time}, O(\e{n} log \e{n}). @@ -338,13 +338,13 @@ of \a value in the variable passed as a reference in argument \a n. For example, here's how to sort the strings in a QStringList in case-insensitive alphabetical order: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 12 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 12 To sort values in reverse order, pass \l{qGreater()}{qGreater<T>()} as the \a lessThan parameter. For example: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 13 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 13 If neither of the two items is "less than" the other, the items are taken to be equal. It is then undefined which one of the two @@ -356,7 +356,7 @@ of \a value in the variable passed as a reference in argument \a n. following code shows how to sort a list of strings case insensitively using QMap: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 14 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 14 \sa QMap */ @@ -382,7 +382,7 @@ of \a value in the variable passed as a reference in argument \a n. property is often useful when sorting user-visible data. Example: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 15 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 15 The sort algorithm is efficient on large data sets. It operates in \l {linear-logarithmic time}, O(\e{n} log \e{n}). @@ -405,7 +405,7 @@ of \a value in the variable passed as a reference in argument \a n. For example, here's how to sort the strings in a QStringList in case-insensitive alphabetical order: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 16 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 16 Note that earlier versions of Qt allowed using a lessThan function that took its arguments by non-const reference. From 4.3 and on this is no longer possible, @@ -415,7 +415,7 @@ of \a value in the variable passed as a reference in argument \a n. \l{qGreater()}{qGreater<T>()} as the \a lessThan parameter. For example: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 17 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 17 If neither of the two items is "less than" the other, the items are taken to be equal. The item that appeared before the other in the @@ -444,7 +444,7 @@ of \a value in the variable passed as a reference in argument \a n. ascending order; see qSort(). Example: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 18 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 18 This function requires the item type (in the example above, \c{int}) to implement \c operator<(). @@ -452,7 +452,7 @@ of \a value in the variable passed as a reference in argument \a n. qLowerBound() can be used in conjunction with qUpperBound() to iterate over all occurrences of the same value: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 19 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 19 \sa qUpperBound(), qBinaryFind() */ @@ -494,7 +494,7 @@ of \a value in the variable passed as a reference in argument \a n. ascending order; see qSort(). Example: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 20 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 20 This function requires the item type (in the example above, \c{int}) to implement \c operator<(). @@ -502,7 +502,7 @@ of \a value in the variable passed as a reference in argument \a n. qUpperBound() can be used in conjunction with qLowerBound() to iterate over all occurrences of the same value: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 21 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 21 \sa qLowerBound(), qBinaryFind() */ @@ -545,7 +545,7 @@ of \a value in the variable passed as a reference in argument \a n. finer control. Example: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 22 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 22 This function requires the item type (in the example above, QString) to implement \c operator<(). @@ -587,7 +587,7 @@ of \a value in the variable passed as a reference in argument \a n. example, \c{QWidget *}). Example: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 23 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 23 Notice that qDeleteAll() doesn't remove the items from the container; it merely calls \c delete on them. In the example @@ -618,7 +618,7 @@ of \a value in the variable passed as a reference in argument \a n. Example: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 24 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 24 \sa {qGreater()}{qGreater<T>()} */ @@ -631,7 +631,7 @@ of \a value in the variable passed as a reference in argument \a n. Example: - \snippet doc/src/snippets/code/doc_src_qalgorithms.qdoc 25 + \snippet doc/src/snippets/code/doc_src_qalgorithms.cpp 25 \sa {qLess()}{qLess<T>()} */ diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp index 568293d..641f8d5 100644 --- a/src/corelib/tools/qbytearray.cpp +++ b/src/corelib/tools/qbytearray.cpp @@ -1363,7 +1363,7 @@ QByteArray::QByteArray(int size, Qt::Initialization) If \a size is less than the current size, bytes are removed from the end. - \sa size() + \sa size(), truncate() */ void QByteArray::resize(int size) diff --git a/src/corelib/tools/qcache.qdoc b/src/corelib/tools/qcache.qdoc index 991238b..9e12c92 100644 --- a/src/corelib/tools/qcache.qdoc +++ b/src/corelib/tools/qcache.qdoc @@ -39,11 +39,11 @@ definition of a cache that stores objects of type Employee associated with an integer key: - \snippet doc/src/snippets/code/doc_src_qcache.qdoc 0 + \snippet doc/src/snippets/code/doc_src_qcache.cpp 0 Here's how to insert an object in the cache: - \snippet doc/src/snippets/code/doc_src_qcache.qdoc 1 + \snippet doc/src/snippets/code/doc_src_qcache.cpp 1 The advantage of using QCache over some other key-based data structure (such as QMap or QHash) is that QCache automatically @@ -59,7 +59,7 @@ By default, QCache's maxCost() is 100. You can specify a different value in the QCache constructor: - \snippet doc/src/snippets/code/doc_src_qcache.qdoc 2 + \snippet doc/src/snippets/code/doc_src_qcache.cpp 2 Each time you call insert(), you can specify a cost as third argument (after the key and a pointer to the object to insert). diff --git a/src/corelib/tools/qiterator.qdoc b/src/corelib/tools/qiterator.qdoc index d651343..6830442 100644 --- a/src/corelib/tools/qiterator.qdoc +++ b/src/corelib/tools/qiterator.qdoc @@ -50,7 +50,7 @@ the list (before the first item). Here's how to iterate over all the elements sequentially: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 0 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 0 The next() function returns the next item in the list and advances the iterator. Unlike STL-style iterators, Java-style @@ -65,7 +65,7 @@ Here's how to iterate over the elements in reverse order: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 1 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 1 If you want to find all occurrences of a particular value, use findNext() or findPrevious() in a loop. @@ -98,7 +98,7 @@ beginning of the list (before the first item). Here's how to iterate over all the elements sequentially: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 2 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 2 The next() function returns the next item in the list and advances the iterator. Unlike STL-style iterators, Java-style @@ -113,7 +113,7 @@ Here's how to iterate over the elements in reverse order: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 3 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 3 If you want to find all occurrences of a particular value, use findNext() or findPrevious() in a loop. @@ -150,7 +150,7 @@ of the vector (before the first item). Here's how to iterate over all the elements sequentially: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 4 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 4 The next() function returns the next item in the vector and advances the iterator. Unlike STL-style iterators, Java-style @@ -165,7 +165,7 @@ Here's how to iterate over the elements in reverse order: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 5 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 5 If you want to find all occurrences of a particular value, use findNext() or findPrevious() in a loop. @@ -197,7 +197,7 @@ the first item). Here's how to iterate over all the elements sequentially: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 6 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 6 The next() function returns the next item in the set and advances the iterator. Unlike STL-style iterators, Java-style @@ -212,7 +212,7 @@ Here's how to iterate over the elements in reverse order: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 7 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 7 If you want to find all occurrences of a particular value, use findNext() or findPrevious() in a loop. @@ -251,7 +251,7 @@ of the list (before the first item). Here's how to iterate over all the elements sequentially: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 8 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 8 The next() function returns the next item in the list and advances the iterator. Unlike STL-style iterators, Java-style @@ -266,7 +266,7 @@ Here's how to iterate over the elements in reverse order: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 9 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 9 If you want to find all occurrences of a particular value, use findNext() or findPrevious() in a loop. @@ -277,7 +277,7 @@ insert(). Example: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 10 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 10 The example traverses a list, replacing negative numbers with their absolute values, and eliminating zeroes. @@ -312,7 +312,7 @@ beginning of the list (before the first item). Here's how to iterate over all the elements sequentially: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 11 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 11 The next() function returns the next item in the list and advances the iterator. Unlike STL-style iterators, Java-style @@ -327,7 +327,7 @@ Here's how to iterate over the elements in reverse order: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 12 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 12 If you want to find all occurrences of a particular value, use findNext() or findPrevious() in a loop. @@ -338,7 +338,7 @@ insert(). Example: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 13 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 13 The example traverses a list, replacing negative numbers with their absolute values, and eliminating zeroes. @@ -378,7 +378,7 @@ beginning of the list (before the first item). Here's how to iterate over all the elements sequentially: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 14 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 14 The next() function returns the next item in the vector and advances the iterator. Unlike STL-style iterators, Java-style @@ -393,7 +393,7 @@ Here's how to iterate over the elements in reverse order: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 15 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 15 If you want to find all occurrences of a particular value, use findNext() or findPrevious() in a loop. @@ -404,7 +404,7 @@ insert(). Example: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 16 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 16 The example traverses a vector, replacing negative numbers with their absolute values, and eliminating zeroes. @@ -440,7 +440,7 @@ of the set (before the first item). Here's how to iterate over all the elements sequentially: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 17 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 17 The next() function returns the next item in the set and advances the iterator. Unlike STL-style iterators, Java-style @@ -455,7 +455,7 @@ Here's how to iterate over the elements in reverse order: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 18 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 18 If you want to remove items as you iterate over the set, use remove(). @@ -755,7 +755,7 @@ traversal functions (next(), previous(), findNext(), findPrevious()). Example: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 19 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 19 \sa insert(), setValue() */ @@ -766,7 +766,7 @@ traversal functions (next(), previous(), findNext(), findPrevious()). Example: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 20 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 20 \sa insert(), setValue() */ @@ -777,7 +777,7 @@ traversal functions (next(), previous(), findNext(), findPrevious()). Example: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 21 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 21 \sa insert(), setValue() */ @@ -788,7 +788,7 @@ traversal functions (next(), previous(), findNext(), findPrevious()). Example: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 22 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 22 \sa value() */ @@ -802,7 +802,7 @@ findPrevious(). Example: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 23 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 23 \sa value(), remove(), insert() */ @@ -816,7 +816,7 @@ findPrevious(). Example: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 24 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 24 \sa value(), remove(), insert() */ @@ -830,7 +830,7 @@ findPrevious(). Example: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 25 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 25 \sa value(), remove(), insert() */ @@ -889,7 +889,7 @@ the map (before the first item). Here's how to iterate over all the elements sequentially: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 26 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 26 The next() function returns the next item in the map and advances the iterator. The key() and value() functions return the @@ -906,12 +906,12 @@ Here's how to iterate over the elements in reverse order: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 27 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 27 If you want to find all occurrences of a particular value, use findNext() or findPrevious() in a loop. For example: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 28 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 28 Multiple iterators can be used on the same map. If the map is modified while a QMapIterator is active, the QMapIterator will @@ -941,7 +941,7 @@ the hash (before the first item). Here's how to iterate over all the elements sequentially: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 29 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 29 The next() function returns the next item in the hash and advances the iterator. The key() and value() functions return the @@ -958,12 +958,12 @@ Here's how to iterate over the elements in reverse order: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 30 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 30 If you want to find all occurrences of a particular value, use findNext() or findPrevious() in a loop. For example: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 31 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 31 Multiple iterators can be used on the same hash. If the hash is modified while a QHashIterator is active, the QHashIterator will @@ -994,7 +994,7 @@ of the map (before the first item). Here's how to iterate over all the elements sequentially: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 32 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 32 The next() function returns the next item in the map and advances the iterator. The key() and value() functions return the @@ -1011,12 +1011,12 @@ Here's how to iterate over the elements in reverse order: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 33 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 33 If you want to find all occurrences of a particular value, use findNext() or findPrevious() in a loop. For example: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 34 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 34 If you want to remove items as you iterate over the map, use remove(). If you want to modify the value of an item, use @@ -1024,7 +1024,7 @@ Example: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 35 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 35 The example removes all (key, value) pairs where the key and the value are the same. @@ -1059,7 +1059,7 @@ of the hash (before the first item). Here's how to iterate over all the elements sequentially: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 36 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 36 The next() function returns the next item in the hash and advances the iterator. The key() and value() functions return the @@ -1076,12 +1076,12 @@ Here's how to iterate over the elements in reverse order: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 37 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 37 If you want to find all occurrences of a particular value, use findNext() or findPrevious() in a loop. For example: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 38 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 38 If you want to remove items as you iterate over the hash, use remove(). If you want to modify the value of an item, use @@ -1089,7 +1089,7 @@ Example: - \snippet doc/src/snippets/code/doc_src_qiterator.qdoc 39 + \snippet doc/src/snippets/code/doc_src_qiterator.cpp 39 The example removes all (key, value) pairs where the key and the value are the same. diff --git a/src/corelib/tools/qmap.cpp b/src/corelib/tools/qmap.cpp index fe53374..2c028af 100644 --- a/src/corelib/tools/qmap.cpp +++ b/src/corelib/tools/qmap.cpp @@ -1073,7 +1073,7 @@ void QMapData::dump() \overload - The prefix -- operator (\c{--i}) makes the preceding item + The postfix -- operator (\c{i--}) makes the preceding item current and returns an iterator pointing to the previously current item. */ diff --git a/src/corelib/tools/qpair.qdoc b/src/corelib/tools/qpair.qdoc index b900c4f..925100d 100644 --- a/src/corelib/tools/qpair.qdoc +++ b/src/corelib/tools/qpair.qdoc @@ -40,12 +40,12 @@ Here's an example of a QPair that stores one QString and one \c double value: - \snippet doc/src/snippets/code/doc_src_qpair.qdoc 0 + \snippet doc/src/snippets/code/doc_src_qpair.cpp 0 The components are accessible as public data members called \l first and \l second. For example: - \snippet doc/src/snippets/code/doc_src_qpair.qdoc 1 + \snippet doc/src/snippets/code/doc_src_qpair.cpp 1 QPair's template data types (T1 and T2) must be \l{assignable data types}. You cannot, for example, store a QWidget as a value; @@ -186,7 +186,7 @@ Returns a QPair\<T1, T2\> that contains \a value1 and \a value2. Example: - \snippet doc/src/snippets/code/doc_src_qpair.qdoc 2 + \snippet doc/src/snippets/code/doc_src_qpair.cpp 2 This is equivalent to QPair<T1, T2>(\a value1, \a value2), but usually requires less typing. diff --git a/src/corelib/tools/qset.qdoc b/src/corelib/tools/qset.qdoc index 011e9ee..5249182 100644 --- a/src/corelib/tools/qset.qdoc +++ b/src/corelib/tools/qset.qdoc @@ -40,19 +40,19 @@ Here's an example QSet with QString values: - \snippet doc/src/snippets/code/doc_src_qset.qdoc 0 + \snippet doc/src/snippets/code/doc_src_qset.cpp 0 To insert a value into the set, use insert(): - \snippet doc/src/snippets/code/doc_src_qset.qdoc 1 + \snippet doc/src/snippets/code/doc_src_qset.cpp 1 Another way to insert items into the set is to use operator<<(): - \snippet doc/src/snippets/code/doc_src_qset.qdoc 2 + \snippet doc/src/snippets/code/doc_src_qset.cpp 2 To test whether an item belongs to the set or not, use contains(): - \snippet doc/src/snippets/code/doc_src_qset.qdoc 3 + \snippet doc/src/snippets/code/doc_src_qset.cpp 3 If you want to navigate through all the values stored in a QSet, you can use an iterator. QSet supports both \l{Java-style @@ -60,18 +60,18 @@ iterators} (QSet::iterator and QSet::const_iterator). Here's how to iterate over a QSet<QWidget *> using a Java-style iterator: - \snippet doc/src/snippets/code/doc_src_qset.qdoc 4 + \snippet doc/src/snippets/code/doc_src_qset.cpp 4 Here's the same code, but using an STL-style iterator: - \snippet doc/src/snippets/code/doc_src_qset.qdoc 5 + \snippet doc/src/snippets/code/doc_src_qset.cpp 5 QSet is unordered, so an iterator's sequence cannot be assumed to be predictable. If ordering by key is required, use a QMap. To navigate through a QSet, you can also use \l{foreach}: - \snippet doc/src/snippets/code/doc_src_qset.qdoc 6 + \snippet doc/src/snippets/code/doc_src_qset.cpp 6 Items can be removed from the set using remove(). There is also a clear() function that removes all items. @@ -187,7 +187,7 @@ This function is useful for code that needs to build a huge set and wants to avoid repeated reallocation. For example: - \snippet doc/src/snippets/code/doc_src_qset.qdoc 7 + \snippet doc/src/snippets/code/doc_src_qset.cpp 7 Ideally, \a size should be slightly more than the maximum number of elements expected in the set. \a size doesn't have to be prime, @@ -603,18 +603,18 @@ start iterating. Here's a typical loop that prints all the items stored in a set: - \snippet doc/src/snippets/code/doc_src_qset.qdoc 8 + \snippet doc/src/snippets/code/doc_src_qset.cpp 8 Here's a loop that removes certain items (all those that start with 'J') from a set while iterating: - \snippet doc/src/snippets/code/doc_src_qset.qdoc 9 + \snippet doc/src/snippets/code/doc_src_qset.cpp 9 STL-style iterators can be used as arguments to \l{generic algorithms}. For example, here's how to find an item in the set using the qFind() algorithm: - \snippet doc/src/snippets/code/doc_src_qset.qdoc 10 + \snippet doc/src/snippets/code/doc_src_qset.cpp 10 Multiple iterators can be used on the same set. However, you may not attempt to modify the container while iterating on it. @@ -646,13 +646,13 @@ start iterating. Here's a typical loop that prints all the items stored in a set: - \snippet doc/src/snippets/code/doc_src_qset.qdoc 11 + \snippet doc/src/snippets/code/doc_src_qset.cpp 11 STL-style iterators can be used as arguments to \l{generic algorithms}. For example, here's how to find an item in the set using the qFind() algorithm: - \snippet doc/src/snippets/code/doc_src_qset.qdoc 12 + \snippet doc/src/snippets/code/doc_src_qset.cpp 12 Multiple iterators can be used on the same set. However, you may not attempt to modify the container while iterating on it. @@ -886,7 +886,7 @@ Example: - \snippet doc/src/snippets/code/doc_src_qset.qdoc 13 + \snippet doc/src/snippets/code/doc_src_qset.cpp 13 \sa fromList(), QList::fromSet(), qSort() */ @@ -911,7 +911,7 @@ Example: - \snippet doc/src/snippets/code/doc_src_qset.qdoc 14 + \snippet doc/src/snippets/code/doc_src_qset.cpp 14 \sa toList(), QList::toSet() */ diff --git a/src/corelib/tools/qtextboundaryfinder.cpp b/src/corelib/tools/qtextboundaryfinder.cpp index c2bb094..34bc406 100644 --- a/src/corelib/tools/qtextboundaryfinder.cpp +++ b/src/corelib/tools/qtextboundaryfinder.cpp @@ -457,33 +457,23 @@ QTextBoundaryFinder::BoundaryReasons QTextBoundaryFinder::boundaryReasons() cons return NotAtBoundary; return StartWord; } - if (pos >= length - 1) { + if (pos == length) { if (d->attributes[length-1].whiteSpace) return NotAtBoundary; return EndWord; } - BoundaryReasons answer; - const bool nextIsSpace = d->attributes[pos + 1].whiteSpace; + const bool nextIsSpace = d->attributes[pos].whiteSpace; const bool prevIsSpace = d->attributes[pos - 1].whiteSpace; - if (d->attributes[pos].whiteSpace) - answer = EndWord; - else if (!prevIsSpace) { - answer = StartWord; - answer |= EndWord; - } - - if (prevIsSpace) - answer |= StartWord; - if (nextIsSpace) - answer |= EndWord; - if (answer == 0) { - answer = StartWord; - answer |= EndWord; - } - - return answer; + if (prevIsSpace && !nextIsSpace) + return StartWord; + else if (!prevIsSpace && nextIsSpace) + return EndWord; + else if (!prevIsSpace && !nextIsSpace) + return BoundaryReasons(StartWord | EndWord); + else + return NotAtBoundary; } QT_END_NAMESPACE diff --git a/src/corelib/tools/qvarlengtharray.qdoc b/src/corelib/tools/qvarlengtharray.qdoc index d68e8a1..996ca7f 100644 --- a/src/corelib/tools/qvarlengtharray.qdoc +++ b/src/corelib/tools/qvarlengtharray.qdoc @@ -35,12 +35,12 @@ The C++ language doesn't support variable-length arrays on the stack. For example, the following code won't compile: - \snippet doc/src/snippets/code/doc_src_qvarlengtharray.qdoc 0 + \snippet doc/src/snippets/code/doc_src_qvarlengtharray.cpp 0 The alternative is to allocate the array on the heap (with \c{new}): - \snippet doc/src/snippets/code/doc_src_qvarlengtharray.qdoc 1 + \snippet doc/src/snippets/code/doc_src_qvarlengtharray.cpp 1 However, if myfunc() is called very frequently from the application's inner loop, heap allocation can be a major source @@ -53,7 +53,7 @@ it is much faster than heap allocation. Example: - \snippet doc/src/snippets/code/doc_src_qvarlengtharray.qdoc 2 + \snippet doc/src/snippets/code/doc_src_qvarlengtharray.cpp 2 In the example above, QVarLengthArray will preallocate 1024 elements on the stack and use them unless \c{n + 1} is greater @@ -223,7 +223,7 @@ be used to access and modify the items in the array. Example: - \snippet doc/src/snippets/code/doc_src_qvarlengtharray.qdoc 3 + \snippet doc/src/snippets/code/doc_src_qvarlengtharray.cpp 3 The pointer remains valid as long as the array isn't reallocated. diff --git a/src/declarative/debugger/qdeclarativedebughelper.cpp b/src/declarative/debugger/qdeclarativedebughelper.cpp index 0478209..93f7423 100644 --- a/src/declarative/debugger/qdeclarativedebughelper.cpp +++ b/src/declarative/debugger/qdeclarativedebughelper.cpp @@ -65,10 +65,12 @@ void QDeclarativeDebugHelper::setAnimationSlowDownFactor(qreal factor) } void QDeclarativeDebugHelper::enableDebugging() { +#ifndef QDECLARATIVE_NO_DEBUG_PROTOCOL if (!QDeclarativeEnginePrivate::qml_debugging_enabled) { qWarning("Qml debugging is enabled. Only use this in a safe environment!"); } QDeclarativeEnginePrivate::qml_debugging_enabled = true; +#endif } QT_END_NAMESPACE diff --git a/src/declarative/debugger/qdeclarativedebugserver.cpp b/src/declarative/debugger/qdeclarativedebugserver.cpp index ea3d9a3..18258f5 100644 --- a/src/declarative/debugger/qdeclarativedebugserver.cpp +++ b/src/declarative/debugger/qdeclarativedebugserver.cpp @@ -91,7 +91,7 @@ public: QStringList clientPlugins; bool gotHello; - static QDeclarativeDebugServerConnection *loadConnectionPlugin(); + static QDeclarativeDebugServerConnection *loadConnectionPlugin(const QString &pluginName); }; QDeclarativeDebugServerPrivate::QDeclarativeDebugServerPrivate() : @@ -113,7 +113,8 @@ void QDeclarativeDebugServerPrivate::advertisePlugins() connection->send(message); } -QDeclarativeDebugServerConnection *QDeclarativeDebugServerPrivate::loadConnectionPlugin() +QDeclarativeDebugServerConnection *QDeclarativeDebugServerPrivate::loadConnectionPlugin( + const QString &pluginName) { QStringList pluginCandidates; const QStringList paths = QCoreApplication::libraryPaths(); @@ -122,7 +123,8 @@ QDeclarativeDebugServerConnection *QDeclarativeDebugServerPrivate::loadConnectio if (dir.exists()) { QStringList plugins(dir.entryList(QDir::Files)); foreach (const QString &pluginPath, plugins) { - pluginCandidates << dir.absoluteFilePath(pluginPath); + if (QFileInfo(pluginPath).fileName().contains(pluginName)) + pluginCandidates << dir.absoluteFilePath(pluginPath); } } } @@ -159,14 +161,14 @@ QDeclarativeDebugServer *QDeclarativeDebugServer::instance() if (!commandLineTested) { commandLineTested = true; -#ifndef QDECLARATIVE_NO_DEBUG_PROTOCOL QApplicationPrivate *appD = static_cast<QApplicationPrivate*>(QObjectPrivate::get(qApp)); +#ifndef QDECLARATIVE_NO_DEBUG_PROTOCOL // ### remove port definition when protocol is changed int port = 0; bool block = false; bool ok = false; - // format: qmljsdebugger=port:3768[,block] + // format: qmljsdebugger=port:3768[,block] OR qmljsdebugger=ost[,block] if (!appD->qmljsDebugArgumentsString().isEmpty()) { if (!QDeclarativeEnginePrivate::qml_debugging_enabled) { const QString message = @@ -177,17 +179,23 @@ QDeclarativeDebugServer *QDeclarativeDebugServer::instance() return 0; } + QString pluginName; if (appD->qmljsDebugArgumentsString().indexOf(QLatin1String("port:")) == 0) { int separatorIndex = appD->qmljsDebugArgumentsString().indexOf(QLatin1Char(',')); port = appD->qmljsDebugArgumentsString().mid(5, separatorIndex - 5).toInt(&ok); + pluginName = QLatin1String("qmldbg_tcp"); + } else if (appD->qmljsDebugArgumentsString().contains("ost")) { + pluginName = QLatin1String("qmldbg_ost"); + ok = true; } + block = appD->qmljsDebugArgumentsString().contains(QLatin1String("block")); if (ok) { server = new QDeclarativeDebugServer(); QDeclarativeDebugServerConnection *connection - = QDeclarativeDebugServerPrivate::loadConnectionPlugin(); + = QDeclarativeDebugServerPrivate::loadConnectionPlugin(pluginName); if (connection) { server->d_func()->connection = connection; @@ -204,6 +212,12 @@ QDeclarativeDebugServer *QDeclarativeDebugServer::instance() appD->qmljsDebugArgumentsString()).toAscii().constData()); } } +#else + if (!appD->qmljsDebugArgumentsString().isEmpty()) { + qWarning(QString::fromAscii("QDeclarativeDebugServer: Ignoring \"-qmljsdebugger=%1\". " + "QtDeclarative is not configured for debugging.").arg( + appD->qmljsDebugArgumentsString()).toAscii().constData()); + } #endif } diff --git a/src/declarative/declarative.pro b/src/declarative/declarative.pro index 1ad888b..f3a7db9 100644 --- a/src/declarative/declarative.pro +++ b/src/declarative/declarative.pro @@ -29,6 +29,8 @@ symbian: { LIBS += -lefsrv } +linux-g++-maemo:DEFINES += QDECLARATIVEVIEW_NOBACKGROUND + DEFINES += QT_NO_OPENTYPE INCLUDEPATH += ../3rdparty/harfbuzz/src diff --git a/src/declarative/graphicsitems/qdeclarativeanchors.cpp b/src/declarative/graphicsitems/qdeclarativeanchors.cpp index 444bbd4..5ff6d2c 100644 --- a/src/declarative/graphicsitems/qdeclarativeanchors.cpp +++ b/src/declarative/graphicsitems/qdeclarativeanchors.cpp @@ -175,16 +175,19 @@ QDeclarativeAnchors::~QDeclarativeAnchors() void QDeclarativeAnchorsPrivate::fillChanged() { + Q_Q(QDeclarativeAnchors); if (!fill || !isItemComplete()) return; if (updatingFill < 2) { ++updatingFill; + qreal horizontalMargin = q->mirrored() ? rightMargin : leftMargin; + if (fill == item->parentItem()) { //child-parent - setItemPos(QPointF(leftMargin, topMargin)); + setItemPos(QPointF(horizontalMargin, topMargin)); } else if (fill->parentItem() == item->parentItem()) { //siblings - setItemPos(QPointF(fill->x()+leftMargin, fill->y()+topMargin)); + setItemPos(QPointF(fill->x()+horizontalMargin, fill->y()+topMargin)); } QGraphicsItemPrivate *fillPrivate = QGraphicsItemPrivate::get(fill); setItemSize(QSizeF(fillPrivate->width()-leftMargin-rightMargin, fillPrivate->height()-topMargin-bottomMargin)); @@ -199,18 +202,21 @@ void QDeclarativeAnchorsPrivate::fillChanged() void QDeclarativeAnchorsPrivate::centerInChanged() { + Q_Q(QDeclarativeAnchors); if (!centerIn || fill || !isItemComplete()) return; if (updatingCenterIn < 2) { ++updatingCenterIn; + + qreal effectiveHCenterOffset = q->mirrored() ? -hCenterOffset : hCenterOffset; if (centerIn == item->parentItem()) { - QPointF p(hcenter(item->parentItem()) - hcenter(item) + hCenterOffset, + QPointF p(hcenter(item->parentItem()) - hcenter(item) + effectiveHCenterOffset, vcenter(item->parentItem()) - vcenter(item) + vCenterOffset); setItemPos(p); } else if (centerIn->parentItem() == item->parentItem()) { - QPointF p(centerIn->x() + hcenter(centerIn) - hcenter(item) + hCenterOffset, + QPointF p(centerIn->x() + hcenter(centerIn) - hcenter(item) + effectiveHCenterOffset, centerIn->y() + vcenter(centerIn) - vcenter(item) + vCenterOffset); setItemPos(p); } @@ -311,6 +317,13 @@ void QDeclarativeAnchors::componentComplete() d->componentComplete = true; } +bool QDeclarativeAnchors::mirrored() +{ + Q_D(QDeclarativeAnchors); + QGraphicsItemPrivate * itemPrivate = QGraphicsItemPrivate::get(d->item); + return itemPrivate->isDeclarativeItem ? static_cast<QDeclarativeItemPrivate *>(itemPrivate)->effectiveLayoutMirror : false; +} + void QDeclarativeAnchorsPrivate::setItemHeight(qreal v) { updatingMe = true; @@ -570,58 +583,94 @@ void QDeclarativeAnchorsPrivate::updateVerticalAnchors() } } +inline QDeclarativeAnchorLine::AnchorLine reverseAnchorLine(QDeclarativeAnchorLine::AnchorLine anchorLine) { + if (anchorLine == QDeclarativeAnchorLine::Left) { + return QDeclarativeAnchorLine::Right; + } else if (anchorLine == QDeclarativeAnchorLine::Right) { + return QDeclarativeAnchorLine::Left; + } else { + return anchorLine; + } +} + void QDeclarativeAnchorsPrivate::updateHorizontalAnchors() { + Q_Q(QDeclarativeAnchors); if (fill || centerIn || !isItemComplete()) return; - if (updatingHorizontalAnchor < 2) { + if (updatingHorizontalAnchor < 3) { ++updatingHorizontalAnchor; + qreal effectiveRightMargin, effectiveLeftMargin, effectiveHorizontalCenterOffset; + QDeclarativeAnchorLine effectiveLeft, effectiveRight, effectiveHorizontalCenter; + QDeclarativeAnchors::Anchor effectiveLeftAnchor, effectiveRightAnchor; + if (q->mirrored()) { + effectiveLeftAnchor = QDeclarativeAnchors::RightAnchor; + effectiveRightAnchor = QDeclarativeAnchors::LeftAnchor; + effectiveLeft.item = right.item; + effectiveLeft.anchorLine = reverseAnchorLine(right.anchorLine); + effectiveRight.item = left.item; + effectiveRight.anchorLine = reverseAnchorLine(left.anchorLine); + effectiveHorizontalCenter.item = hCenter.item; + effectiveHorizontalCenter.anchorLine = reverseAnchorLine(hCenter.anchorLine); + effectiveLeftMargin = rightMargin; + effectiveRightMargin = leftMargin; + effectiveHorizontalCenterOffset = -hCenterOffset; + } else { + effectiveLeftAnchor = QDeclarativeAnchors::LeftAnchor; + effectiveRightAnchor = QDeclarativeAnchors::RightAnchor; + effectiveLeft = left; + effectiveRight = right; + effectiveHorizontalCenter = hCenter; + effectiveLeftMargin = leftMargin; + effectiveRightMargin = rightMargin; + effectiveHorizontalCenterOffset = hCenterOffset; + } + QGraphicsItemPrivate *itemPrivate = QGraphicsItemPrivate::get(item); - if (usedAnchors & QDeclarativeAnchors::LeftAnchor) { + if (usedAnchors & effectiveLeftAnchor) { //Handle stretching bool invalid = true; qreal width = 0.0; - if (usedAnchors & QDeclarativeAnchors::RightAnchor) { - invalid = calcStretch(left, right, leftMargin, -rightMargin, QDeclarativeAnchorLine::Left, width); + if (usedAnchors & effectiveRightAnchor) { + invalid = calcStretch(effectiveLeft, effectiveRight, effectiveLeftMargin, -effectiveRightMargin, QDeclarativeAnchorLine::Left, width); } else if (usedAnchors & QDeclarativeAnchors::HCenterAnchor) { - invalid = calcStretch(left, hCenter, leftMargin, hCenterOffset, QDeclarativeAnchorLine::Left, width); + invalid = calcStretch(effectiveLeft, effectiveHorizontalCenter, effectiveLeftMargin, effectiveHorizontalCenterOffset, QDeclarativeAnchorLine::Left, width); width *= 2; } if (!invalid) setItemWidth(width); //Handle left - if (left.item == item->parentItem()) { - setItemX(adjustedPosition(left.item, left.anchorLine) + leftMargin); - } else if (left.item->parentItem() == item->parentItem()) { - setItemX(position(left.item, left.anchorLine) + leftMargin); + if (effectiveLeft.item == item->parentItem()) { + setItemX(adjustedPosition(effectiveLeft.item, effectiveLeft.anchorLine) + effectiveLeftMargin); + } else if (effectiveLeft.item->parentItem() == item->parentItem()) { + setItemX(position(effectiveLeft.item, effectiveLeft.anchorLine) + effectiveLeftMargin); } - } else if (usedAnchors & QDeclarativeAnchors::RightAnchor) { + } else if (usedAnchors & effectiveRightAnchor) { //Handle stretching (left + right case is handled in updateLeftAnchor) if (usedAnchors & QDeclarativeAnchors::HCenterAnchor) { qreal width = 0.0; - bool invalid = calcStretch(hCenter, right, hCenterOffset, -rightMargin, + bool invalid = calcStretch(effectiveHorizontalCenter, effectiveRight, effectiveHorizontalCenterOffset, -effectiveRightMargin, QDeclarativeAnchorLine::Left, width); if (!invalid) setItemWidth(width*2); } //Handle right - if (right.item == item->parentItem()) { - setItemX(adjustedPosition(right.item, right.anchorLine) - itemPrivate->width() - rightMargin); - } else if (right.item->parentItem() == item->parentItem()) { - setItemX(position(right.item, right.anchorLine) - itemPrivate->width() - rightMargin); + if (effectiveRight.item == item->parentItem()) { + setItemX(adjustedPosition(effectiveRight.item, effectiveRight.anchorLine) - itemPrivate->width() - effectiveRightMargin); + } else if (effectiveRight.item->parentItem() == item->parentItem()) { + setItemX(position(effectiveRight.item, effectiveRight.anchorLine) - itemPrivate->width() - effectiveRightMargin); } } else if (usedAnchors & QDeclarativeAnchors::HCenterAnchor) { //Handle hCenter - if (hCenter.item == item->parentItem()) { - setItemX(adjustedPosition(hCenter.item, hCenter.anchorLine) - hcenter(item) + hCenterOffset); - } else if (hCenter.item->parentItem() == item->parentItem()) { - setItemX(position(hCenter.item, hCenter.anchorLine) - hcenter(item) + hCenterOffset); + if (effectiveHorizontalCenter.item == item->parentItem()) { + setItemX(adjustedPosition(effectiveHorizontalCenter.item, effectiveHorizontalCenter.anchorLine) - hcenter(item) + effectiveHorizontalCenterOffset); + } else if (effectiveHorizontalCenter.item->parentItem() == item->parentItem()) { + setItemX(position(effectiveHorizontalCenter.item, effectiveHorizontalCenter.anchorLine) - hcenter(item) + effectiveHorizontalCenterOffset); } } - --updatingHorizontalAnchor; } else { // ### Make this certain :) diff --git a/src/declarative/graphicsitems/qdeclarativeanchors_p.h b/src/declarative/graphicsitems/qdeclarativeanchors_p.h index d2c0a89..388d6b9 100644 --- a/src/declarative/graphicsitems/qdeclarativeanchors_p.h +++ b/src/declarative/graphicsitems/qdeclarativeanchors_p.h @@ -79,6 +79,7 @@ class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeAnchors : public QObject Q_PROPERTY(qreal baselineOffset READ baselineOffset WRITE setBaselineOffset NOTIFY baselineOffsetChanged) Q_PROPERTY(QGraphicsObject *fill READ fill WRITE setFill RESET resetFill NOTIFY fillChanged) Q_PROPERTY(QGraphicsObject *centerIn READ centerIn WRITE setCenterIn RESET resetCenterIn NOTIFY centerInChanged) + Q_PROPERTY(bool mirrored READ mirrored NOTIFY mirroredChanged REVISION 1) public: QDeclarativeAnchors(QObject *parent=0); @@ -163,6 +164,8 @@ public: void classBegin(); void componentComplete(); + bool mirrored(); + Q_SIGNALS: void leftChanged(); void rightChanged(); @@ -181,9 +184,11 @@ Q_SIGNALS: void verticalCenterOffsetChanged(); void horizontalCenterOffsetChanged(); void baselineOffsetChanged(); + Q_REVISION(1) void mirroredChanged(); private: friend class QDeclarativeItem; + friend class QDeclarativeItemPrivate; friend class QDeclarativeGraphicsWidget; Q_DISABLE_COPY(QDeclarativeAnchors) Q_DECLARE_PRIVATE(QDeclarativeAnchors) diff --git a/src/declarative/graphicsitems/qdeclarativeanchors_p_p.h b/src/declarative/graphicsitems/qdeclarativeanchors_p_p.h index c4508e0..d8d2f15 100644 --- a/src/declarative/graphicsitems/qdeclarativeanchors_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativeanchors_p_p.h @@ -133,6 +133,7 @@ public: bool checkVAnchorValid(QDeclarativeAnchorLine anchor) const; bool calcStretch(const QDeclarativeAnchorLine &edge1, const QDeclarativeAnchorLine &edge2, qreal offset1, qreal offset2, QDeclarativeAnchorLine::AnchorLine line, qreal &stretch); + bool isMirrored() const; void updateHorizontalAnchors(); void updateVerticalAnchors(); void fillChanged(); diff --git a/src/declarative/graphicsitems/qdeclarativeanimatedimage.cpp b/src/declarative/graphicsitems/qdeclarativeanimatedimage.cpp index 016b87d..8cc8165 100644 --- a/src/declarative/graphicsitems/qdeclarativeanimatedimage.cpp +++ b/src/declarative/graphicsitems/qdeclarativeanimatedimage.cpp @@ -231,9 +231,18 @@ void QDeclarativeAnimatedImage::load() { Q_D(QDeclarativeAnimatedImage); + QDeclarativeImageBase::Status oldStatus = d->status; + qreal oldProgress = d->progress; + if (d->url.isEmpty()) { delete d->_movie; + d->setPixmap(QPixmap()); + d->progress = 0; d->status = Null; + if (d->status != oldStatus) + emit statusChanged(d->status); + if (d->progress != oldProgress) + emit progressChanged(d->progress); } else { #ifndef QT_NO_LOCALFILE_OPTIMIZED_QML QString lf = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(d->url); @@ -245,7 +254,8 @@ void QDeclarativeAnimatedImage::load() delete d->_movie; d->_movie = 0; d->status = Error; - emit statusChanged(d->status); + if (d->status != oldStatus) + emit statusChanged(d->status); return; } connect(d->_movie, SIGNAL(stateChanged(QMovie::MovieState)), @@ -262,20 +272,25 @@ void QDeclarativeAnimatedImage::load() d->setPixmap(d->_movie->currentPixmap()); d->status = Ready; d->progress = 1.0; - emit statusChanged(d->status); - emit sourceChanged(d->url); - emit progressChanged(d->progress); + if (d->status != oldStatus) + emit statusChanged(d->status); + if (d->progress != oldProgress) + emit progressChanged(d->progress); return; } #endif d->status = Loading; + d->progress = 0; + emit statusChanged(d->status); + emit progressChanged(d->progress); QNetworkRequest req(d->url); req.setAttribute(QNetworkRequest::HttpPipeliningAllowedAttribute, true); d->reply = qmlEngine(this)->networkAccessManager()->get(req); QObject::connect(d->reply, SIGNAL(finished()), this, SLOT(movieRequestFinished())); + QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), + this, SLOT(requestProgress(qint64,qint64))); } - emit statusChanged(d->status); } #define ANIMATEDIMAGE_MAXIMUM_REDIRECT_RECURSION 16 diff --git a/src/declarative/graphicsitems/qdeclarativeborderimage.cpp b/src/declarative/graphicsitems/qdeclarativeborderimage.cpp index 8f37e90..45a03a0 100644 --- a/src/declarative/graphicsitems/qdeclarativeborderimage.cpp +++ b/src/declarative/graphicsitems/qdeclarativeborderimage.cpp @@ -300,7 +300,7 @@ void QDeclarativeBorderImage::load() } if (d->url.isEmpty()) { - d->pix.clear(); + d->pix.clear(this); d->status = Null; setImplicitWidth(0); setImplicitHeight(0); @@ -340,6 +340,7 @@ void QDeclarativeBorderImage::load() options |= QDeclarativePixmap::Asynchronous; if (d->cache) options |= QDeclarativePixmap::Cache; + d->pix.clear(this); d->pix.load(qmlEngine(this), d->url, options); if (d->pix.isLoading()) { @@ -472,6 +473,7 @@ void QDeclarativeBorderImage::setGridScaledImage(const QDeclarativeGridScaledIma options |= QDeclarativePixmap::Asynchronous; if (d->cache) options |= QDeclarativePixmap::Cache; + d->pix.clear(this); d->pix.load(qmlEngine(this), d->sciurl, options); if (d->pix.isLoading()) { diff --git a/src/declarative/graphicsitems/qdeclarativeflickable.cpp b/src/declarative/graphicsitems/qdeclarativeflickable.cpp index d64c347..82ed18c 100644 --- a/src/declarative/graphicsitems/qdeclarativeflickable.cpp +++ b/src/declarative/graphicsitems/qdeclarativeflickable.cpp @@ -45,9 +45,40 @@ #include <QGraphicsSceneMouseEvent> #include <QPointer> #include <QTimer> +#include "qplatformdefs.h" QT_BEGIN_NAMESPACE +// The maximum number of pixels a flick can overshoot +#ifndef QML_FLICK_OVERSHOOT +#define QML_FLICK_OVERSHOOT 200 +#endif + +// The number of samples to use in calculating the velocity of a flick +#ifndef QML_FLICK_SAMPLEBUFFER +#define QML_FLICK_SAMPLEBUFFER 3 +#endif + +// The number of samples to discard when calculating the flick velocity. +// Touch panels often produce inaccurate results as the finger is lifted. +#ifndef QML_FLICK_DISCARDSAMPLES +#define QML_FLICK_DISCARDSAMPLES 1 +#endif + +// The default maximum velocity of a flick. +#ifndef QML_FLICK_DEFAULTMAXVELOCITY +#define QML_FLICK_DEFAULTMAXVELOCITY 2500 +#endif + +// The default deceleration of a flick. +#ifndef QML_FLICK_DEFAULTDECELERATION +#define QML_FLICK_DEFAULTDECELERATION 1750 +#endif + +// How much faster to decelerate when overshooting +#ifndef QML_FLICK_OVERSHOOTFRICTION +#define QML_FLICK_OVERSHOOTFRICTION 8 +#endif // FlickThreshold determines how far the "mouse" must have moved // before we perform a flick. @@ -141,8 +172,9 @@ QDeclarativeFlickablePrivate::QDeclarativeFlickablePrivate() , hMoved(false), vMoved(false) , movingHorizontally(false), movingVertically(false) , stealMouse(false), pressed(false), interactive(true), calcVelocity(false) - , deceleration(500), maxVelocity(2000), reportedVelocitySmoothing(100) - , delayedPressEvent(0), delayedPressTarget(0), pressDelay(0), fixupDuration(600) + , deceleration(QML_FLICK_DEFAULTDECELERATION) + , maxVelocity(QML_FLICK_DEFAULTMAXVELOCITY), reportedVelocitySmoothing(100) + , delayedPressEvent(0), delayedPressTarget(0), pressDelay(0), fixupDuration(400) , fixupMode(Normal), vTime(0), visibleArea(0) , flickableDirection(QDeclarativeFlickable::AutoFlickDirection) , boundsBehavior(QDeclarativeFlickable::DragAndOvershootBounds) @@ -176,19 +208,39 @@ void QDeclarativeFlickablePrivate::init() } /* - Returns the amount to overshoot by given a velocity. - Will be roughly in range 0 - size/4 + Returns the amount to overshoot by given a view size. + Will be up to the lesser of 1/3 of the view size or QML_FLICK_OVERSHOOT */ -qreal QDeclarativeFlickablePrivate::overShootDistance(qreal velocity, qreal size) +qreal QDeclarativeFlickablePrivate::overShootDistance(qreal size) { if (maxVelocity <= 0) return 0.0; - velocity = qAbs(velocity); - if (velocity > maxVelocity) - velocity = maxVelocity; - qreal dist = size / 4 * velocity / maxVelocity; - return dist; + return qMin(qreal(QML_FLICK_OVERSHOOT), size/3); +} + +void QDeclarativeFlickablePrivate::AxisData::addVelocitySample(qreal v, qreal maxVelocity) +{ + if (v > maxVelocity) + v = maxVelocity; + else if (v < -maxVelocity) + v = -maxVelocity; + velocityBuffer.append(v); + if (velocityBuffer.count() > QML_FLICK_SAMPLEBUFFER) + velocityBuffer.remove(0); +} + +void QDeclarativeFlickablePrivate::AxisData::updateVelocity() +{ + if (velocityBuffer.count() > QML_FLICK_DISCARDSAMPLES) { + velocity = 0; + int count = velocityBuffer.count()-QML_FLICK_DISCARDSAMPLES; + for (int i = 0; i < count; ++i) { + qreal v = velocityBuffer.at(i); + velocity += v; + } + velocity /= count; + } } void QDeclarativeFlickablePrivate::itemGeometryChanged(QDeclarativeItem *item, const QRectF &newGeom, const QRectF &oldGeom) @@ -220,15 +272,12 @@ void QDeclarativeFlickablePrivate::flick(AxisData &data, qreal minExtent, qreal Q_Q(QDeclarativeFlickable); qreal maxDistance = -1; data.fixingUp = false; - bool overShoot = boundsBehavior == QDeclarativeFlickable::DragAndOvershootBounds; // -ve velocity means list is moving up if (velocity > 0) { - if (data.move.value() < minExtent) - maxDistance = qAbs(minExtent - data.move.value() + (overShoot?overShootDistance(velocity,vSize):0)); + maxDistance = qAbs(minExtent - data.move.value()); data.flickTarget = minExtent; } else { - if (data.move.value() > maxExtent) - maxDistance = qAbs(maxExtent - data.move.value()) + (overShoot?overShootDistance(velocity,vSize):0); + maxDistance = qAbs(maxExtent - data.move.value()); data.flickTarget = maxExtent; } if (maxDistance > 0) { @@ -240,7 +289,10 @@ void QDeclarativeFlickablePrivate::flick(AxisData &data, qreal minExtent, qreal v = maxVelocity; } timeline.reset(data.move); - timeline.accel(data.move, v, deceleration, maxDistance); + if (boundsBehavior == QDeclarativeFlickable::DragAndOvershootBounds) + timeline.accel(data.move, v, deceleration); + else + timeline.accel(data.move, v, deceleration, maxDistance); timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this)); if (!flickingHorizontally && q->xflick()) { flickingHorizontally = true; @@ -327,6 +379,7 @@ void QDeclarativeFlickablePrivate::fixup(AxisData &data, qreal minExtent, qreal } } } + data.inOvershoot = false; fixupMode = Normal; vTime = timeline.time(); } @@ -399,7 +452,7 @@ void QDeclarativeFlickablePrivate::updateBeginningEnd() \section1 Example Usage - \div {float-right} + \div {class="float-right"} \inlineimage flickable.gif \enddiv @@ -706,16 +759,13 @@ void QDeclarativeFlickablePrivate::handleMousePressEvent(QGraphicsSceneMouseEven q->setKeepMouseGrab(stealMouse); pressed = true; timeline.clear(); - hData.velocity = 0; - vData.velocity = 0; - hData.dragStartOffset = 0; - vData.dragStartOffset = 0; + hData.reset(); + vData.reset(); hData.dragMinBound = q->minXExtent(); vData.dragMinBound = q->minYExtent(); hData.dragMaxBound = q->maxXExtent(); vData.dragMaxBound = q->maxYExtent(); - hData.fixingUp = false; - vData.fixingUp = false; + fixupMode = Normal; lastPos = QPoint(); QDeclarativeItemPrivate::start(lastPosTime); pressPos = event->pos(); @@ -807,33 +857,33 @@ void QDeclarativeFlickablePrivate::handleMouseMoveEvent(QGraphicsSceneMouseEvent if (stealMouse) q->setKeepMouseGrab(true); - if (!lastPos.isNull()) { - qreal elapsed = qreal(QDeclarativeItemPrivate::restart(lastPosTime)) / 1000.; - if (elapsed <= 0) - elapsed = 1; - if (q->yflick()) { - qreal diff = event->pos().y() - lastPos.y(); - // average to reduce the effect of spurious moves - vData.velocity += diff / elapsed; - vData.velocity /= 2; - } - - if (q->xflick()) { - qreal diff = event->pos().x() - lastPos.x(); - // average to reduce the effect of spurious moves - hData.velocity += diff / elapsed; - hData.velocity /= 2; - } + if (rejectY) { + vData.velocityBuffer.clear(); + vData.velocity = 0; + } + if (rejectX) { + hData.velocityBuffer.clear(); + hData.velocity = 0; } - - if (rejectY) vData.velocity = 0; - if (rejectX) hData.velocity = 0; if (hMoved || vMoved) { q->movementStarting(); q->viewportMoved(); } + if (!lastPos.isNull()) { + qreal elapsed = qreal(QDeclarativeItemPrivate::elapsed(lastPosTime)) / 1000.; + if (elapsed <= 0) + return; + QDeclarativeItemPrivate::restart(lastPosTime); + qreal dy = event->pos().y()-lastPos.y(); + if (q->yflick() && !rejectY) + vData.addVelocitySample(dy/elapsed, maxVelocity); + qreal dx = event->pos().x()-lastPos.x(); + if (q->xflick() && !rejectX) + hData.addVelocitySample(dx/elapsed, maxVelocity); + } + lastPos = event->pos(); } @@ -846,25 +896,33 @@ void QDeclarativeFlickablePrivate::handleMouseReleaseEvent(QGraphicsSceneMouseEv if (!lastPosTime.isValid()) return; - if (QDeclarativeItemPrivate::elapsed(lastPosTime) > 100) { - // if we drag then pause before release we should not cause a flick. + // if we drag then pause before release we should not cause a flick. + if (QDeclarativeItemPrivate::elapsed(lastPosTime) < 100) { + vData.updateVelocity(); + hData.updateVelocity(); + } else { hData.velocity = 0.0; vData.velocity = 0.0; } vTime = timeline.time(); - if (qAbs(vData.velocity) > MinimumFlickVelocity && qAbs(event->pos().y() - pressPos.y()) > FlickThreshold) - flickY(vData.velocity); + + qreal velocity = vData.velocity; + if (vData.atBeginning || vData.atEnd) + velocity /= 2; + if (qAbs(velocity) > MinimumFlickVelocity && qAbs(event->pos().y() - pressPos.y()) > FlickThreshold) + flickY(velocity); else fixupY(); - if (qAbs(hData.velocity) > MinimumFlickVelocity && qAbs(event->pos().x() - pressPos.x()) > FlickThreshold) - flickX(hData.velocity); + velocity = hData.velocity; + if (hData.atBeginning || hData.atEnd) + velocity /= 2; + if (qAbs(velocity) > MinimumFlickVelocity && qAbs(event->pos().x() - pressPos.x()) > FlickThreshold) + flickX(velocity); else fixupX(); - lastPosTime.invalidate(); - if (!timeline.isActive()) q->movementEnding(); } @@ -911,29 +969,41 @@ void QDeclarativeFlickable::wheelEvent(QGraphicsSceneWheelEvent *event) if (!d->interactive) { QDeclarativeItem::wheelEvent(event); } else if (yflick() && event->orientation() == Qt::Vertical) { - if (event->delta() > 0) - d->vData.velocity = qMax(event->delta() - d->vData.smoothVelocity.value(), qreal(250.0)); - else - d->vData.velocity = qMin(event->delta() - d->vData.smoothVelocity.value(), qreal(-250.0)); - d->flickingVertically = false; - d->flickY(d->vData.velocity); - if (d->flickingVertically) { - d->vMoved = true; - movementStarting(); + bool valid = false; + if (event->delta() > 0 && contentY() > -minYExtent()) { + d->vData.velocity = qMax(event->delta()*2 - d->vData.smoothVelocity.value(), qreal(d->maxVelocity/4)); + valid = true; + } else if (event->delta() < 0 && contentY() < -maxYExtent()) { + d->vData.velocity = qMin(event->delta()*2 - d->vData.smoothVelocity.value(), qreal(-d->maxVelocity/4)); + valid = true; + } + if (valid) { + d->flickingVertically = false; + d->flickY(d->vData.velocity); + if (d->flickingVertically) { + d->vMoved = true; + movementStarting(); + } + event->accept(); } - event->accept(); } else if (xflick() && event->orientation() == Qt::Horizontal) { - if (event->delta() > 0) - d->hData.velocity = qMax(event->delta() - d->hData.smoothVelocity.value(), qreal(250.0)); - else - d->hData.velocity = qMin(event->delta() - d->hData.smoothVelocity.value(), qreal(-250.0)); - d->flickingHorizontally = false; - d->flickX(d->hData.velocity); - if (d->flickingHorizontally) { - d->hMoved = true; - movementStarting(); + bool valid = false; + if (event->delta() > 0 && contentX() > -minXExtent()) { + d->hData.velocity = qMax(event->delta()*2 - d->hData.smoothVelocity.value(), qreal(d->maxVelocity/4)); + valid = true; + } else if (event->delta() < 0 && contentX() < -maxXExtent()) { + d->hData.velocity = qMin(event->delta()*2 - d->hData.smoothVelocity.value(), qreal(-d->maxVelocity/4)); + valid = true; + } + if (valid) { + d->flickingHorizontally = false; + d->flickX(d->hData.velocity); + if (d->flickingHorizontally) { + d->hMoved = true; + movementStarting(); + } + event->accept(); } - event->accept(); } else { QDeclarativeItem::wheelEvent(event); } @@ -1071,6 +1141,27 @@ void QDeclarativeFlickable::viewportMoved() } } + if (!d->vData.inOvershoot && !d->vData.fixingUp && d->flickingVertically + && (d->vData.move.value() > minYExtent() || d->vData.move.value() < maxYExtent()) + && qAbs(d->vData.smoothVelocity.value()) > 100) { + // Increase deceleration if we've passed a bound + d->vData.inOvershoot = true; + qreal maxDistance = d->overShootDistance(height()); + d->timeline.reset(d->vData.move); + d->timeline.accel(d->vData.move, -d->vData.smoothVelocity.value(), d->deceleration*QML_FLICK_OVERSHOOTFRICTION, maxDistance); + d->timeline.callback(QDeclarativeTimeLineCallback(&d->vData.move, d->fixupY_callback, d)); + } + if (!d->hData.inOvershoot && !d->hData.fixingUp && d->flickingHorizontally + && (d->hData.move.value() > minXExtent() || d->hData.move.value() < maxXExtent()) + && qAbs(d->hData.smoothVelocity.value()) > 100) { + // Increase deceleration if we've passed a bound + d->hData.inOvershoot = true; + qreal maxDistance = d->overShootDistance(width()); + d->timeline.reset(d->hData.move); + d->timeline.accel(d->hData.move, -d->hData.smoothVelocity.value(), d->deceleration*QML_FLICK_OVERSHOOTFRICTION, maxDistance); + d->timeline.callback(QDeclarativeTimeLineCallback(&d->hData.move, d->fixupX_callback, d)); + } + d->lastFlickablePosition = QPointF(d->hData.move.value(), d->vData.move.value()); d->vTime = d->timeline.time(); @@ -1339,7 +1430,9 @@ void QDeclarativeFlickable::resizeContent(qreal w, qreal h, QPointF center) Q_D(QDeclarativeFlickable); if (w != d->hData.viewSize) { qreal oldSize = d->hData.viewSize; - setContentWidth(w); + d->hData.viewSize = w; + d->contentItem->setWidth(w); + emit contentWidthChanged(); if (center.x() != 0) { qreal pos = center.x() * w / oldSize; setContentX(contentX() + pos - center.x()); @@ -1347,12 +1440,15 @@ void QDeclarativeFlickable::resizeContent(qreal w, qreal h, QPointF center) } if (h != d->vData.viewSize) { qreal oldSize = d->vData.viewSize; - setContentHeight(h); + d->vData.viewSize = h; + d->contentItem->setHeight(h); + emit contentHeightChanged(); if (center.y() != 0) { qreal pos = center.y() * h / oldSize; setContentY(contentY() + pos - center.y()); } } + d->updateBeginningEnd(); } /*! @@ -1430,8 +1526,10 @@ bool QDeclarativeFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event) QGraphicsScene *s = scene(); QDeclarativeItem *grabber = s ? qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem()) : 0; + QGraphicsItem *grabberItem = s ? s->mouseGrabberItem() : 0; + bool disabledItem = grabberItem && !grabberItem->isEnabled(); bool stealThisEvent = d->stealMouse; - if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab())) { + if ((stealThisEvent || myRect.contains(event->scenePos().toPoint())) && (!grabber || !grabber->keepMouseGrab() || disabledItem)) { mouseEvent.setAccepted(false); for (int i = 0x1; i <= 0x10; i <<= 1) { if (event->buttons() & i) { @@ -1478,12 +1576,12 @@ bool QDeclarativeFlickable::sendMouseEvent(QGraphicsSceneMouseEvent *event) break; } grabber = qobject_cast<QDeclarativeItem*>(s->mouseGrabberItem()); - if (grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this) { + if ((grabber && stealThisEvent && !grabber->keepMouseGrab() && grabber != this) || disabledItem) { d->clearDelayedPress(); grabMouse(); } - return stealThisEvent || d->delayedPressEvent; + return stealThisEvent || d->delayedPressEvent || disabledItem; } else if (d->lastPosTime.isValid()) { d->lastPosTime.invalidate(); } @@ -1517,7 +1615,7 @@ bool QDeclarativeFlickable::sceneEventFilter(QGraphicsItem *i, QEvent *e) \qmlproperty real Flickable::maximumFlickVelocity This property holds the maximum velocity that the user can flick the view in pixels/second. - The default is 2000 pixels/s + The default value is platform dependent. */ qreal QDeclarativeFlickable::maximumFlickVelocity() const { @@ -1538,7 +1636,7 @@ void QDeclarativeFlickable::setMaximumFlickVelocity(qreal v) \qmlproperty real Flickable::flickDeceleration This property holds the rate at which a flick will decelerate. - The default is 500. + The default value is platform dependent. */ qreal QDeclarativeFlickable::flickDeceleration() const { diff --git a/src/declarative/graphicsitems/qdeclarativeflickable_p_p.h b/src/declarative/graphicsitems/qdeclarativeflickable_p_p.h index 38a5eb3..1117abb 100644 --- a/src/declarative/graphicsitems/qdeclarativeflickable_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativeflickable_p_p.h @@ -94,9 +94,19 @@ public: struct AxisData { AxisData(QDeclarativeFlickablePrivate *fp, void (QDeclarativeFlickablePrivate::*func)(qreal)) : move(fp, func), viewSize(-1), smoothVelocity(fp), atEnd(false), atBeginning(true) - , fixingUp(false) + , fixingUp(false), inOvershoot(false) {} + void reset() { + velocityBuffer.clear(); + dragStartOffset = 0; + fixingUp = false; + inOvershoot = false; + } + + void addVelocitySample(qreal v, qreal maxVelocity); + void updateVelocity(); + QDeclarativeTimeLineValueProxy<QDeclarativeFlickablePrivate> move; qreal viewSize; qreal pressPos; @@ -106,9 +116,11 @@ public: qreal velocity; qreal flickTarget; QDeclarativeFlickablePrivate::Velocity smoothVelocity; + QPODVector<qreal,10> velocityBuffer; bool atEnd : 1; bool atBeginning : 1; bool fixingUp : 1; + bool inOvershoot : 1; }; void flickX(qreal velocity); @@ -129,7 +141,7 @@ public: void setRoundedViewportX(qreal x); void setRoundedViewportY(qreal y); - qreal overShootDistance(qreal velocity, qreal size); + qreal overShootDistance(qreal size); void itemGeometryChanged(QDeclarativeItem *, const QRectF &, const QRectF &); diff --git a/src/declarative/graphicsitems/qdeclarativeflipable.cpp b/src/declarative/graphicsitems/qdeclarativeflipable.cpp index 5fda758..d23374b 100644 --- a/src/declarative/graphicsitems/qdeclarativeflipable.cpp +++ b/src/declarative/graphicsitems/qdeclarativeflipable.cpp @@ -86,13 +86,13 @@ public: The following example shows a Flipable item that flips whenever it is clicked, rotating about the y-axis. - This flipable item has a \c flipped boolean property that is toggled - whenever the MouseArea within the flipable is clicked. When - \c flipped is true, the item changes to the "back" state; in this + This flipable item has a \c flipped boolean property that is toggled + whenever the MouseArea within the flipable is clicked. When + \c flipped is true, the item changes to the "back" state; in this state, the \c angle of the \l Rotation item is changed to 180 degrees to produce the flipping effect. When \c flipped is false, the - item reverts to the default state, in which the \c angle value is 0. - + item reverts to the default state, in which the \c angle value is 0. + \snippet doc/src/snippets/declarative/flipable/flipable.qml 0 \image flipable.gif @@ -103,8 +103,8 @@ public: its old and new values. See \l {QML States} for details on state changes and the default - state, and \l {QML Animation} for more information on how animations - work within transitions. + state, and \l {QML Animation and Transitions} for more information on how + animations work within transitions. \sa {declarative/ui-components/flipable}{Flipable example} */ diff --git a/src/declarative/graphicsitems/qdeclarativegridview.cpp b/src/declarative/graphicsitems/qdeclarativegridview.cpp index 1d2ad1c..05e64b9 100644 --- a/src/declarative/graphicsitems/qdeclarativegridview.cpp +++ b/src/declarative/graphicsitems/qdeclarativegridview.cpp @@ -68,19 +68,60 @@ public: } ~FxGridItem() {} - qreal rowPos() const { return (view->flow() == QDeclarativeGridView::LeftToRight ? item->y() : item->x()); } - qreal colPos() const { return (view->flow() == QDeclarativeGridView::LeftToRight ? item->x() : item->y()); } + qreal rowPos() const { + qreal rowPos = 0; + if (view->flow() == QDeclarativeGridView::LeftToRight) { + rowPos = item->y(); + } else { + if (view->effectiveLayoutDirection() == Qt::RightToLeft) + rowPos = -view->cellWidth()-item->x(); + else + rowPos = item->x(); + } + return rowPos; + } + qreal colPos() const { + qreal colPos = 0; + if (view->flow() == QDeclarativeGridView::LeftToRight) { + if (view->effectiveLayoutDirection() == Qt::RightToLeft) { + int colSize = view->cellWidth(); + int columns = view->width()/colSize; + colPos = colSize * (columns-1) - item->x(); + } else { + colPos = item->x(); + } + } else { + colPos = item->y(); + } + + return colPos; + } + qreal endRowPos() const { - return view->flow() == QDeclarativeGridView::LeftToRight - ? item->y() + view->cellHeight() - 1 - : item->x() + view->cellWidth() - 1; + if (view->flow() == QDeclarativeGridView::LeftToRight) { + return item->y() + view->cellHeight() - 1; + } else { + if (view->effectiveLayoutDirection() == Qt::RightToLeft) + return -item->x() - 1; + else + return item->x() + view->cellWidth() - 1; + } } void setPosition(qreal col, qreal row) { - if (view->flow() == QDeclarativeGridView::LeftToRight) { - item->setPos(QPointF(col, row)); + if (view->effectiveLayoutDirection() == Qt::RightToLeft) { + if (view->flow() == QDeclarativeGridView::LeftToRight) { + int columns = view->width()/view->cellWidth(); + item->setPos(QPointF((view->cellWidth() * (columns-1) - col), row)); + } else { + item->setPos(QPointF(-view->cellWidth()-row, col)); + } } else { - item->setPos(QPointF(row, col)); + if (view->flow() == QDeclarativeGridView::LeftToRight) + item->setPos(QPointF(col, row)); + else + item->setPos(QPointF(row, col)); } + } bool contains(qreal x, qreal y) const { return (x >= item->x() && x < item->x() + view->cellWidth() && @@ -101,10 +142,12 @@ class QDeclarativeGridViewPrivate : public QDeclarativeFlickablePrivate public: QDeclarativeGridViewPrivate() - : currentItem(0), flow(QDeclarativeGridView::LeftToRight) + : currentItem(0), layoutDirection(Qt::LeftToRight), flow(QDeclarativeGridView::LeftToRight) , visibleIndex(0) , currentIndex(-1) , cellWidth(100), cellHeight(100), columns(1), requestedIndex(-1), itemCount(0) - , highlightRangeStart(0), highlightRangeEnd(0), highlightRange(QDeclarativeGridView::NoHighlightRange) + , highlightRangeStart(0), highlightRangeEnd(0) + , highlightRangeStartValid(false), highlightRangeEndValid(false) + , highlightRange(QDeclarativeGridView::NoHighlightRange) , highlightComponent(0), highlight(0), trackedItem(0) , moveReason(Other), buffer(0), highlightXAnimator(0), highlightYAnimator(0) , highlightMoveDuration(150) @@ -144,35 +187,72 @@ public: return 0; } + bool isRightToLeftTopToBottom() const { + Q_Q(const QDeclarativeGridView); + return flow == QDeclarativeGridView::TopToBottom && q->effectiveLayoutDirection() == Qt::RightToLeft; + } + + void regenerate() { + Q_Q(QDeclarativeGridView); + if (q->isComponentComplete()) { + clear(); + updateGrid(); + setPosition(0); + q->refill(); + updateCurrent(currentIndex); + } + } + + void mirrorChange() { + Q_Q(QDeclarativeGridView); + regenerate(); + emit q->effectiveLayoutDirectionChanged(); + } + qreal position() const { Q_Q(const QDeclarativeGridView); return flow == QDeclarativeGridView::LeftToRight ? q->contentY() : q->contentX(); } void setPosition(qreal pos) { Q_Q(QDeclarativeGridView); - if (flow == QDeclarativeGridView::LeftToRight) + if (flow == QDeclarativeGridView::LeftToRight) { q->QDeclarativeFlickable::setContentY(pos); - else - q->QDeclarativeFlickable::setContentX(pos); + q->QDeclarativeFlickable::setContentX(0); + } else { + if (q->effectiveLayoutDirection() == Qt::LeftToRight) + q->QDeclarativeFlickable::setContentX(pos); + else + q->QDeclarativeFlickable::setContentX(-pos-size()); + q->QDeclarativeFlickable::setContentY(0); + } } int size() const { Q_Q(const QDeclarativeGridView); return flow == QDeclarativeGridView::LeftToRight ? q->height() : q->width(); } - qreal startPosition() const { + qreal originPosition() const { qreal pos = 0; if (!visibleItems.isEmpty()) pos = visibleItems.first()->rowPos() - visibleIndex / columns * rowSize(); return pos; } - qreal endPosition() const { + qreal lastPosition() const { qreal pos = 0; if (model && model->count()) pos = rowPosAt(model->count() - 1) + rowSize(); return pos; } + qreal startPosition() const { + return isRightToLeftTopToBottom() ? -lastPosition()+1 : originPosition(); + } + + qreal endPosition() const { + return isRightToLeftTopToBottom() ? -originPosition()+1 : lastPosition(); + + } + bool isValid() const { return model && model->count() && model->isValid(); } @@ -227,7 +307,7 @@ public: } FxGridItem *firstVisibleItem() const { - const qreal pos = position(); + const qreal pos = isRightToLeftTopToBottom() ? -position()-size() : position(); for (int i = 0; i < visibleItems.count(); ++i) { FxGridItem *item = visibleItems.at(i); if (item->index != -1 && item->endRowPos() > pos) @@ -237,15 +317,12 @@ public: } int lastVisibleIndex() const { - int lastIndex = -1; - for (int i = visibleItems.count()-1; i >= 0; --i) { - FxGridItem *gridItem = visibleItems.at(i); - if (gridItem->index != -1) { - lastIndex = gridItem->index; - break; - } + for (int i = 0; i < visibleItems.count(); ++i) { + FxGridItem *item = visibleItems.at(i); + if (item->index != -1) + return item->index; } - return lastIndex; + return -1; } // Map a model index to visibleItems list index. @@ -271,8 +348,15 @@ public: pos += rowSize()/2; snapPos = visibleItems.first()->rowPos() - visibleIndex / columns * rowSize(); snapPos = pos - fmodf(pos - snapPos, qreal(rowSize())); - qreal maxExtent = flow == QDeclarativeGridView::LeftToRight ? -q->maxYExtent() : -q->maxXExtent(); - qreal minExtent = flow == QDeclarativeGridView::LeftToRight ? -q->minYExtent() : -q->minXExtent(); + qreal maxExtent; + qreal minExtent; + if (isRightToLeftTopToBottom()) { + maxExtent = q->minXExtent(); + minExtent = q->maxXExtent(); + } else { + maxExtent = flow == QDeclarativeGridView::LeftToRight ? -q->maxYExtent() : -q->maxXExtent(); + minExtent = flow == QDeclarativeGridView::LeftToRight ? -q->minYExtent() : -q->minXExtent(); + } if (snapPos > maxExtent) snapPos = maxExtent; if (snapPos < minExtent) @@ -363,6 +447,7 @@ public: QList<FxGridItem*> visibleItems; QHash<QDeclarativeItem*,int> unrequestedItems; FxGridItem *currentItem; + Qt::LayoutDirection layoutDirection; QDeclarativeGridView::Flow flow; int visibleIndex; int currentIndex; @@ -373,6 +458,8 @@ public: int itemCount; qreal highlightRangeStart; qreal highlightRangeEnd; + bool highlightRangeStartValid; + bool highlightRangeEndValid; QDeclarativeGridView::HighlightRangeMode highlightRange; QDeclarativeComponent *highlightComponent; FxGridItem *highlight; @@ -497,6 +584,26 @@ void QDeclarativeGridViewPrivate::refill(qreal from, qreal to, bool doBuffer) --i; modelIndex = visibleItems.at(i)->index + 1; } + + if (visibleItems.count() && (fillFrom > rowPos + rowSize()*2 + || fillTo < rowPosAt(visibleIndex) - rowSize())) { + // We've jumped more than a page. Estimate which items are now + // visible and fill from there. + int count = (fillFrom - (rowPos + rowSize())) / (rowSize()) * columns; + for (int i = 0; i < visibleItems.count(); ++i) + releaseItem(visibleItems.at(i)); + visibleItems.clear(); + modelIndex += count; + if (modelIndex >= model->count()) + modelIndex = model->count() - 1; + else if (modelIndex < 0) + modelIndex = 0; + modelIndex = modelIndex / columns * columns; + visibleIndex = modelIndex; + colPos = colPosAt(visibleIndex); + rowPos = rowPosAt(visibleIndex); + } + int colNum = colPos / colSize(); FxGridItem *item = 0; @@ -554,7 +661,7 @@ void QDeclarativeGridViewPrivate::refill(qreal from, qreal to, bool doBuffer) if (!lazyRelease || !changed || deferredRelease) { // avoid destroying items in the same frame that we create while (visibleItems.count() > 1 && (item = visibleItems.first()) - && item->endRowPos() < bufferFrom - rowSize()*(item->colPos()/colSize()+1)/(columns+1)) { + && item->rowPos()+rowSize()-1 < bufferFrom - rowSize()*(item->colPos()/colSize()+1)/(columns+1)) { if (item->attached->delayRemove()) break; // qDebug() << "refill: remove first" << visibleIndex << "top end pos" << item->endRowPos(); @@ -596,12 +703,13 @@ void QDeclarativeGridViewPrivate::refill(qreal from, qreal to, bool doBuffer) void QDeclarativeGridViewPrivate::updateGrid() { Q_Q(QDeclarativeGridView); + columns = (int)qMax((flow == QDeclarativeGridView::LeftToRight ? q->width() : q->height()) / colSize(), qreal(1.)); if (isValid()) { if (flow == QDeclarativeGridView::LeftToRight) q->setContentHeight(endPosition() - startPosition()); else - q->setContentWidth(endPosition() - startPosition()); + q->setContentWidth(lastPosition() - originPosition()); } } @@ -669,10 +777,14 @@ void QDeclarativeGridViewPrivate::updateUnrequestedPositions() { QHash<QDeclarativeItem*,int>::const_iterator it; for (it = unrequestedItems.begin(); it != unrequestedItems.end(); ++it) { + QDeclarativeItem *item = it.key(); if (flow == QDeclarativeGridView::LeftToRight) { - it.key()->setPos(QPointF(colPosAt(*it), rowPosAt(*it))); + item->setPos(QPointF(colPosAt(*it), rowPosAt(*it))); } else { - it.key()->setPos(QPointF(rowPosAt(*it), colPosAt(*it))); + if (isRightToLeftTopToBottom()) + item->setPos(QPointF(-rowPosAt(*it)-item->width(), colPosAt(*it))); + else + item->setPos(QPointF(rowPosAt(*it), colPosAt(*it))); } } } @@ -837,23 +949,30 @@ void QDeclarativeGridViewPrivate::updateFooter() } } if (footer) { + qreal colOffset = 0; + qreal rowOffset; + if (isRightToLeftTopToBottom()) { + rowOffset = footer->item->width()-cellWidth; + } else { + rowOffset = 0; + if (q->effectiveLayoutDirection() == Qt::RightToLeft) + colOffset = footer->item->width()-cellWidth; + } if (visibleItems.count()) { - qreal endPos = endPosition(); + qreal endPos = lastPosition(); if (lastVisibleIndex() == model->count()-1) { - footer->setPosition(0, endPos); + footer->setPosition(colOffset, endPos + rowOffset); } else { - qreal visiblePos = position() + q->height(); - if (endPos <= visiblePos || footer->endRowPos() < endPos) - footer->setPosition(0, endPos); + qreal visiblePos = isRightToLeftTopToBottom() ? -position() : position() + size(); + if (endPos <= visiblePos || footer->endRowPos() < endPos + rowOffset) + footer->setPosition(colOffset, endPos + rowOffset); } } else { qreal endPos = 0; if (header) { - endPos += flow == QDeclarativeGridView::LeftToRight - ? header->item->height() - : header->item->width(); + endPos += flow == QDeclarativeGridView::LeftToRight ? header->item->height() : header->item->width(); } - footer->setPosition(0, endPos); + footer->setPosition(colOffset, endPos); } } } @@ -883,16 +1002,27 @@ void QDeclarativeGridViewPrivate::updateHeader() } } if (header) { + qreal colOffset = 0; + qreal rowOffset; + if (isRightToLeftTopToBottom()) { + rowOffset = -cellWidth; + } else { + rowOffset = -headerSize(); + if (q->effectiveLayoutDirection() == Qt::RightToLeft) + colOffset = header->item->width()-cellWidth; + } if (visibleItems.count()) { - qreal startPos = startPosition(); + qreal startPos = originPosition(); if (visibleIndex == 0) { - header->setPosition(0, startPos - headerSize()); + header->setPosition(colOffset, startPos + rowOffset); } else { - if (position() <= startPos || header->rowPos() > startPos - headerSize()) - header->setPosition(0, startPos - headerSize()); + qreal tempPos = isRightToLeftTopToBottom() ? -position()-size() : position(); + qreal headerPos = isRightToLeftTopToBottom() ? header->rowPos() + cellWidth - headerSize() : header->rowPos(); + if (tempPos <= startPos || headerPos > startPos + rowOffset) + header->setPosition(colOffset, startPos + rowOffset); } } else { - header->setPosition(0, 0); + header->setPosition(colOffset, 0); } } } @@ -914,21 +1044,46 @@ void QDeclarativeGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m fixupMode = moveReason == Mouse ? fixupMode : Immediate; + qreal highlightStart; + qreal highlightEnd; + qreal viewPos; + if (isRightToLeftTopToBottom()) { + // Handle Right-To-Left exceptions + viewPos = -position()-size(); + highlightStart = highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart; + highlightEnd = highlightRangeEndValid ? size()-highlightRangeStart : highlightRangeEnd; + } else { + viewPos = position(); + highlightStart = highlightRangeStart; + highlightEnd = highlightRangeEnd; + } + if (snapMode != QDeclarativeGridView::NoSnap) { - FxGridItem *topItem = snapItemAt(position()+highlightRangeStart); - FxGridItem *bottomItem = snapItemAt(position()+highlightRangeEnd); + qreal tempPosition = isRightToLeftTopToBottom() ? -position()-size() : position(); + FxGridItem *topItem = snapItemAt(tempPosition+highlightStart); + FxGridItem *bottomItem = snapItemAt(tempPosition+highlightEnd); qreal pos; if (topItem && bottomItem && haveHighlightRange && highlightRange == QDeclarativeGridView::StrictlyEnforceRange) { - qreal topPos = qMin(topItem->rowPos() - highlightRangeStart, -maxExtent); - qreal bottomPos = qMax(bottomItem->rowPos() - highlightRangeEnd, -minExtent); + qreal topPos = qMin(topItem->rowPos() - highlightStart, -maxExtent); + qreal bottomPos = qMax(bottomItem->rowPos() - highlightEnd, -minExtent); pos = qAbs(data.move + topPos) < qAbs(data.move + bottomPos) ? topPos : bottomPos; } else if (topItem) { - if (topItem->index == 0 && header && position()+highlightRangeStart < header->rowPos()+headerSize()/2) - pos = header->rowPos() - highlightRangeStart; - else - pos = qMax(qMin(topItem->rowPos() - highlightRangeStart, -maxExtent), -minExtent); + qreal headerPos = 0; + if (header) + headerPos = isRightToLeftTopToBottom() ? header->rowPos() + cellWidth - headerSize() : header->rowPos(); + if (topItem->index == 0 && header && tempPosition+highlightStart < headerPos+headerSize()/2) { + pos = isRightToLeftTopToBottom() ? - headerPos + highlightStart - size() : headerPos - highlightStart; + } else { + if (isRightToLeftTopToBottom()) + pos = qMax(qMin(-topItem->rowPos() + highlightStart - size(), -maxExtent), -minExtent); + else + pos = qMax(qMin(topItem->rowPos() - highlightStart, -maxExtent), -minExtent); + } } else if (bottomItem) { - pos = qMax(qMin(bottomItem->rowPos() - highlightRangeStart, -maxExtent), -minExtent); + if (isRightToLeftTopToBottom()) + pos = qMax(qMin(-bottomItem->rowPos() + highlightStart - size(), -maxExtent), -minExtent); + else + pos = qMax(qMin(bottomItem->rowPos() - highlightStart, -maxExtent), -minExtent); } else { QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent); return; @@ -936,12 +1091,15 @@ void QDeclarativeGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m if (currentItem && haveHighlightRange && highlightRange == QDeclarativeGridView::StrictlyEnforceRange) { updateHighlight(); qreal currPos = currentItem->rowPos(); - if (pos < currPos + rowSize() - highlightRangeEnd) - pos = currPos + rowSize() - highlightRangeEnd; - if (pos > currPos - highlightRangeStart) - pos = currPos - highlightRangeStart; + if (isRightToLeftTopToBottom()) + pos = -pos-size(); // Transform Pos if required + if (pos < currPos + rowSize() - highlightEnd) + pos = currPos + rowSize() - highlightEnd; + if (pos > currPos - highlightStart) + pos = currPos - highlightStart; + if (isRightToLeftTopToBottom()) + pos = -pos-size(); // Untransform } - qreal dist = qAbs(data.move + pos); if (dist > 0) { timeline.reset(data.move); @@ -957,12 +1115,12 @@ void QDeclarativeGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m if (currentItem) { updateHighlight(); qreal pos = currentItem->rowPos(); - qreal viewPos = position(); - if (viewPos < pos + rowSize() - highlightRangeEnd) - viewPos = pos + rowSize() - highlightRangeEnd; - if (viewPos > pos - highlightRangeStart) - viewPos = pos - highlightRangeStart; - + if (viewPos < pos + rowSize() - highlightEnd) + viewPos = pos + rowSize() - highlightEnd; + if (viewPos > pos - highlightStart) + viewPos = pos - highlightStart; + if (isRightToLeftTopToBottom()) + viewPos = -viewPos-size(); timeline.reset(data.move); if (viewPos != position()) { if (fixupMode != Immediate) { @@ -977,6 +1135,7 @@ void QDeclarativeGridViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m } else { QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent); } + data.inOvershoot = false; fixupMode = Normal; } @@ -992,12 +1151,14 @@ void QDeclarativeGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal m return; } qreal maxDistance = 0; - // -ve velocity means list is moving up + qreal dataValue = isRightToLeftTopToBottom() ? -data.move.value()+size() : data.move.value(); + // -ve velocity means list is moving up/left if (velocity > 0) { if (data.move.value() < minExtent) { if (snapMode == QDeclarativeGridView::SnapOneRow) { - if (FxGridItem *item = firstVisibleItem()) - maxDistance = qAbs(item->rowPos() + data.move.value()); + if (FxGridItem *item = firstVisibleItem()) { + maxDistance = qAbs(item->rowPos() + dataValue); + } } else { maxDistance = qAbs(minExtent - data.move.value()); } @@ -1007,8 +1168,8 @@ void QDeclarativeGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal m } else { if (data.move.value() > maxExtent) { if (snapMode == QDeclarativeGridView::SnapOneRow) { - qreal pos = snapPosAt(-data.move.value()) + rowSize(); - maxDistance = qAbs(pos + data.move.value()); + qreal pos = snapPosAt(-dataValue) + (isRightToLeftTopToBottom() ? 0 : rowSize()); + maxDistance = qAbs(pos + dataValue); } else { maxDistance = qAbs(maxExtent - data.move.value()); } @@ -1016,7 +1177,10 @@ void QDeclarativeGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal m if (snapMode == QDeclarativeGridView::NoSnap && highlightRange != QDeclarativeGridView::StrictlyEnforceRange) data.flickTarget = maxExtent; } + bool overShoot = boundsBehavior == QDeclarativeFlickable::DragAndOvershootBounds; + qreal highlightStart = isRightToLeftTopToBottom() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart; + if (maxDistance > 0 || overShoot) { // This mode requires the grid to stop exactly on a row boundary. qreal v = velocity; @@ -1035,7 +1199,9 @@ void QDeclarativeGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal m dist = qMin(dist, maxDistance); if (v > 0) dist = -dist; - data.flickTarget = -snapPosAt(-(data.move.value() - highlightRangeStart) + dist) + highlightRangeStart; + qreal distTemp = isRightToLeftTopToBottom() ? -dist : dist; + data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + distTemp) + highlightStart; + data.flickTarget = isRightToLeftTopToBottom() ? -data.flickTarget+size() : data.flickTarget; qreal adjDist = -data.flickTarget + data.move.value(); if (qAbs(adjDist) > qAbs(dist)) { // Prevent painfully slow flicking - adjust velocity to suit flickDeceleration @@ -1051,7 +1217,7 @@ void QDeclarativeGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal m accel = v2 / (2.0f * qAbs(dist)); } else { data.flickTarget = velocity > 0 ? minExtent : maxExtent; - overshootDist = overShoot ? overShootDistance(v, vSize) : 0; + overshootDist = overShoot ? overShootDistance(vSize) : 0; } timeline.reset(data.move); timeline.accel(data.move, v, accel, maxDistance + overshootDist); @@ -1101,7 +1267,7 @@ void QDeclarativeGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal m \snippet doc/src/snippets/declarative/gridview/ContactModel.qml 0 - \div {float-right} + \div {class="float-right"} \inlineimage gridview-simple.png \enddiv @@ -1117,7 +1283,7 @@ void QDeclarativeGridViewPrivate::flick(AxisData &data, qreal minExtent, qreal m \codeline \snippet doc/src/snippets/declarative/gridview/gridview.qml classdocs simple - \div {float-right} + \div {class="float-right"} \inlineimage gridview-highlight.png \enddiv @@ -1227,6 +1393,13 @@ QVariant QDeclarativeGridView::model() const return d->modelVariant; } +// For internal use +int QDeclarativeGridView::modelCount() const +{ + Q_D(const QDeclarativeGridView); + return d->model->count(); +} + void QDeclarativeGridView::setModel(const QVariant &model) { Q_D(QDeclarativeGridView); @@ -1552,6 +1725,7 @@ qreal QDeclarativeGridView::preferredHighlightBegin() const void QDeclarativeGridView::setPreferredHighlightBegin(qreal start) { Q_D(QDeclarativeGridView); + d->highlightRangeStartValid = true; if (d->highlightRangeStart == start) return; d->highlightRangeStart = start; @@ -1559,6 +1733,16 @@ void QDeclarativeGridView::setPreferredHighlightBegin(qreal start) emit preferredHighlightBeginChanged(); } +void QDeclarativeGridView::resetPreferredHighlightBegin() +{ + Q_D(QDeclarativeGridView); + d->highlightRangeStartValid = false; + if (d->highlightRangeStart == 0) + return; + d->highlightRangeStart = 0; + emit preferredHighlightBeginChanged(); +} + qreal QDeclarativeGridView::preferredHighlightEnd() const { Q_D(const QDeclarativeGridView); @@ -1568,6 +1752,7 @@ qreal QDeclarativeGridView::preferredHighlightEnd() const void QDeclarativeGridView::setPreferredHighlightEnd(qreal end) { Q_D(QDeclarativeGridView); + d->highlightRangeEndValid = true; if (d->highlightRangeEnd == end) return; d->highlightRangeEnd = end; @@ -1575,6 +1760,16 @@ void QDeclarativeGridView::setPreferredHighlightEnd(qreal end) emit preferredHighlightEndChanged(); } +void QDeclarativeGridView::resetPreferredHighlightEnd() +{ + Q_D(QDeclarativeGridView); + d->highlightRangeEndValid = false; + if (d->highlightRangeEnd == 0) + return; + d->highlightRangeEnd = 0; + emit preferredHighlightEndChanged(); +} + QDeclarativeGridView::HighlightRangeMode QDeclarativeGridView::highlightRangeMode() const { Q_D(const QDeclarativeGridView); @@ -1591,6 +1786,60 @@ void QDeclarativeGridView::setHighlightRangeMode(HighlightRangeMode mode) emit highlightRangeModeChanged(); } +/*! + \qmlproperty enumeration GridView::layoutDirection + This property holds the layout direction of the grid. + + Possible values: + + \list + \o Qt.LeftToRight (default) - Items will be laid out starting in the top, left corner. The flow is + dependent on the \l GridView::flow property. + \o Qt.RightToLeft - Items will be laid out starting in the top, right corner. The flow is dependent + on the \l GridView:flow property. + \endlist + + \bold Note: If GridView::flow is set to GridView.LeftToRight, this is not to be confused if + GridView::layoutDirection is set to Qt.RightToLeft. The GridView.LeftToRight flow value simply + indicates that the flow is horizontal. +*/ + +Qt::LayoutDirection QDeclarativeGridView::layoutDirection() const +{ + Q_D(const QDeclarativeGridView); + return d->layoutDirection; +} + +void QDeclarativeGridView::setLayoutDirection(Qt::LayoutDirection layoutDirection) +{ + Q_D(QDeclarativeGridView); + if (d->layoutDirection != layoutDirection) { + d->layoutDirection = layoutDirection; + d->regenerate(); + emit layoutDirectionChanged(); + emit effectiveLayoutDirectionChanged(); + } +} + +/*! + \qmlproperty enumeration GridView::effectiveLayoutDirection + This property holds the effective layout direction of the grid. + + When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts, + the visual layout direction of the grid will be mirrored. However, the + property \l {GridView::layoutDirection}{layoutDirection} will remain unchanged. + + \sa GridView::layoutDirection, {LayoutMirroring}{LayoutMirroring} +*/ + +Qt::LayoutDirection QDeclarativeGridView::effectiveLayoutDirection() const +{ + Q_D(const QDeclarativeGridView); + if (d->effectiveLayoutMirror) + return d->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft; + else + return d->layoutDirection; +} /*! \qmlproperty enumeration GridView::flow @@ -1623,10 +1872,7 @@ void QDeclarativeGridView::setFlow(Flow flow) } setContentX(0); setContentY(0); - d->clear(); - d->updateGrid(); - refill(); - d->updateCurrent(d->currentIndex); + d->regenerate(); emit flowChanged(); } } @@ -1893,11 +2139,23 @@ void QDeclarativeGridView::viewportMoved() if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) { // reposition highlight qreal pos = d->highlight->rowPos(); - qreal viewPos = d->position(); - if (pos > viewPos + d->highlightRangeEnd - d->rowSize()) - pos = viewPos + d->highlightRangeEnd - d->rowSize(); - if (pos < viewPos + d->highlightRangeStart) - pos = viewPos + d->highlightRangeStart; + qreal viewPos; + qreal highlightStart; + qreal highlightEnd; + if (d->isRightToLeftTopToBottom()) { + highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart; + highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd; + viewPos = -d->position()-d->size(); + } else { + highlightStart = d->highlightRangeStart; + highlightEnd = d->highlightRangeEnd; + viewPos = d->position(); + } + if (pos > viewPos + highlightEnd - d->rowSize()) + pos = viewPos + highlightEnd - d->rowSize(); + if (pos < viewPos + highlightStart) + pos = viewPos + highlightStart; + d->highlight->setPosition(d->highlight->colPos(), qRound(pos)); // update current index @@ -1959,11 +2217,27 @@ qreal QDeclarativeGridView::minXExtent() const if (d->flow == QDeclarativeGridView::LeftToRight) return QDeclarativeFlickable::minXExtent(); qreal extent = -d->startPosition(); - if (d->header && d->visibleItems.count()) - extent += d->header->item->width(); + qreal highlightStart; + qreal highlightEnd; + qreal endPositionFirstItem; + if (d->isRightToLeftTopToBottom()) { + endPositionFirstItem = d->rowPosAt(d->model->count()-1); + highlightStart = d->highlightRangeStartValid + ? d->highlightRangeStart - (d->lastPosition()-endPositionFirstItem) + : d->size() - (d->lastPosition()-endPositionFirstItem); + highlightEnd = d->highlightRangeEndValid ? d->highlightRangeEnd : d->size(); + if (d->footer && d->visibleItems.count()) + extent += d->footer->item->width(); + } else { + endPositionFirstItem = d->rowPosAt(0)+d->rowSize(); + highlightStart = d->highlightRangeStart; + highlightEnd = d->highlightRangeEnd; + if (d->header && d->visibleItems.count()) + extent += d->header->item->width(); + } if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { - extent += d->highlightRangeStart; - extent = qMax(extent, -(d->rowPosAt(0) + d->rowSize() - d->highlightRangeEnd)); + extent += highlightStart; + extent = qMax(extent, -(endPositionFirstItem - highlightEnd)); } return extent; } @@ -1974,17 +2248,38 @@ qreal QDeclarativeGridView::maxXExtent() const if (d->flow == QDeclarativeGridView::LeftToRight) return QDeclarativeFlickable::maxXExtent(); qreal extent; + qreal highlightStart; + qreal highlightEnd; + qreal lastItemPosition = 0; + if (d->isRightToLeftTopToBottom()){ + highlightStart = d->highlightRangeStartValid ? d->highlightRangeEnd : d->size(); + highlightEnd = d->highlightRangeEndValid ? d->highlightRangeStart : d->size(); + lastItemPosition = d->endPosition(); + } else { + highlightStart = d->highlightRangeStart; + highlightEnd = d->highlightRangeEnd; + if (d->model && d->model->count()) + lastItemPosition = d->rowPosAt(d->model->count()-1); + } if (!d->model || !d->model->count()) { extent = 0; - } if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { - extent = -(d->rowPosAt(d->model->count()-1) - d->highlightRangeStart); - if (d->highlightRangeEnd != d->highlightRangeStart) - extent = qMin(extent, -(d->endPosition() - d->highlightRangeEnd + 1)); + } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { + extent = -(lastItemPosition - highlightStart); + if (highlightEnd != highlightStart) + extent = d->isRightToLeftTopToBottom() + ? qMax(extent, -(d->endPosition() - highlightEnd + 1)) + : qMin(extent, -(d->endPosition() - highlightEnd + 1)); } else { extent = -(d->endPosition() - width()); } - if (d->footer) - extent -= d->footer->item->width(); + if (d->isRightToLeftTopToBottom()) { + if (d->header) + extent -= d->header->item->width(); + } else { + if (d->footer) + extent -= d->footer->item->width(); + } + const qreal minX = minXExtent(); if (extent > minX) extent = minX; @@ -2097,15 +2392,30 @@ void QDeclarativeGridView::moveCurrentIndexLeft() const int count = d->model ? d->model->count() : 0; if (!count) return; - if (d->flow == QDeclarativeGridView::LeftToRight) { - if (currentIndex() > 0 || d->wrap) { - int index = currentIndex() - 1; - setCurrentIndex((index >= 0 && index < count) ? index : count-1); + + if (effectiveLayoutDirection() == Qt::LeftToRight) { + if (d->flow == QDeclarativeGridView::LeftToRight) { + if (currentIndex() > 0 || d->wrap) { + int index = currentIndex() - 1; + setCurrentIndex((index >= 0 && index < count) ? index : count-1); + } + } else { + if (currentIndex() >= d->columns || d->wrap) { + int index = currentIndex() - d->columns; + setCurrentIndex((index >= 0 && index < count) ? index : count-1); + } } } else { - if (currentIndex() >= d->columns || d->wrap) { - int index = currentIndex() - d->columns; - setCurrentIndex((index >= 0 && index < count) ? index : count-1); + if (d->flow == QDeclarativeGridView::LeftToRight) { + if (currentIndex() < count - 1 || d->wrap) { + int index = currentIndex() + 1; + setCurrentIndex((index >= 0 && index < count) ? index : 0); + } + } else { + if (currentIndex() < count - d->columns || d->wrap) { + int index = currentIndex() + d->columns; + setCurrentIndex((index >= 0 && index < count) ? index : 0); + } } } } @@ -2125,15 +2435,30 @@ void QDeclarativeGridView::moveCurrentIndexRight() const int count = d->model ? d->model->count() : 0; if (!count) return; - if (d->flow == QDeclarativeGridView::LeftToRight) { - if (currentIndex() < count - 1 || d->wrap) { - int index = currentIndex() + 1; - setCurrentIndex((index >= 0 && index < count) ? index : 0); + + if (effectiveLayoutDirection() == Qt::LeftToRight) { + if (d->flow == QDeclarativeGridView::LeftToRight) { + if (currentIndex() < count - 1 || d->wrap) { + int index = currentIndex() + 1; + setCurrentIndex((index >= 0 && index < count) ? index : 0); + } + } else { + if (currentIndex() < count - d->columns || d->wrap) { + int index = currentIndex()+d->columns; + setCurrentIndex((index >= 0 && index < count) ? index : 0); + } } } else { - if (currentIndex() < count - d->columns || d->wrap) { - int index = currentIndex()+d->columns; - setCurrentIndex((index >= 0 && index < count) ? index : 0); + if (d->flow == QDeclarativeGridView::LeftToRight) { + if (currentIndex() > 0 || d->wrap) { + int index = currentIndex() - 1; + setCurrentIndex((index >= 0 && index < count) ? index : count-1); + } + } else { + if (currentIndex() >= d->columns || d->wrap) { + int index = currentIndex() - d->columns; + setCurrentIndex((index >= 0 && index < count) ? index : count-1); + } } } } @@ -2150,16 +2475,24 @@ void QDeclarativeGridViewPrivate::positionViewAtIndex(int index, int mode) if (layoutScheduled) layout(); - qreal pos = position(); + qreal pos = isRightToLeftTopToBottom() ? -position() - size() : position(); FxGridItem *item = visibleItem(idx); - qreal maxExtent = flow == QDeclarativeGridView::LeftToRight ? -q->maxYExtent() : -q->maxXExtent(); + qreal maxExtent; + if (flow == QDeclarativeGridView::LeftToRight) + maxExtent = -q->maxYExtent(); + else + maxExtent = isRightToLeftTopToBottom() ? q->minXExtent()-size() : -q->maxXExtent(); + if (!item) { int itemPos = rowPosAt(idx); // save the currently visible items in case any of them end up visible again QList<FxGridItem*> oldVisible = visibleItems; visibleItems.clear(); visibleIndex = idx - idx % columns; - maxExtent = flow == QDeclarativeGridView::LeftToRight ? -q->maxYExtent() : -q->maxXExtent(); + if (flow == QDeclarativeGridView::LeftToRight) + maxExtent = -q->maxYExtent(); + else + maxExtent = isRightToLeftTopToBottom() ? q->minXExtent()-size() : -q->maxXExtent(); setPosition(qMin(qreal(itemPos), maxExtent)); // now release the reference to all the old visible items. for (int i = 0; i < oldVisible.count(); ++i) @@ -2200,8 +2533,13 @@ void QDeclarativeGridViewPrivate::positionViewAtIndex(int index, int mode) if (itemPos < pos) pos = itemPos; } + pos = qMin(pos, maxExtent); - qreal minExtent = flow == QDeclarativeGridView::LeftToRight ? -q->minYExtent() : -q->minXExtent(); + qreal minExtent; + if (flow == QDeclarativeGridView::LeftToRight) + minExtent = -q->minYExtent(); + else + minExtent = isRightToLeftTopToBottom() ? q->maxXExtent()-size() : -q->minXExtent(); pos = qMax(pos, minExtent); moveReason = QDeclarativeGridViewPrivate::Other; q->cancelFlick(); @@ -2341,32 +2679,43 @@ void QDeclarativeGridView::trackedPositionChanged() return; if (d->moveReason == QDeclarativeGridViewPrivate::SetIndex) { const qreal trackedPos = d->trackedItem->rowPos(); - const qreal viewPos = d->position(); + qreal viewPos; + qreal highlightStart; + qreal highlightEnd; + if (d->isRightToLeftTopToBottom()) { + viewPos = -d->position()-d->size(); + highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart; + highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd; + } else { + viewPos = d->position(); + highlightStart = d->highlightRangeStart; + highlightEnd = d->highlightRangeEnd; + } qreal pos = viewPos; if (d->haveHighlightRange) { if (d->highlightRange == StrictlyEnforceRange) { - if (trackedPos > pos + d->highlightRangeEnd - d->rowSize()) - pos = trackedPos - d->highlightRangeEnd + d->rowSize(); - if (trackedPos < pos + d->highlightRangeStart) - pos = trackedPos - d->highlightRangeStart; + if (trackedPos > pos + highlightEnd - d->rowSize()) + pos = trackedPos - highlightEnd + d->rowSize(); + if (trackedPos < pos + highlightStart) + pos = trackedPos - highlightStart; } else { - if (trackedPos < d->startPosition() + d->highlightRangeStart) { + if (trackedPos < d->startPosition() + highlightStart) { pos = d->startPosition(); - } else if (d->trackedItem->endRowPos() > d->endPosition() - d->size() + d->highlightRangeEnd) { + } else if (d->trackedItem->endRowPos() > d->endPosition() - d->size() + highlightEnd) { pos = d->endPosition() - d->size() + 1; if (pos < d->startPosition()) pos = d->startPosition(); } else { - if (trackedPos < viewPos + d->highlightRangeStart) { - pos = trackedPos - d->highlightRangeStart; - } else if (trackedPos > viewPos + d->highlightRangeEnd - d->rowSize()) { - pos = trackedPos - d->highlightRangeEnd + d->rowSize(); + if (trackedPos < viewPos + highlightStart) { + pos = trackedPos - highlightStart; + } else if (trackedPos > viewPos + highlightEnd - d->rowSize()) { + pos = trackedPos - highlightEnd + d->rowSize(); } } } } else { if (trackedPos < viewPos && d->currentItem->rowPos() < viewPos) { - pos = d->currentItem->rowPos() < trackedPos ? trackedPos : d->currentItem->rowPos(); + pos = qMax(trackedPos, d->currentItem->rowPos()); } else if (d->trackedItem->endRowPos() >= viewPos + d->size() && d->currentItem->endRowPos() >= viewPos + d->size()) { if (d->trackedItem->endRowPos() <= d->currentItem->endRowPos()) { @@ -2434,7 +2783,8 @@ void QDeclarativeGridView::itemsInserted(int modelIndex, int count) modelIndex = d->visibleIndex; } - int to = d->buffer+d->position()+d->size()-1; + qreal tempPos = d->isRightToLeftTopToBottom() ? -d->position()-d->size()+d->width()+1 : d->position(); + int to = d->buffer+tempPos+d->size()-1; int colPos = 0; int rowPos = 0; if (d->visibleItems.count()) { @@ -2452,10 +2802,7 @@ void QDeclarativeGridView::itemsInserted(int modelIndex, int count) } } } else if (d->itemCount == 0 && d->header) { - if (d->flow == QDeclarativeGridView::LeftToRight) - rowPos = d->headerSize(); - else - colPos = d->headerSize(); + rowPos = d->headerSize(); } // Update the indexes of the following visible items. @@ -2508,10 +2855,10 @@ void QDeclarativeGridView::itemsInserted(int modelIndex, int count) if (d->currentItem) { d->currentItem->index = d->currentIndex; d->currentItem->setPosition(d->colPosAt(d->currentIndex), d->rowPosAt(d->currentIndex)); - } else if (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared)) { - d->updateCurrent(0); } emit currentIndexChanged(); + } else if (d->itemCount == 0 && (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared))) { + setCurrentIndex(0); } // everything is in order now - emit add() signal @@ -2578,6 +2925,8 @@ void QDeclarativeGridView::itemsRemoved(int modelIndex, int count) d->currentIndex = -1; if (d->itemCount) d->updateCurrent(qMin(modelIndex, d->itemCount-1)); + else + emit currentIndexChanged(); } // update visibleIndex @@ -2760,7 +3109,10 @@ void QDeclarativeGridView::animStopped() void QDeclarativeGridView::refill() { Q_D(QDeclarativeGridView); - d->refill(d->position(), d->position()+d->size()-1); + if (d->isRightToLeftTopToBottom()) + d->refill(-d->position()-d->size()+1, -d->position()); + else + d->refill(d->position(), d->position()+d->size()-1); } diff --git a/src/declarative/graphicsitems/qdeclarativegridview_p.h b/src/declarative/graphicsitems/qdeclarativegridview_p.h index e68a9ba..4d99a14 100644 --- a/src/declarative/graphicsitems/qdeclarativegridview_p.h +++ b/src/declarative/graphicsitems/qdeclarativegridview_p.h @@ -69,11 +69,13 @@ class Q_AUTOTEST_EXPORT QDeclarativeGridView : public QDeclarativeFlickable Q_PROPERTY(bool highlightFollowsCurrentItem READ highlightFollowsCurrentItem WRITE setHighlightFollowsCurrentItem) Q_PROPERTY(int highlightMoveDuration READ highlightMoveDuration WRITE setHighlightMoveDuration NOTIFY highlightMoveDurationChanged) - Q_PROPERTY(qreal preferredHighlightBegin READ preferredHighlightBegin WRITE setPreferredHighlightBegin NOTIFY preferredHighlightBeginChanged) - Q_PROPERTY(qreal preferredHighlightEnd READ preferredHighlightEnd WRITE setPreferredHighlightEnd NOTIFY preferredHighlightEndChanged) + Q_PROPERTY(qreal preferredHighlightBegin READ preferredHighlightBegin WRITE setPreferredHighlightBegin NOTIFY preferredHighlightBeginChanged RESET resetPreferredHighlightBegin) + Q_PROPERTY(qreal preferredHighlightEnd READ preferredHighlightEnd WRITE setPreferredHighlightEnd NOTIFY preferredHighlightEndChanged RESET resetPreferredHighlightEnd) Q_PROPERTY(HighlightRangeMode highlightRangeMode READ highlightRangeMode WRITE setHighlightRangeMode NOTIFY highlightRangeModeChanged) Q_PROPERTY(Flow flow READ flow WRITE setFlow NOTIFY flowChanged) + Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged REVISION 1) + Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged REVISION 1) Q_PROPERTY(bool keyNavigationWraps READ isWrapEnabled WRITE setWrapEnabled NOTIFY keyNavigationWrapsChanged) Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged) Q_PROPERTY(int cellWidth READ cellWidth WRITE setCellWidth NOTIFY cellWidthChanged) @@ -95,6 +97,7 @@ public: ~QDeclarativeGridView(); QVariant model() const; + int modelCount() const; void setModel(const QVariant &); QDeclarativeComponent *delegate() const; @@ -122,9 +125,15 @@ public: qreal preferredHighlightBegin() const; void setPreferredHighlightBegin(qreal); + void resetPreferredHighlightBegin(); qreal preferredHighlightEnd() const; void setPreferredHighlightEnd(qreal); + void resetPreferredHighlightEnd(); + + Qt::LayoutDirection layoutDirection() const; + void setLayoutDirection(Qt::LayoutDirection); + Qt::LayoutDirection effectiveLayoutDirection() const; enum Flow { LeftToRight, TopToBottom }; Flow flow() const; @@ -184,6 +193,8 @@ Q_SIGNALS: void modelChanged(); void delegateChanged(); void flowChanged(); + Q_REVISION(1) void layoutDirectionChanged(); + Q_REVISION(1) void effectiveLayoutDirectionChanged(); void keyNavigationWrapsChanged(); void cacheBufferChanged(); void snapModeChanged(); diff --git a/src/declarative/graphicsitems/qdeclarativeimage.cpp b/src/declarative/graphicsitems/qdeclarativeimage.cpp index 2c9bde5..b776532 100644 --- a/src/declarative/graphicsitems/qdeclarativeimage.cpp +++ b/src/declarative/graphicsitems/qdeclarativeimage.cpp @@ -136,19 +136,17 @@ void QDeclarativeImagePrivate::setPixmap(const QPixmap &pixmap) Q_Q(QDeclarativeImage); pix.setPixmap(pixmap); - q->setImplicitWidth(pix.width()); - q->setImplicitHeight(pix.height()); + q->pixmapChange(); status = pix.isNull() ? QDeclarativeImageBase::Null : QDeclarativeImageBase::Ready; q->update(); - q->pixmapChange(); } /*! \qmlproperty enumeration Image::fillMode - Set this property to define what happens when the image set for the item is smaller - than the size of the item. + Set this property to define what happens when the source image has a different size + than the item. \list \o Image.Stretch - the image is scaled to fit @@ -234,6 +232,9 @@ void QDeclarativeImagePrivate::setPixmap(const QPixmap &pixmap) \endtable + Note that \c clip is \c false by default which means that the element might + paint outside its bounding rectangle even if the fillMode is set to \c PreserveAspectCrop. + \sa {declarative/imageelements/image}{Image example} */ QDeclarativeImage::FillMode QDeclarativeImage::fillMode() const @@ -374,6 +375,9 @@ qreal QDeclarativeImage::paintedHeight() const If the source is a non-scalable image (eg. JPEG), the loaded image will be no greater than this property specifies. For some formats (currently only JPEG), the whole image will never actually be loaded into memory. + + Since QtQuick 1.1 the sourceSize can be cleared to the natural size of the image + by setting sourceSize to \c undefined. \note \e {Changing this property dynamically causes the image source to be reloaded, potentially even from the network, if it is not in the disk cache.} @@ -384,22 +388,31 @@ void QDeclarativeImage::updatePaintedGeometry() Q_D(QDeclarativeImage); if (d->fillMode == PreserveAspectFit) { - if (!d->pix.width() || !d->pix.height()) + if (!d->pix.width() || !d->pix.height()) { + setImplicitWidth(0); + setImplicitHeight(0); return; - qreal widthScale = width() / qreal(d->pix.width()); - qreal heightScale = height() / qreal(d->pix.height()); + } + qreal w = widthValid() ? width() : d->pix.width(); + qreal widthScale = w / qreal(d->pix.width()); + qreal h = heightValid() ? height() : d->pix.height(); + qreal heightScale = h / qreal(d->pix.height()); if (widthScale <= heightScale) { - d->paintedWidth = width(); + d->paintedWidth = w; d->paintedHeight = widthScale * qreal(d->pix.height()); } else if(heightScale < widthScale) { d->paintedWidth = heightScale * qreal(d->pix.width()); - d->paintedHeight = height(); + d->paintedHeight = h; } if (widthValid() && !heightValid()) { setImplicitHeight(d->paintedHeight); + } else { + setImplicitHeight(d->pix.height()); } if (heightValid() && !widthValid()) { setImplicitWidth(d->paintedWidth); + } else { + setImplicitWidth(d->pix.width()); } } else if (d->fillMode == PreserveAspectCrop) { if (!d->pix.width() || !d->pix.height()) @@ -558,6 +571,13 @@ void QDeclarativeImage::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWi void QDeclarativeImage::pixmapChange() { + Q_D(QDeclarativeImage); + // PreserveAspectFit calculates the implicit size differently so we + // don't call our superclass pixmapChange(), since that would + // result in the implicit size being set incorrectly, then updated + // in updatePaintedGeometry() + if (d->fillMode != PreserveAspectFit) + QDeclarativeImageBase::pixmapChange(); updatePaintedGeometry(); } diff --git a/src/declarative/graphicsitems/qdeclarativeimagebase.cpp b/src/declarative/graphicsitems/qdeclarativeimagebase.cpp index 471c87f..81eac78 100644 --- a/src/declarative/graphicsitems/qdeclarativeimagebase.cpp +++ b/src/declarative/graphicsitems/qdeclarativeimagebase.cpp @@ -130,7 +130,19 @@ QSize QDeclarativeImageBase::sourceSize() const int width = d->sourcesize.width(); int height = d->sourcesize.height(); - return QSize(width != -1 ? width : implicitWidth(), height != -1 ? height : implicitHeight()); + return QSize(width != -1 ? width : d->pix.width(), height != -1 ? height : d->pix.height()); +} + +void QDeclarativeImageBase::resetSourceSize() +{ + Q_D(QDeclarativeImageBase); + if (!d->explicitSourceSize) + return; + d->explicitSourceSize = false; + d->sourcesize = QSize(); + emit sourceSizeChanged(); + if (isComponentComplete()) + load(); } bool QDeclarativeImageBase::cache() const @@ -176,14 +188,12 @@ void QDeclarativeImageBase::load() Q_D(QDeclarativeImageBase); if (d->url.isEmpty()) { - d->pix.clear(); + d->pix.clear(this); d->status = Null; d->progress = 0.0; - setImplicitWidth(0); - setImplicitHeight(0); + pixmapChange(); emit progressChanged(d->progress); emit statusChanged(d->status); - pixmapChange(); update(); } else { QDeclarativePixmap::Options options; @@ -191,6 +201,7 @@ void QDeclarativeImageBase::load() options |= QDeclarativePixmap::Asynchronous; if (d->cache) options |= QDeclarativePixmap::Cache; + d->pix.clear(this); d->pix.load(qmlEngine(this), d->url, d->explicitSourceSize ? sourceSize() : QSize(), options); if (d->pix.isLoading()) { @@ -233,8 +244,7 @@ void QDeclarativeImageBase::requestFinished() d->progress = 1.0; - setImplicitWidth(d->pix.width()); - setImplicitHeight(d->pix.height()); + pixmapChange(); if (d->sourcesize.width() != d->pix.width() || d->sourcesize.height() != d->pix.height()) emit sourceSizeChanged(); @@ -243,7 +253,7 @@ void QDeclarativeImageBase::requestFinished() emit statusChanged(d->status); if (d->progress != oldProgress) emit progressChanged(d->progress); - pixmapChange(); + update(); } @@ -266,6 +276,9 @@ void QDeclarativeImageBase::componentComplete() void QDeclarativeImageBase::pixmapChange() { + Q_D(QDeclarativeImageBase); + setImplicitWidth(d->pix.width()); + setImplicitHeight(d->pix.height()); } QT_END_NAMESPACE diff --git a/src/declarative/graphicsitems/qdeclarativeimagebase_p.h b/src/declarative/graphicsitems/qdeclarativeimagebase_p.h index abee25d..1763bba 100644 --- a/src/declarative/graphicsitems/qdeclarativeimagebase_p.h +++ b/src/declarative/graphicsitems/qdeclarativeimagebase_p.h @@ -59,7 +59,7 @@ class Q_AUTOTEST_EXPORT QDeclarativeImageBase : public QDeclarativeImplicitSizeI Q_PROPERTY(qreal progress READ progress NOTIFY progressChanged) Q_PROPERTY(bool asynchronous READ asynchronous WRITE setAsynchronous NOTIFY asynchronousChanged) Q_PROPERTY(bool cache READ cache WRITE setCache NOTIFY cacheChanged REVISION 1) - Q_PROPERTY(QSize sourceSize READ sourceSize WRITE setSourceSize NOTIFY sourceSizeChanged) + Q_PROPERTY(QSize sourceSize READ sourceSize WRITE setSourceSize RESET resetSourceSize NOTIFY sourceSizeChanged) Q_PROPERTY(bool mirror READ mirror WRITE setMirror NOTIFY mirrorChanged REVISION 1) public: @@ -80,6 +80,7 @@ public: virtual void setSourceSize(const QSize&); QSize sourceSize() const; + void resetSourceSize(); virtual void setMirror(bool mirror); bool mirror() const; diff --git a/src/declarative/graphicsitems/qdeclarativeitem.cpp b/src/declarative/graphicsitems/qdeclarativeitem.cpp index ffef61b..6602dda 100644 --- a/src/declarative/graphicsitems/qdeclarativeitem.cpp +++ b/src/declarative/graphicsitems/qdeclarativeitem.cpp @@ -39,12 +39,12 @@ ** ****************************************************************************/ -#include "private/qdeclarativeitem_p.h" #include "qdeclarativeitem.h" #include "private/qdeclarativeevents_p_p.h" #include <private/qdeclarativeengine_p.h> #include <private/qgraphicsitem_p.h> +#include <QtDeclarative/private/qdeclarativeitem_p.h> #include <qdeclarativeengine.h> #include <qdeclarativeopenmetaobject_p.h> @@ -615,19 +615,28 @@ void QDeclarativeKeyNavigationAttached::keyPressed(QKeyEvent *event, bool post) return; } + bool mirror = false; switch(event->key()) { - case Qt::Key_Left: - if (d->left) { - setFocusNavigation(d->left, "left"); + case Qt::Key_Left: { + if (QDeclarativeItem *parentItem = qobject_cast<QDeclarativeItem*>(parent())) + mirror = QDeclarativeItemPrivate::get(parentItem)->effectiveLayoutMirror; + QDeclarativeItem* leftItem = mirror ? d->right : d->left; + if (leftItem) { + setFocusNavigation(leftItem, mirror ? "right" : "left"); event->accept(); } break; - case Qt::Key_Right: - if (d->right) { - setFocusNavigation(d->right, "right"); + } + case Qt::Key_Right: { + if (QDeclarativeItem *parentItem = qobject_cast<QDeclarativeItem*>(parent())) + mirror = QDeclarativeItemPrivate::get(parentItem)->effectiveLayoutMirror; + QDeclarativeItem* rightItem = mirror ? d->left : d->right; + if (rightItem) { + setFocusNavigation(rightItem, mirror ? "left" : "right"); event->accept(); } break; + } case Qt::Key_Up: if (d->up) { setFocusNavigation(d->up, "up"); @@ -669,16 +678,19 @@ void QDeclarativeKeyNavigationAttached::keyReleased(QKeyEvent *event, bool post) return; } + bool mirror = false; switch(event->key()) { case Qt::Key_Left: - if (d->left) { + if (QDeclarativeItem *parentItem = qobject_cast<QDeclarativeItem*>(parent())) + mirror = QDeclarativeItemPrivate::get(parentItem)->effectiveLayoutMirror; + if (mirror ? d->right : d->left) event->accept(); - } break; case Qt::Key_Right: - if (d->right) { + if (QDeclarativeItem *parentItem = qobject_cast<QDeclarativeItem*>(parent())) + mirror = QDeclarativeItemPrivate::get(parentItem)->effectiveLayoutMirror; + if (mirror ? d->left : d->right) event->accept(); - } break; case Qt::Key_Up: if (d->up) { @@ -731,6 +743,171 @@ void QDeclarativeKeyNavigationAttached::setFocusNavigation(QDeclarativeItem *cur } /*! + \qmlclass LayoutMirroring QDeclarativeLayoutMirroringAttached + \since QtQuick 1.1 + \ingroup qml-utility-elements + \brief The LayoutMirroring attached property is used to mirror layout behavior. + + The LayoutMirroring attached property is used to horizontally mirror \l {anchor-layout}{Item anchors}, + \l{Using QML Positioner and Repeater Items}{positioner} elements (such as \l Row and \l Grid) + and views (such as \l GridView and horizontal \l ListView). Mirroring is a visual change: left + anchors become right anchors, and positioner elements like \l Grid and \l Row reverse the + horizontal layout of child items. + + Mirroring is enabled for an item by setting the \l enabled property to true. By default, this + only affects the item itself; setting the \l childrenInherit property to true propagates the mirroring + behavior to all child elements as well. If the \c LayoutMirroring attached property has not been defined + for an item, mirroring is not enabled. + + The following example shows mirroring in action. The \l Row below is specified as being anchored + to the left of its parent. However, since mirroring has been enabled, the anchor is horizontally + reversed and it is now anchored to the right. Also, since items in a \l Row are positioned + from left to right by default, they are now positioned from right to left instead, as demonstrated + by the numbering and opacity of the items: + + \snippet doc/src/snippets/declarative/layoutmirroring.qml 0 + + \image layoutmirroring.png + + Layout mirroring is useful when it is necessary to support both left-to-right and right-to-left + layout versions of an application to target different language areas. The \l childrenInherit + property allows layout mirroring to be applied without manually setting layout configurations + for every item in an application. Keep in mind, however, that mirroring does not affect any + positioning that is defined by the \l Item \l {Item::}{x} coordinate value, so even with + mirroring enabled, it will often be necessary to apply some layout fixes to support the + desired layout direction. Also, it may be necessary to disable the mirroring of individual + child items (by setting \l {enabled}{LayoutMirroring.enabled} to false for such items) if + mirroring is not the desired behavior, or if the child item already implements mirroring in + some custom way. + + See \l {QML Right-to-left User Interfaces} for further details on using \c LayoutMirroring and + other related features to implement right-to-left support for an application. +*/ + +/*! + \qmlproperty bool LayoutMirroring::enabled + + This property holds whether the item's layout is mirrored horizontally. Setting this to true + horizontally reverses \l {anchor-layout}{anchor} settings such that left anchors become right, + and right anchors become left. For \l{Using QML Positioner and Repeater Items}{positioner} elements + (such as \l Row and \l Grid) and view elements (such as \l {GridView}{GridView} and \l {ListView}{ListView}) + this also mirrors the horizontal layout direction of the item. + + The default value is false. +*/ + +/*! + \qmlproperty bool LayoutMirroring::childrenInherit + + This property holds whether the \l {enabled}{LayoutMirroring.enabled} value for this item + is inherited by its children. + + The default value is false. +*/ + +QDeclarativeLayoutMirroringAttached::QDeclarativeLayoutMirroringAttached(QObject *parent) : QObject(parent), itemPrivate(0) +{ + if (QDeclarativeItem *item = qobject_cast<QDeclarativeItem*>(parent)) { + itemPrivate = QDeclarativeItemPrivate::get(item); + itemPrivate->attachedLayoutDirection = this; + } else + qmlInfo(parent) << tr("LayoutDirection attached property only works with Items"); +} + +QDeclarativeLayoutMirroringAttached * QDeclarativeLayoutMirroringAttached::qmlAttachedProperties(QObject *object) +{ + return new QDeclarativeLayoutMirroringAttached(object); +} + +bool QDeclarativeLayoutMirroringAttached::enabled() const +{ + return itemPrivate ? itemPrivate->effectiveLayoutMirror : false; +} + +void QDeclarativeLayoutMirroringAttached::setEnabled(bool enabled) +{ + if (!itemPrivate) + return; + + itemPrivate->isMirrorImplicit = false; + if (enabled != itemPrivate->effectiveLayoutMirror) { + itemPrivate->setLayoutMirror(enabled); + if (itemPrivate->inheritMirrorFromItem) + itemPrivate->resolveLayoutMirror(); + } +} + +void QDeclarativeLayoutMirroringAttached::resetEnabled() +{ + if (itemPrivate && !itemPrivate->isMirrorImplicit) { + itemPrivate->isMirrorImplicit = true; + itemPrivate->resolveLayoutMirror(); + } +} + +bool QDeclarativeLayoutMirroringAttached::childrenInherit() const +{ + return itemPrivate ? itemPrivate->inheritMirrorFromItem : false; +} + +void QDeclarativeLayoutMirroringAttached::setChildrenInherit(bool childrenInherit) { + if (itemPrivate && childrenInherit != itemPrivate->inheritMirrorFromItem) { + itemPrivate->inheritMirrorFromItem = childrenInherit; + itemPrivate->resolveLayoutMirror(); + childrenInheritChanged(); + } +} + +void QDeclarativeItemPrivate::resolveLayoutMirror() +{ + Q_Q(QDeclarativeItem); + if (QDeclarativeItem *parentItem = q->parentItem()) { + QDeclarativeItemPrivate *parentPrivate = QDeclarativeItemPrivate::get(parentItem); + setImplicitLayoutMirror(parentPrivate->inheritedLayoutMirror, parentPrivate->inheritMirrorFromParent); + } else { + setImplicitLayoutMirror(isMirrorImplicit ? false : effectiveLayoutMirror, inheritMirrorFromItem); + } +} + +void QDeclarativeItemPrivate::setImplicitLayoutMirror(bool mirror, bool inherit) +{ + inherit = inherit || inheritMirrorFromItem; + if (!isMirrorImplicit && inheritMirrorFromItem) + mirror = effectiveLayoutMirror; + if (mirror == inheritedLayoutMirror && inherit == inheritMirrorFromParent) + return; + + inheritMirrorFromParent = inherit; + inheritedLayoutMirror = inheritMirrorFromParent ? mirror : false; + + if (isMirrorImplicit) + setLayoutMirror(inherit ? inheritedLayoutMirror : false); + for (int i = 0; i < children.count(); ++i) { + if (QDeclarativeItem *child = qobject_cast<QDeclarativeItem *>(children.at(i))) { + QDeclarativeItemPrivate *childPrivate = QDeclarativeItemPrivate::get(child); + childPrivate->setImplicitLayoutMirror(inheritedLayoutMirror, inheritMirrorFromParent); + } + } +} + +void QDeclarativeItemPrivate::setLayoutMirror(bool mirror) +{ + if (mirror != effectiveLayoutMirror) { + effectiveLayoutMirror = mirror; + if (_anchors) { + _anchors->d_func()->fillChanged(); + _anchors->d_func()->centerInChanged(); + _anchors->d_func()->updateHorizontalAnchors(); + emit _anchors->mirroredChanged(); + } + mirrorChange(); + if (attachedLayoutDirection) { + emit attachedLayoutDirection->enabledChanged(); + } + } +} + +/*! \qmlclass Keys QDeclarativeKeysAttached \ingroup qml-basic-interaction-elements \since 4.7 @@ -1397,6 +1574,11 @@ QDeclarativeKeysAttached *QDeclarativeKeysAttached::qmlAttachedProperties(QObjec \endqml See the \l {Keys}{Keys} attached property for detailed documentation. + + \section1 Layout Mirroring + + Item layouts can be mirrored using the \l {LayoutMirroring}{LayoutMirroring} attached property. + */ /*! @@ -2154,6 +2336,8 @@ QDeclarativeAnchorLine QDeclarativeItemPrivate::baseline() const \qmlproperty real Item::anchors.verticalCenterOffset \qmlproperty real Item::anchors.baselineOffset + \qmlproperty bool Item::anchors.mirrored + Anchors provide a way to position an item by specifying its relationship with other items. @@ -2211,6 +2395,8 @@ QDeclarativeAnchorLine QDeclarativeItemPrivate::baseline() const To clear an anchor value, set it to \c undefined. + \c anchors.mirrored returns true it the layout has been \l {LayoutMirroring}{mirrored}. + \note You can only anchor an item to siblings or a parent. For more information see \l {anchor-layout}{Anchor Layouts}. @@ -2561,7 +2747,7 @@ QDeclarativeListProperty<QDeclarativeState> QDeclarativeItemPrivate::states() } \endqml - \sa {qdeclarativeanimation.html#transitions}{QML Transitions} + \sa {QML Animation and Transitions}{Transitions} */ @@ -2812,6 +2998,7 @@ QVariant QDeclarativeItem::itemChange(GraphicsItemChange change, Q_D(QDeclarativeItem); switch (change) { case ItemParentHasChanged: + d->resolveLayoutMirror(); emit parentChanged(parentItem()); d->parentNotifier.notify(); break; @@ -3268,7 +3455,7 @@ qreal QDeclarativeItem::implicitHeight() const Setting the implicit size is useful for defining components that have a preferred size based on their content, for example: - \code + \qml // Label.qml import QtQuick 1.1 @@ -3285,7 +3472,7 @@ qreal QDeclarativeItem::implicitHeight() const anchors.verticalCenter: parent.verticalCenter } } - \endcode + \endqml \bold Note: using implicitWidth of Text or TextEdit and setting the width explicitly incurs a performance penalty as the text must be laid out twice. diff --git a/src/declarative/graphicsitems/qdeclarativeitem_p.h b/src/declarative/graphicsitems/qdeclarativeitem_p.h index 4303c0a..dae581c 100644 --- a/src/declarative/graphicsitems/qdeclarativeitem_p.h +++ b/src/declarative/graphicsitems/qdeclarativeitem_p.h @@ -77,6 +77,7 @@ QT_BEGIN_NAMESPACE class QNetworkReply; class QDeclarativeItemKeyFilter; +class QDeclarativeLayoutMirroringAttached; //### merge into private? class QDeclarativeContents : public QObject, public QDeclarativeItemChangeListener @@ -125,8 +126,10 @@ public: _stateGroup(0), origin(QDeclarativeItem::Center), widthValid(false), heightValid(false), componentComplete(true), keepMouse(false), - smooth(false), transformOriginDirty(true), doneEventPreHandler(false), keyHandler(0), - mWidth(0), mHeight(0), mImplicitWidth(0), mImplicitHeight(0), hadSubFocusItem(false) + smooth(false), transformOriginDirty(true), doneEventPreHandler(false), + inheritedLayoutMirror(false), effectiveLayoutMirror(false), isMirrorImplicit(true), + inheritMirrorFromParent(false), inheritMirrorFromItem(false), keyHandler(0), + mWidth(0), mHeight(0), mImplicitWidth(0), mImplicitHeight(0), attachedLayoutDirection(0), hadSubFocusItem(false) { QGraphicsItemPrivate::acceptedMouseButtons = 0; isDeclarativeItem = 1; @@ -134,7 +137,6 @@ public: QGraphicsItem::ItemHasNoContents | QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemNegativeZStacksBehindParent); - } void init(QDeclarativeItem *parent) @@ -143,11 +145,17 @@ public: if (parent) { QDeclarative_setParent_noEvent(q, parent); q->setParentItem(parent); + QDeclarativeItemPrivate *parentPrivate = QDeclarativeItemPrivate::get(parent); + setImplicitLayoutMirror(parentPrivate->inheritedLayoutMirror, parentPrivate->inheritMirrorFromParent); } baselineOffset.invalidate(); mouseSetsFocus = false; } + bool isMirrored() const { + return effectiveLayoutMirror; + } + // Private Properties qreal width() const; void setWidth(qreal); @@ -162,6 +170,10 @@ public: virtual void implicitWidthChanged(); virtual void implicitHeightChanged(); + void resolveLayoutMirror(); + void setImplicitLayoutMirror(bool mirror, bool inherit); + void setLayoutMirror(bool mirror); + QDeclarativeListProperty<QObject> data(); QDeclarativeListProperty<QObject> resources(); @@ -272,6 +284,11 @@ public: bool smooth:1; bool transformOriginDirty : 1; bool doneEventPreHandler : 1; + bool inheritedLayoutMirror:1; + bool effectiveLayoutMirror:1; + bool isMirrorImplicit:1; + bool inheritMirrorFromParent:1; + bool inheritMirrorFromItem:1; QDeclarativeItemKeyFilter *keyHandler; @@ -280,6 +297,8 @@ public: qreal mImplicitWidth; qreal mImplicitHeight; + QDeclarativeLayoutMirroringAttached* attachedLayoutDirection; + bool hadSubFocusItem; QPointF computeTransformOrigin() const; @@ -326,6 +345,8 @@ public: virtual void focusChanged(bool); + virtual void mirrorChange() {}; + static qint64 consistentTime; static void setConsistentTime(qint64 t); static void start(QElapsedTimer &); @@ -423,6 +444,31 @@ private: void setFocusNavigation(QDeclarativeItem *currentItem, const char *dir); }; +class QDeclarativeLayoutMirroringAttached : public QObject +{ + Q_OBJECT + Q_PROPERTY(bool enabled READ enabled WRITE setEnabled RESET resetEnabled NOTIFY enabledChanged) + Q_PROPERTY(bool childrenInherit READ childrenInherit WRITE setChildrenInherit NOTIFY childrenInheritChanged) + +public: + explicit QDeclarativeLayoutMirroringAttached(QObject *parent = 0); + + bool enabled() const; + void setEnabled(bool); + void resetEnabled(); + + bool childrenInherit() const; + void setChildrenInherit(bool); + + static QDeclarativeLayoutMirroringAttached *qmlAttachedProperties(QObject *); +Q_SIGNALS: + void enabledChanged(); + void childrenInheritChanged(); +private: + friend class QDeclarativeItemPrivate; + QDeclarativeItemPrivate *itemPrivate; +}; + class QDeclarativeKeysAttachedPrivate : public QObjectPrivate { public: @@ -572,5 +618,7 @@ QML_DECLARE_TYPE(QDeclarativeKeysAttached) QML_DECLARE_TYPEINFO(QDeclarativeKeysAttached, QML_HAS_ATTACHED_PROPERTIES) QML_DECLARE_TYPE(QDeclarativeKeyNavigationAttached) QML_DECLARE_TYPEINFO(QDeclarativeKeyNavigationAttached, QML_HAS_ATTACHED_PROPERTIES) +QML_DECLARE_TYPE(QDeclarativeLayoutMirroringAttached) +QML_DECLARE_TYPEINFO(QDeclarativeLayoutMirroringAttached, QML_HAS_ATTACHED_PROPERTIES) #endif // QDECLARATIVEITEM_P_H diff --git a/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp b/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp index 3c8f64e..c4a9030 100644 --- a/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp +++ b/src/declarative/graphicsitems/qdeclarativeitemsmodule.cpp @@ -198,6 +198,7 @@ void QDeclarativeItemModule::defineModule() qmlRegisterRevision<QDeclarativeImplicitSizeItem,1>("QtQuick",1,1); qmlRegisterRevision<QDeclarativeImplicitSizePaintedItem,0>("QtQuick",1,0); qmlRegisterRevision<QDeclarativeImplicitSizePaintedItem,1>("QtQuick",1,1); + qmlRegisterUncreatableType<QDeclarativeLayoutMirroringAttached>("QtQuick",1,1,"LayoutMirroring", QDeclarativeLayoutMirroringAttached::tr("LayoutMirroring is only available via attached properties")); #ifndef QT_NO_IMPORT_QT47_QML #ifdef QT_NO_MOVIE diff --git a/src/declarative/graphicsitems/qdeclarativelistview.cpp b/src/declarative/graphicsitems/qdeclarativelistview.cpp index e369ba6..7c01293 100644 --- a/src/declarative/graphicsitems/qdeclarativelistview.cpp +++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp @@ -100,13 +100,21 @@ public: } ~FxListItem() {} qreal position() const { - if (section) - return (view->orientation() == QDeclarativeListView::Vertical ? section->y() : section->x()); - else - return (view->orientation() == QDeclarativeListView::Vertical ? item->y() : item->x()); + if (section) { + if (view->orientation() == QDeclarativeListView::Vertical) + return section->y(); + else + return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -section->width()-section->x() : section->x()); + } else { + return itemPosition(); + } } + qreal itemPosition() const { - return (view->orientation() == QDeclarativeListView::Vertical ? item->y() : item->x()); + if (view->orientation() == QDeclarativeListView::Vertical) + return item->y(); + else + return (view->effectiveLayoutDirection() == Qt::RightToLeft ? -item->width()-item->x() : item->x()); } qreal size() const { if (section) @@ -123,9 +131,13 @@ public: return 0.0; } qreal endPosition() const { - return (view->orientation() == QDeclarativeListView::Vertical - ? item->y() + (item->height() >= 1.0 ? item->height() : 1) - : item->x() + (item->width() >= 1.0 ? item->width() : 1)) - 1; + if (view->orientation() == QDeclarativeListView::Vertical) { + return item->y() + (item->height() >= 1.0 ? item->height() : 1) - 1; + } else { + return (view->effectiveLayoutDirection() == Qt::RightToLeft + ? -item->width()-item->x() + (item->width() >= 1.0 ? item->width() : 1) + : item->x() + (item->width() >= 1.0 ? item->width() : 1)) - 1; + } } void setPosition(qreal pos) { if (view->orientation() == QDeclarativeListView::Vertical) { @@ -135,11 +147,19 @@ public: } item->setY(pos); } else { - if (section) { - section->setX(pos); - pos += section->width(); + if (view->effectiveLayoutDirection() == Qt::RightToLeft) { + if (section) { + section->setX(-section->width()-pos); + pos += section->width(); + } + item->setX(-item->width()-pos); + } else { + if (section) { + section->setX(pos); + pos += section->width(); + } + item->setX(pos); } - item->setX(pos); } } void setSize(qreal size) { @@ -168,10 +188,11 @@ class QDeclarativeListViewPrivate : public QDeclarativeFlickablePrivate public: QDeclarativeListViewPrivate() - : currentItem(0), orient(QDeclarativeListView::Vertical) + : currentItem(0), orient(QDeclarativeListView::Vertical), layoutDirection(Qt::LeftToRight) , visiblePos(0), visibleIndex(0) , averageSize(100.0), currentIndex(-1), requestedIndex(-1) , itemCount(0), highlightRangeStart(0), highlightRangeEnd(0) + , highlightRangeStartValid(false), highlightRangeEndValid(false) , highlightComponent(0), highlight(0), trackedItem(0) , moveReason(Other), buffer(0), highlightPosAnimator(0), highlightSizeAnimator(0) , sectionCriteria(0), spacing(0.0) @@ -204,7 +225,7 @@ public: } FxListItem *firstVisibleItem() const { - const qreal pos = position(); + const qreal pos = isRightToLeft() ? -position()-size() : position(); for (int i = 0; i < visibleItems.count(); ++i) { FxListItem *item = visibleItems.at(i); if (item->index != -1 && item->endPosition() > pos) @@ -214,7 +235,7 @@ public: } FxListItem *nextVisibleItem() const { - const qreal pos = position(); + const qreal pos = isRightToLeft() ? -position()-size() : position(); bool foundFirst = false; for (int i = 0; i < visibleItems.count(); ++i) { FxListItem *item = visibleItems.at(i); @@ -248,23 +269,65 @@ public: return 0; } + void regenerate() { + Q_Q(QDeclarativeListView); + if (q->isComponentComplete()) { + if (header) { + if (q->scene()) + q->scene()->removeItem(header->item); + header->item->deleteLater(); + delete header; + header = 0; + } + if (footer) { + if (q->scene()) + q->scene()->removeItem(footer->item); + footer->item->deleteLater(); + delete footer; + footer = 0; + } + updateHeader(); + updateFooter(); + clear(); + setPosition(0); + q->refill(); + updateCurrent(currentIndex); + } + } + + void mirrorChange() { + Q_Q(QDeclarativeListView); + regenerate(); + emit q->effectiveLayoutDirectionChanged(); + } + + bool isRightToLeft() const { + Q_Q(const QDeclarativeListView); + return orient == QDeclarativeListView::Horizontal && q->effectiveLayoutDirection() == Qt::RightToLeft; + } + qreal position() const { Q_Q(const QDeclarativeListView); return orient == QDeclarativeListView::Vertical ? q->contentY() : q->contentX(); } + void setPosition(qreal pos) { Q_Q(QDeclarativeListView); - if (orient == QDeclarativeListView::Vertical) + if (orient == QDeclarativeListView::Vertical) { q->QDeclarativeFlickable::setContentY(pos); - else - q->QDeclarativeFlickable::setContentX(pos); + } else { + if (isRightToLeft()) + q->QDeclarativeFlickable::setContentX(-pos-size()); + else + q->QDeclarativeFlickable::setContentX(pos); + } } qreal size() const { Q_Q(const QDeclarativeListView); return orient == QDeclarativeListView::Vertical ? q->height() : q->width(); } - qreal startPosition() const { + qreal originPosition() const { qreal pos = 0; if (!visibleItems.isEmpty()) { pos = (*visibleItems.constBegin())->position(); @@ -274,7 +337,7 @@ public: return pos; } - qreal endPosition() const { + qreal lastPosition() const { qreal pos = 0; if (!visibleItems.isEmpty()) { int invisibleCount = visibleItems.count() - visibleIndex; @@ -291,6 +354,14 @@ public: return pos; } + qreal startPosition() const { + return isRightToLeft() ? -lastPosition()-1 : originPosition(); + } + + qreal endPosition() const { + return isRightToLeft() ? -originPosition()-1 : lastPosition(); + } + qreal positionAt(int modelIndex) const { if (FxListItem *item = visibleItem(modelIndex)) return item->position(); @@ -312,6 +383,7 @@ public: else idx = visibleItems.at(idx)->index; int count = modelIndex - idx - 1; + return (*(--visibleItems.constEnd()))->endPosition() + spacing + count * (averageSize + spacing) + 1; } } @@ -368,7 +440,7 @@ public: } else if (pos > endPos) return endPos + qRound((pos - endPos) / averageSize) * averageSize; } - return qRound((pos - startPosition()) / averageSize) * averageSize + startPosition(); + return qRound((pos - originPosition()) / averageSize) * averageSize + originPosition(); } FxListItem *snapItemAt(qreal pos) { @@ -484,6 +556,7 @@ public: QHash<QDeclarativeItem*,int> unrequestedItems; FxListItem *currentItem; QDeclarativeListView::Orientation orient; + Qt::LayoutDirection layoutDirection; qreal visiblePos; int visibleIndex; qreal averageSize; @@ -492,6 +565,8 @@ public: int itemCount; qreal highlightRangeStart; qreal highlightRangeEnd; + bool highlightRangeStartValid; + bool highlightRangeEndValid; QDeclarativeComponent *highlightComponent; FxListItem *highlight; FxListItem *trackedItem; @@ -670,6 +745,27 @@ void QDeclarativeListViewPrivate::refill(qreal from, qreal to, bool doBuffer) modelIndex = visibleItems.at(i)->index + 1; } + if (visibleItems.count() && (fillFrom > itemEnd+averageSize+spacing + || fillTo < visiblePos - averageSize - spacing)) { + // We've jumped more than a page. Estimate which items are now + // visible and fill from there. + int count = (fillFrom - itemEnd) / (averageSize + spacing); + for (int i = 0; i < visibleItems.count(); ++i) + releaseItem(visibleItems.at(i)); + visibleItems.clear(); + modelIndex += count; + if (modelIndex >= model->count()) { + count -= modelIndex - model->count() + 1; + modelIndex = model->count() - 1; + } else if (modelIndex < 0) { + count -= modelIndex; + modelIndex = 0; + } + visibleIndex = modelIndex; + visiblePos = itemEnd + count * (averageSize + spacing) + 1; + itemEnd = visiblePos-1; + } + bool changed = false; FxListItem *item = 0; qreal pos = itemEnd + 1; @@ -815,8 +911,12 @@ void QDeclarativeListViewPrivate::updateUnrequestedPositions() if (item->y() + item->height() > pos && item->y() < pos + q->height()) item->setY(positionAt(*it)); } else { - if (item->x() + item->width() > pos && item->x() < pos + q->width()) - item->setX(positionAt(*it)); + if (item->x() + item->width() > pos && item->x() < pos + q->width()) { + if (isRightToLeft()) + item->setX(-positionAt(*it)-item->width()); + else + item->setX(positionAt(*it)); + } } } } @@ -907,7 +1007,9 @@ void QDeclarativeListViewPrivate::updateHighlight() createHighlight(); if (currentItem && autoHighlight && highlight && !movingHorizontally && !movingVertically) { // auto-update highlight - highlightPosAnimator->to = currentItem->itemPosition(); + highlightPosAnimator->to = isRightToLeft() + ? -currentItem->itemPosition()-currentItem->itemSize() + : currentItem->itemPosition(); highlightSizeAnimator->to = currentItem->itemSize(); if (orient == QDeclarativeListView::Vertical) { if (highlight->item->width() == 0) @@ -1125,7 +1227,7 @@ void QDeclarativeListViewPrivate::updateFooter() } if (footer) { if (visibleItems.count()) { - qreal endPos = endPosition() + 1; + qreal endPos = lastPosition() + 1; if (lastVisibleIndex() == model->count()-1) { footer->setPosition(endPos); } else { @@ -1165,7 +1267,7 @@ void QDeclarativeListViewPrivate::updateHeader() } if (header) { if (visibleItems.count()) { - qreal startPos = startPosition(); + qreal startPos = originPosition(); if (visibleIndex == 0) { header->setPosition(startPos - header->size()); } else { @@ -1200,14 +1302,30 @@ void QDeclarativeListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m correctFlick = false; fixupMode = moveReason == Mouse ? fixupMode : Immediate; - if (currentItem && haveHighlightRange && highlightRange == QDeclarativeListView::StrictlyEnforceRange) { + qreal highlightStart; + qreal highlightEnd; + qreal viewPos; + if (isRightToLeft()) { + // Handle Right-To-Left exceptions + viewPos = -position()-size(); + highlightStart = highlightRangeStartValid ? size() - highlightRangeEnd : highlightRangeStart; + highlightEnd = highlightRangeEndValid ? size() - highlightRangeStart : highlightRangeEnd; + } else { + viewPos = position(); + highlightStart = highlightRangeStart; + highlightEnd = highlightRangeEnd; + } + + if (currentItem && haveHighlightRange && highlightRange == QDeclarativeListView::StrictlyEnforceRange + && moveReason != QDeclarativeListViewPrivate::SetIndex) { updateHighlight(); qreal pos = currentItem->itemPosition(); - qreal viewPos = position(); - if (viewPos < pos + currentItem->itemSize() - highlightRangeEnd) - viewPos = pos + currentItem->itemSize() - highlightRangeEnd; - if (viewPos > pos - highlightRangeStart) - viewPos = pos - highlightRangeStart; + if (viewPos < pos + currentItem->itemSize() - highlightEnd) + viewPos = pos + currentItem->itemSize() - highlightEnd; + if (viewPos > pos - highlightStart) + viewPos = pos - highlightStart; + if (isRightToLeft()) + viewPos = -viewPos-size(); timeline.reset(data.move); if (viewPos != position()) { @@ -1219,17 +1337,26 @@ void QDeclarativeListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m } } vTime = timeline.time(); - } else if (snapMode != QDeclarativeListView::NoSnap) { - FxListItem *topItem = snapItemAt(position()+highlightRangeStart); - FxListItem *bottomItem = snapItemAt(position()+highlightRangeEnd); + } else if (snapMode != QDeclarativeListView::NoSnap && moveReason != QDeclarativeListViewPrivate::SetIndex) { + qreal tempPosition = isRightToLeft() ? -position()-size() : position(); + FxListItem *topItem = snapItemAt(tempPosition+highlightStart); + FxListItem *bottomItem = snapItemAt(tempPosition+highlightEnd); qreal pos; - if (topItem) { - if (topItem->index == 0 && header && position()+highlightRangeStart < header->position()+header->size()/2) - pos = header->position() - highlightRangeStart; + bool isInBounds = -position() > maxExtent && -position() < minExtent; + if (topItem && isInBounds) { + if (topItem->index == 0 && header && tempPosition+highlightStart < header->position()+header->size()/2) { + pos = isRightToLeft() ? - header->position() + highlightStart - size() : header->position() - highlightStart; + } else { + if (isRightToLeft()) + pos = qMax(qMin(-topItem->position() + highlightStart - size(), -maxExtent), -minExtent); + else + pos = qMax(qMin(topItem->position() - highlightStart, -maxExtent), -minExtent); + } + } else if (bottomItem && isInBounds) { + if (isRightToLeft()) + pos = qMax(qMin(-bottomItem->position() + highlightStart - size(), -maxExtent), -minExtent); else - pos = qMax(qMin(topItem->position() - highlightRangeStart, -maxExtent), -minExtent); - } else if (bottomItem) { - pos = qMax(qMin(bottomItem->position() - highlightRangeStart, -maxExtent), -minExtent); + pos = qMax(qMin(bottomItem->position() - highlightStart, -maxExtent), -minExtent); } else { QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent); return; @@ -1249,6 +1376,7 @@ void QDeclarativeListViewPrivate::fixup(AxisData &data, qreal minExtent, qreal m } else { QDeclarativeFlickablePrivate::fixup(data, minExtent, maxExtent); } + data.inOvershoot = false; fixupMode = Normal; } @@ -1265,12 +1393,13 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m return; } qreal maxDistance = 0; + qreal dataValue = isRightToLeft() ? -data.move.value()+size() : data.move.value(); // -ve velocity means list is moving up/left if (velocity > 0) { if (data.move.value() < minExtent) { if (snapMode == QDeclarativeListView::SnapOneItem) { - if (FxListItem *item = firstVisibleItem()) - maxDistance = qAbs(item->position() + data.move.value()); + if (FxListItem *item = isRightToLeft() ? nextVisibleItem() : firstVisibleItem()) + maxDistance = qAbs(item->position() + dataValue); } else { maxDistance = qAbs(minExtent - data.move.value()); } @@ -1280,8 +1409,8 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m } else { if (data.move.value() > maxExtent) { if (snapMode == QDeclarativeListView::SnapOneItem) { - if (FxListItem *item = nextVisibleItem()) - maxDistance = qAbs(item->position() + data.move.value()); + if (FxListItem *item = isRightToLeft() ? firstVisibleItem() : nextVisibleItem()) + maxDistance = qAbs(item->position() + dataValue); } else { maxDistance = qAbs(maxExtent - data.move.value()); } @@ -1289,7 +1418,10 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m if (snapMode == QDeclarativeListView::NoSnap && highlightRange != QDeclarativeListView::StrictlyEnforceRange) data.flickTarget = maxExtent; } + bool overShoot = boundsBehavior == QDeclarativeFlickable::DragAndOvershootBounds; + qreal highlightStart = isRightToLeft() && highlightRangeStartValid ? size()-highlightRangeEnd : highlightRangeStart; + if (maxDistance > 0 || overShoot) { // These modes require the list to stop exactly on an item boundary. // The initial flick will estimate the boundary to stop on. @@ -1314,13 +1446,15 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m if (v > 0) dist = -dist; if ((maxDistance > 0.0 && v2 / (2.0f * maxDistance) < accel) || snapMode == QDeclarativeListView::SnapOneItem) { - data.flickTarget = -snapPosAt(-(data.move.value() - highlightRangeStart) + dist) + highlightRangeStart; + qreal distTemp = isRightToLeft() ? -dist : dist; + data.flickTarget = -snapPosAt(-(dataValue - highlightStart) + distTemp) + highlightStart; + data.flickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget; if (overShoot) { if (data.flickTarget >= minExtent) { - overshootDist = overShootDistance(v, vSize); + overshootDist = overShootDistance(vSize); data.flickTarget += overshootDist; } else if (data.flickTarget <= maxExtent) { - overshootDist = overShootDistance(v, vSize); + overshootDist = overShootDistance(vSize); data.flickTarget -= overshootDist; } } @@ -1340,13 +1474,14 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m } else if (overShoot) { data.flickTarget = data.move.value() - dist; if (data.flickTarget >= minExtent) { - overshootDist = overShootDistance(v, vSize); + overshootDist = overShootDistance(vSize); data.flickTarget += overshootDist; } else if (data.flickTarget <= maxExtent) { - overshootDist = overShootDistance(v, vSize); + overshootDist = overShootDistance(vSize); data.flickTarget -= overshootDist; } } + timeline.reset(data.move); timeline.accel(data.move, v, accel, maxDistance + overshootDist); timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this)); @@ -1366,8 +1501,11 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m } else { // reevaluate the target boundary. qreal newtarget = data.flickTarget; - if (snapMode != QDeclarativeListView::NoSnap || highlightRange == QDeclarativeListView::StrictlyEnforceRange) - newtarget = -snapPosAt(-(data.flickTarget - highlightRangeStart)) + highlightRangeStart; + if (snapMode != QDeclarativeListView::NoSnap || highlightRange == QDeclarativeListView::StrictlyEnforceRange) { + qreal tempFlickTarget = isRightToLeft() ? -data.flickTarget+size() : data.flickTarget; + newtarget = -snapPosAt(-(tempFlickTarget - highlightStart)) + highlightStart; + newtarget = isRightToLeft() ? -newtarget+size() : newtarget; + } if (velocity < 0 && newtarget <= maxExtent) newtarget = maxExtent - overshootDist; else if (velocity > 0 && newtarget >= minExtent) @@ -1385,6 +1523,7 @@ void QDeclarativeListViewPrivate::flick(AxisData &data, qreal minExtent, qreal m fixup(data, minExtent, maxExtent); return; } + timeline.reset(data.move); timeline.accelDistance(data.move, v, -dist); timeline.callback(QDeclarativeTimeLineCallback(&data.move, fixupCallback, this)); @@ -1883,6 +2022,7 @@ qreal QDeclarativeListView::preferredHighlightBegin() const void QDeclarativeListView::setPreferredHighlightBegin(qreal start) { Q_D(QDeclarativeListView); + d->highlightRangeStartValid = true; if (d->highlightRangeStart == start) return; d->highlightRangeStart = start; @@ -1890,6 +2030,16 @@ void QDeclarativeListView::setPreferredHighlightBegin(qreal start) emit preferredHighlightBeginChanged(); } +void QDeclarativeListView::resetPreferredHighlightBegin() +{ + Q_D(QDeclarativeListView); + d->highlightRangeStartValid = false; + if (d->highlightRangeStart == 0) + return; + d->highlightRangeStart = 0; + emit preferredHighlightBeginChanged(); +} + qreal QDeclarativeListView::preferredHighlightEnd() const { Q_D(const QDeclarativeListView); @@ -1899,6 +2049,7 @@ qreal QDeclarativeListView::preferredHighlightEnd() const void QDeclarativeListView::setPreferredHighlightEnd(qreal end) { Q_D(QDeclarativeListView); + d->highlightRangeEndValid = true; if (d->highlightRangeEnd == end) return; d->highlightRangeEnd = end; @@ -1906,6 +2057,16 @@ void QDeclarativeListView::setPreferredHighlightEnd(qreal end) emit preferredHighlightEndChanged(); } +void QDeclarativeListView::resetPreferredHighlightEnd() +{ + Q_D(QDeclarativeListView); + d->highlightRangeEndValid = false; + if (d->highlightRangeEnd == 0) + return; + d->highlightRangeEnd = 0; + emit preferredHighlightEndChanged(); +} + QDeclarativeListView::HighlightRangeMode QDeclarativeListView::highlightRangeMode() const { Q_D(const QDeclarativeListView); @@ -1980,19 +2141,69 @@ void QDeclarativeListView::setOrientation(QDeclarativeListView::Orientation orie if (d->orient == QDeclarativeListView::Vertical) { setContentWidth(-1); setFlickableDirection(VerticalFlick); + setContentX(0); } else { setContentHeight(-1); setFlickableDirection(HorizontalFlick); + setContentY(0); } - d->clear(); - d->setPosition(0); - refill(); + d->regenerate(); emit orientationChanged(); - d->updateCurrent(d->currentIndex); } } /*! + \qmlproperty enumeration ListView::layoutDirection + This property holds the layout direction of the horizontal list. + + Possible values: + + \list + \o Qt.LeftToRight (default) - Items will be laid out from left to right. + \o Qt.RightToLeft - Items will be laid out from right to let. + \endlist + + \sa ListView::effectiveLayoutDirection +*/ + +Qt::LayoutDirection QDeclarativeListView::layoutDirection() const +{ + Q_D(const QDeclarativeListView); + return d->layoutDirection; +} + +void QDeclarativeListView::setLayoutDirection(Qt::LayoutDirection layoutDirection) +{ + Q_D(QDeclarativeListView); + if (d->layoutDirection != layoutDirection) { + d->layoutDirection = layoutDirection; + d->regenerate(); + emit layoutDirectionChanged(); + emit effectiveLayoutDirectionChanged(); + } +} + +/*! + \qmlproperty enumeration ListView::effectiveLayoutDirection + This property holds the effective layout direction of the horizontal list. + + When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts, + the visual layout direction of the horizontal list will be mirrored. However, the + property \l {ListView::layoutDirection}{layoutDirection} will remain unchanged. + + \sa ListView::layoutDirection, {LayoutMirroring}{LayoutMirroring} +*/ + +Qt::LayoutDirection QDeclarativeListView::effectiveLayoutDirection() const +{ + Q_D(const QDeclarativeListView); + if (d->effectiveLayoutMirror) + return d->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft; + else + return d->layoutDirection; +} + +/*! \qmlproperty bool ListView::keyNavigationWraps This property holds whether the list wraps key navigation. @@ -2363,11 +2574,23 @@ void QDeclarativeListView::viewportMoved() if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange && d->highlight) { // reposition highlight qreal pos = d->highlight->position(); - qreal viewPos = d->position(); - if (pos > viewPos + d->highlightRangeEnd - d->highlight->size()) - pos = viewPos + d->highlightRangeEnd - d->highlight->size(); - if (pos < viewPos + d->highlightRangeStart) - pos = viewPos + d->highlightRangeStart; + qreal viewPos; + qreal highlightStart; + qreal highlightEnd; + if (d->isRightToLeft()) { + // Handle Right-To-Left exceptions + viewPos = -d->position()-d->size(); + highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart; + highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd; + } else { + viewPos = d->position(); + highlightStart = d->highlightRangeStart; + highlightEnd = d->highlightRangeEnd; + } + if (pos > viewPos + highlightEnd - d->highlight->size()) + pos = viewPos + highlightEnd - d->highlight->size(); + if (pos < viewPos + highlightStart) + pos = viewPos + highlightStart; d->highlightPosAnimator->stop(); d->highlight->setPosition(qRound(pos)); @@ -2383,7 +2606,7 @@ void QDeclarativeListView::viewportMoved() d->inFlickCorrection = true; // Near an end and it seems that the extent has changed? // Recalculate the flick so that we don't end up in an odd position. - if (yflick()) { + if (yflick() && !d->vData.inOvershoot) { if (d->vData.velocity > 0) { const qreal minY = minYExtent(); if ((minY - d->vData.move.value() < height()/2 || d->vData.flickTarget - d->vData.move.value() < height()/2) @@ -2399,19 +2622,21 @@ void QDeclarativeListView::viewportMoved() } } - if (xflick()) { + if (xflick() && !d->hData.inOvershoot) { if (d->hData.velocity > 0) { const qreal minX = minXExtent(); if ((minX - d->hData.move.value() < width()/2 || d->hData.flickTarget - d->hData.move.value() < width()/2) && minX != d->hData.flickTarget) d->flickX(-d->hData.smoothVelocity.value()); - d->bufferMode = QDeclarativeListViewPrivate::BufferBefore; + d->bufferMode = d->isRightToLeft() + ? QDeclarativeListViewPrivate::BufferAfter : QDeclarativeListViewPrivate::BufferBefore; } else if (d->hData.velocity < 0) { const qreal maxX = maxXExtent(); if ((d->hData.move.value() - maxX < width()/2 || d->hData.move.value() - d->hData.flickTarget < width()/2) && maxX != d->hData.flickTarget) d->flickX(-d->hData.smoothVelocity.value()); - d->bufferMode = QDeclarativeListViewPrivate::BufferAfter; + d->bufferMode = d->isRightToLeft() + ? QDeclarativeListViewPrivate::BufferBefore : QDeclarativeListViewPrivate::BufferAfter; } } d->inFlickCorrection = false; @@ -2449,7 +2674,8 @@ qreal QDeclarativeListView::maxYExtent() const return height(); if (d->maxExtentDirty) { if (!d->model || !d->model->count()) { - d->maxExtent = 0; + d->maxExtent = d->header ? -d->header->size() : 0; + d->maxExtent += height(); } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { d->maxExtent = -(d->positionAt(d->model->count()-1) - d->highlightRangeStart); if (d->highlightRangeEnd != d->highlightRangeStart) @@ -2474,11 +2700,34 @@ qreal QDeclarativeListView::minXExtent() const return QDeclarativeFlickable::minXExtent(); if (d->minExtentDirty) { d->minExtent = -d->startPosition(); - if (d->header) - d->minExtent += d->header->size(); + + qreal highlightStart; + qreal highlightEnd; + qreal endPositionFirstItem = 0; + if (d->isRightToLeft()) { + if (d->model && d->model->count()) + endPositionFirstItem = d->positionAt(d->model->count()-1); + else if (d->header) + d->minExtent += d->header->size(); + highlightStart = d->highlightRangeStartValid + ? d->highlightRangeStart - (d->lastPosition()-endPositionFirstItem) + : d->size() - (d->lastPosition()-endPositionFirstItem); + highlightEnd = d->highlightRangeEndValid ? d->highlightRangeEnd : d->size(); + if (d->footer) + d->minExtent += d->footer->size(); + qreal maxX = maxXExtent(); + if (d->minExtent < maxX) + d->minExtent = maxX; + } else { + endPositionFirstItem = d->endPositionAt(0); + highlightStart = d->highlightRangeStart; + highlightEnd = d->highlightRangeEnd; + if (d->header && d->visibleItems.count()) + d->minExtent += d->header->size(); + } if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { - d->minExtent += d->highlightRangeStart; - d->minExtent = qMax(d->minExtent, -(d->endPositionAt(0) - d->highlightRangeEnd + 1)); + d->minExtent += highlightStart; + d->minExtent = qMax(d->minExtent, -(endPositionFirstItem - highlightEnd + 1)); } d->minExtentDirty = false; } @@ -2492,23 +2741,46 @@ qreal QDeclarativeListView::maxXExtent() const if (d->orient == QDeclarativeListView::Vertical) return width(); if (d->maxExtentDirty) { + qreal highlightStart; + qreal highlightEnd; + qreal lastItemPosition = 0; + d->maxExtent = 0; + if (d->isRightToLeft()) { + highlightStart = d->highlightRangeStartValid ? d->highlightRangeEnd : d->size(); + highlightEnd = d->highlightRangeEndValid ? d->highlightRangeStart : d->size(); + lastItemPosition = d->endPosition(); + } else { + highlightStart = d->highlightRangeStart; + highlightEnd = d->highlightRangeEnd; + if (d->model && d->model->count()) + lastItemPosition = d->positionAt(d->model->count()-1); + } if (!d->model || !d->model->count()) { - d->maxExtent = 0; + if (!d->isRightToLeft()) + d->maxExtent = d->header ? -d->header->size() : 0; + d->maxExtent += width(); } else if (d->haveHighlightRange && d->highlightRange == StrictlyEnforceRange) { - d->maxExtent = -(d->positionAt(d->model->count()-1) - d->highlightRangeStart); - if (d->highlightRangeEnd != d->highlightRangeStart) - d->maxExtent = qMin(d->maxExtent, -(d->endPosition() - d->highlightRangeEnd + 1)); + d->maxExtent = -(lastItemPosition - highlightStart); + if (highlightEnd != highlightStart) { + d->maxExtent = d->isRightToLeft() + ? qMax(d->maxExtent, -(d->endPosition() - highlightEnd + 1)) + : qMin(d->maxExtent, -(d->endPosition() - highlightEnd + 1)); + } } else { d->maxExtent = -(d->endPosition() - width() + 1); } - if (d->footer) - d->maxExtent -= d->footer->size(); - qreal minX = minXExtent(); - if (d->maxExtent > minX) - d->maxExtent = minX; + if (d->isRightToLeft()) { + if (d->header && d->visibleItems.count()) + d->maxExtent -= d->header->size(); + } else { + if (d->footer) + d->maxExtent -= d->footer->size(); + qreal minX = minXExtent(); + if (d->maxExtent > minX) + d->maxExtent = minX; + } d->maxExtentDirty = false; } - return d->maxExtent; } @@ -2520,7 +2792,8 @@ void QDeclarativeListView::keyPressEvent(QKeyEvent *event) return; if (d->model && d->model->count() && d->interactive) { - if ((d->orient == QDeclarativeListView::Horizontal && event->key() == Qt::Key_Left) + if ((d->orient == QDeclarativeListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Left) + || (d->orient == QDeclarativeListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Right) || (d->orient == QDeclarativeListView::Vertical && event->key() == Qt::Key_Up)) { if (currentIndex() > 0 || (d->wrap && !event->isAutoRepeat())) { decrementCurrentIndex(); @@ -2530,7 +2803,8 @@ void QDeclarativeListView::keyPressEvent(QKeyEvent *event) event->accept(); return; } - } else if ((d->orient == QDeclarativeListView::Horizontal && event->key() == Qt::Key_Right) + } else if ((d->orient == QDeclarativeListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Right) + || (d->orient == QDeclarativeListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Left) || (d->orient == QDeclarativeListView::Vertical && event->key() == Qt::Key_Down)) { if (currentIndex() < d->model->count() - 1 || (d->wrap && !event->isAutoRepeat())) { incrementCurrentIndex(); @@ -2552,6 +2826,11 @@ void QDeclarativeListView::geometryChanged(const QRectF &newGeometry, Q_D(QDeclarativeListView); d->maxExtentDirty = true; d->minExtentDirty = true; + if (d->isRightToLeft() && d->orient == Qt::Horizontal) { + // maintain position relative to the right edge + int dx = newGeometry.width() - oldGeometry.width(); + setContentX(contentX() - dx); + } QDeclarativeFlickable::geometryChanged(newGeometry, oldGeometry); } @@ -2607,9 +2886,14 @@ void QDeclarativeListViewPrivate::positionViewAtIndex(int index, int mode) if (layoutScheduled) layout(); - qreal pos = position(); + qreal pos = isRightToLeft() ? -position() - size() : position(); FxListItem *item = visibleItem(idx); - qreal maxExtent = orient == QDeclarativeListView::Vertical ? -q->maxYExtent() : -q->maxXExtent(); + qreal maxExtent; + if (orient == QDeclarativeListView::Vertical) + maxExtent = -q->maxYExtent(); + else + maxExtent = isRightToLeft() ? q->minXExtent()-size(): -q->maxXExtent(); + if (!item) { int itemPos = positionAt(idx); // save the currently visible items in case any of them end up visible again @@ -2652,7 +2936,12 @@ void QDeclarativeListViewPrivate::positionViewAtIndex(int index, int mode) pos = itemPos; } pos = qMin(pos, maxExtent); - qreal minExtent = orient == QDeclarativeListView::Vertical ? -q->minYExtent() : -q->minXExtent(); + qreal minExtent; + if (orient == QDeclarativeListView::Vertical) { + minExtent = -q->minYExtent(); + } else { + minExtent = isRightToLeft() ? q->maxXExtent()-size(): -q->minXExtent(); + } pos = qMax(pos, minExtent); moveReason = QDeclarativeListViewPrivate::Other; q->cancelFlick(); @@ -2810,7 +3099,10 @@ void QDeclarativeListView::updateSections() void QDeclarativeListView::refill() { Q_D(QDeclarativeListView); - d->refill(d->position(), d->position()+d->size()-1); + if (d->isRightToLeft()) + d->refill(-d->position()-d->size()+1, -d->position()); + else + d->refill(d->position(), d->position()+d->size()-1); } void QDeclarativeListView::trackedPositionChanged() @@ -2825,26 +3117,37 @@ void QDeclarativeListView::trackedPositionChanged() trackedPos -= d->currentItem->sectionSize(); trackedSize += d->currentItem->sectionSize(); } - const qreal viewPos = d->position(); + qreal viewPos; + qreal highlightStart; + qreal highlightEnd; + if (d->isRightToLeft()) { + viewPos = -d->position()-d->size(); + highlightStart = d->highlightRangeStartValid ? d->size()-d->highlightRangeEnd : d->highlightRangeStart; + highlightEnd = d->highlightRangeEndValid ? d->size()-d->highlightRangeStart : d->highlightRangeEnd; + } else { + viewPos = d->position(); + highlightStart = d->highlightRangeStart; + highlightEnd = d->highlightRangeEnd; + } qreal pos = viewPos; if (d->haveHighlightRange) { if (d->highlightRange == StrictlyEnforceRange) { - if (trackedPos > pos + d->highlightRangeEnd - d->trackedItem->size()) - pos = trackedPos - d->highlightRangeEnd + d->trackedItem->size(); - if (trackedPos < pos + d->highlightRangeStart) - pos = trackedPos - d->highlightRangeStart; + if (trackedPos > pos + highlightEnd - d->trackedItem->size()) + pos = trackedPos - highlightEnd + d->trackedItem->size(); + if (trackedPos < pos + highlightStart) + pos = trackedPos - highlightStart; } else { - if (trackedPos < d->startPosition() + d->highlightRangeStart) { + if (trackedPos < d->startPosition() + highlightStart) { pos = d->startPosition(); - } else if (d->trackedItem->endPosition() > d->endPosition() - d->size() + d->highlightRangeEnd) { + } else if (d->trackedItem->endPosition() > d->endPosition() - d->size() + highlightEnd) { pos = d->endPosition() - d->size() + 1; if (pos < d->startPosition()) pos = d->startPosition(); } else { - if (trackedPos < viewPos + d->highlightRangeStart) { - pos = trackedPos - d->highlightRangeStart; - } else if (trackedPos > viewPos + d->highlightRangeEnd - trackedSize) { - pos = trackedPos - d->highlightRangeEnd + trackedSize; + if (trackedPos < viewPos + highlightStart) { + pos = trackedPos - highlightStart; + } else if (trackedPos > viewPos + highlightEnd - trackedSize) { + pos = trackedPos - highlightEnd + trackedSize; } } } @@ -2881,7 +3184,9 @@ void QDeclarativeListView::itemsInserted(int modelIndex, int count) d->updateUnrequestedIndexes(); d->moveReason = QDeclarativeListViewPrivate::Other; + qreal tempPos = d->isRightToLeft() ? -d->position()-d->size() : d->position(); int index = d->visibleItems.count() ? d->mapFromModel(modelIndex) : 0; + if (index < 0) { int i = d->visibleItems.count() - 1; while (i > 0 && d->visibleItems.at(i)->index == -1) @@ -2890,7 +3195,7 @@ void QDeclarativeListView::itemsInserted(int modelIndex, int count) // there are no visible items except items marked for removal index = d->visibleItems.count(); } else if (d->visibleItems.at(i)->index + 1 == modelIndex - && d->visibleItems.at(i)->endPosition() < d->buffer+d->position()+d->size()-1) { + && d->visibleItems.at(i)->endPosition() < d->buffer+tempPos+d->size()-1) { // Special case of appending an item to the model. index = d->visibleItems.count(); } else { @@ -2935,7 +3240,7 @@ void QDeclarativeListView::itemsInserted(int modelIndex, int count) // Insert items before the visible item. int insertionIdx = index; int i = 0; - int from = d->position() - d->buffer; + int from = tempPos - d->buffer; for (i = count-1; i >= 0 && pos > from; --i) { if (!addedVisible) { d->scheduleLayout(); @@ -2965,7 +3270,7 @@ void QDeclarativeListView::itemsInserted(int modelIndex, int count) } } else { int i = 0; - int to = d->buffer+d->position()+d->size()-1; + int to = d->buffer+tempPos+d->size()-1; for (i = 0; i < count && pos <= to; ++i) { if (!addedVisible) { d->scheduleLayout(); @@ -2992,10 +3297,10 @@ void QDeclarativeListView::itemsInserted(int modelIndex, int count) if (d->currentItem) { d->currentItem->index = d->currentIndex; d->currentItem->setPosition(d->currentItem->position() + diff); - } else if (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared)) { - d->updateCurrent(0); } emit currentIndexChanged(); + } else if (!d->itemCount && (!d->currentIndex || (d->currentIndex < 0 && !d->currentIndexCleared))) { + d->updateCurrent(0); } // Update the indexes of the following visible items. for (; index < d->visibleItems.count(); ++index) { @@ -3076,6 +3381,8 @@ void QDeclarativeListView::itemsRemoved(int modelIndex, int count) d->currentIndex = -1; if (d->itemCount) d->updateCurrent(qMin(modelIndex, d->itemCount-1)); + else + emit currentIndexChanged(); } // update visibleIndex @@ -3241,11 +3548,8 @@ void QDeclarativeListView::itemsChanged(int, int) void QDeclarativeListView::modelReset() { Q_D(QDeclarativeListView); - d->clear(); - d->setPosition(0); - refill(); d->moveReason = QDeclarativeListViewPrivate::SetIndex; - d->updateCurrent(d->currentIndex); + d->regenerate(); if (d->highlight && d->currentItem) { if (d->autoHighlight) d->highlight->setPosition(d->currentItem->position()); @@ -3261,10 +3565,14 @@ void QDeclarativeListView::createdItem(int index, QDeclarativeItem *item) if (d->requestedIndex != index) { item->setParentItem(contentItem()); d->unrequestedItems.insert(item, index); - if (d->orient == QDeclarativeListView::Vertical) + if (d->orient == QDeclarativeListView::Vertical) { item->setY(d->positionAt(index)); - else - item->setX(d->positionAt(index)); + } else { + if (d->isRightToLeft()) + item->setX(-d->positionAt(index)-item->width()); + else + item->setX(d->positionAt(index)); + } } } diff --git a/src/declarative/graphicsitems/qdeclarativelistview_p.h b/src/declarative/graphicsitems/qdeclarativelistview_p.h index 265f4bd..3b12225 100644 --- a/src/declarative/graphicsitems/qdeclarativelistview_p.h +++ b/src/declarative/graphicsitems/qdeclarativelistview_p.h @@ -107,12 +107,14 @@ class Q_AUTOTEST_EXPORT QDeclarativeListView : public QDeclarativeFlickable Q_PROPERTY(qreal highlightResizeSpeed READ highlightResizeSpeed WRITE setHighlightResizeSpeed NOTIFY highlightResizeSpeedChanged) Q_PROPERTY(int highlightResizeDuration READ highlightResizeDuration WRITE setHighlightResizeDuration NOTIFY highlightResizeDurationChanged) - Q_PROPERTY(qreal preferredHighlightBegin READ preferredHighlightBegin WRITE setPreferredHighlightBegin NOTIFY preferredHighlightBeginChanged) - Q_PROPERTY(qreal preferredHighlightEnd READ preferredHighlightEnd WRITE setPreferredHighlightEnd NOTIFY preferredHighlightEndChanged) + Q_PROPERTY(qreal preferredHighlightBegin READ preferredHighlightBegin WRITE setPreferredHighlightBegin NOTIFY preferredHighlightBeginChanged RESET resetPreferredHighlightBegin) + Q_PROPERTY(qreal preferredHighlightEnd READ preferredHighlightEnd WRITE setPreferredHighlightEnd NOTIFY preferredHighlightEndChanged RESET resetPreferredHighlightEnd) Q_PROPERTY(HighlightRangeMode highlightRangeMode READ highlightRangeMode WRITE setHighlightRangeMode NOTIFY highlightRangeModeChanged) Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing NOTIFY spacingChanged) Q_PROPERTY(Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged) + Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged REVISION 1) + Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged REVISION 1) Q_PROPERTY(bool keyNavigationWraps READ isWrapEnabled WRITE setWrapEnabled NOTIFY keyNavigationWrapsChanged) Q_PROPERTY(int cacheBuffer READ cacheBuffer WRITE setCacheBuffer NOTIFY cacheBufferChanged) Q_PROPERTY(QDeclarativeViewSection *section READ sectionCriteria CONSTANT) @@ -158,9 +160,11 @@ public: qreal preferredHighlightBegin() const; void setPreferredHighlightBegin(qreal); + void resetPreferredHighlightBegin(); qreal preferredHighlightEnd() const; void setPreferredHighlightEnd(qreal); + void resetPreferredHighlightEnd(); qreal spacing() const; void setSpacing(qreal spacing); @@ -169,6 +173,10 @@ public: Orientation orientation() const; void setOrientation(Orientation); + Qt::LayoutDirection layoutDirection() const; + void setLayoutDirection(Qt::LayoutDirection); + Qt::LayoutDirection effectiveLayoutDirection() const; + bool isWrapEnabled() const; void setWrapEnabled(bool); @@ -220,6 +228,8 @@ Q_SIGNALS: void countChanged(); void spacingChanged(); void orientationChanged(); + Q_REVISION(1) void layoutDirectionChanged(); + Q_REVISION(1) void effectiveLayoutDirectionChanged(); void currentIndexChanged(); void currentSectionChanged(); void highlightMoveSpeedChanged(); diff --git a/src/declarative/graphicsitems/qdeclarativemousearea.cpp b/src/declarative/graphicsitems/qdeclarativemousearea.cpp index da11b00..f5145d0 100644 --- a/src/declarative/graphicsitems/qdeclarativemousearea.cpp +++ b/src/declarative/graphicsitems/qdeclarativemousearea.cpp @@ -216,7 +216,7 @@ QDeclarativeMouseAreaPrivate::~QDeclarativeMouseAreaPrivate() \section1 Example Usage - \div {float-right} + \div {class="float-right"} \inlineimage qml-mousearea-snippet.png \enddiv @@ -315,7 +315,7 @@ QDeclarativeMouseAreaPrivate::~QDeclarativeMouseAreaPrivate() The \e accepted property of the MouseEvent parameter is ignored in this handler. - \sa onCanceled() + \sa onCanceled */ /*! diff --git a/src/declarative/graphicsitems/qdeclarativepathview.cpp b/src/declarative/graphicsitems/qdeclarativepathview.cpp index 4e401e9..778b8b9 100644 --- a/src/declarative/graphicsitems/qdeclarativepathview.cpp +++ b/src/declarative/graphicsitems/qdeclarativepathview.cpp @@ -796,6 +796,7 @@ void QDeclarativePathView::setPreferredHighlightBegin(qreal start) return; d->highlightRangeStart = start; d->haveHighlightRange = d->highlightRangeMode != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd; + refill(); emit preferredHighlightBeginChanged(); } @@ -812,6 +813,7 @@ void QDeclarativePathView::setPreferredHighlightEnd(qreal end) return; d->highlightRangeEnd = end; d->haveHighlightRange = d->highlightRangeMode != NoHighlightRange && d->highlightRangeStart <= d->highlightRangeEnd; + refill(); emit preferredHighlightEndChanged(); } diff --git a/src/declarative/graphicsitems/qdeclarativepincharea.cpp b/src/declarative/graphicsitems/qdeclarativepincharea.cpp index eae83f6..c30ff8c 100644 --- a/src/declarative/graphicsitems/qdeclarativepincharea.cpp +++ b/src/declarative/graphicsitems/qdeclarativepincharea.cpp @@ -138,6 +138,14 @@ QT_BEGIN_NAMESPACE ignored. */ +/*! + \qmlproperty int PinchEvent::pointCount + + Holds the number of points currently touched. The PinchArea will not react + until two touch points have initited a gesture, but will remain active until + all touch points have been released. +*/ + QDeclarativePinch::QDeclarativePinch() : m_target(0), m_minScale(1.0), m_maxScale(1.0) , m_minRotation(0.0), m_maxRotation(0.0) @@ -295,137 +303,154 @@ bool QDeclarativePinchArea::event(QEvent *event) void QDeclarativePinchArea::updatePinch() { Q_D(QDeclarativePinchArea); - if (d->touchPoints.count() != 2) { + if (d->touchPoints.count() == 0) { if (d->inPinch) { d->stealMouse = false; setKeepMouseGrab(false); d->inPinch = false; - const qreal rotationAngle = d->pinchStartAngle - d->pinchLastAngle; QPointF pinchCenter = mapFromScene(d->sceneLastCenter); - QDeclarativePinchEvent pe(pinchCenter, d->pinchLastScale, d->pinchLastAngle, rotationAngle); + QDeclarativePinchEvent pe(pinchCenter, d->pinchLastScale, d->pinchLastAngle, d->pinchRotation); pe.setStartCenter(d->pinchStartCenter); pe.setPreviousCenter(pinchCenter); pe.setPreviousAngle(d->pinchLastAngle); pe.setPreviousScale(d->pinchLastScale); pe.setStartPoint1(mapFromScene(d->sceneStartPoint1)); pe.setStartPoint2(mapFromScene(d->sceneStartPoint2)); - pe.setPoint1(d->lastPoint1); - pe.setPoint2(d->lastPoint2); + pe.setPoint1(mapFromScene(d->lastPoint1)); + pe.setPoint2(mapFromScene(d->lastPoint2)); emit pinchFinished(&pe); d->pinchStartDist = 0; + d->pinchActivated = false; if (d->pinch && d->pinch->target()) d->pinch->setActive(false); } return; } - if (d->touchPoints.at(0).state() & Qt::TouchPointPressed - || d->touchPoints.at(1).state() & Qt::TouchPointPressed) { - d->sceneStartPoint1 = d->touchPoints.at(0).scenePos(); - d->sceneStartPoint2 = d->touchPoints.at(1).scenePos(); + QTouchEvent::TouchPoint touchPoint1 = d->touchPoints.at(0); + QTouchEvent::TouchPoint touchPoint2 = d->touchPoints.at(d->touchPoints. count() >= 2 ? 1 : 0); + if (d->touchPoints.count() == 2 + && (touchPoint1.state() & Qt::TouchPointPressed || touchPoint2.state() & Qt::TouchPointPressed)) { + d->id1 = touchPoint1.id(); + d->sceneStartPoint1 = touchPoint1.scenePos(); + d->sceneStartPoint2 = touchPoint2.scenePos(); d->inPinch = false; d->pinchRejected = false; - } else if (!d->pinchRejected){ - QDeclarativeItem *grabber = scene() ? qobject_cast<QDeclarativeItem*>(scene()->mouseGrabberItem()) : 0; - if (grabber == this || !grabber || !grabber->keepMouseGrab()) { - const int dragThreshold = QApplication::startDragDistance(); - QPointF p1 = d->touchPoints.at(0).scenePos(); - QPointF p2 = d->touchPoints.at(1).scenePos(); - qreal dx = p1.x() - p2.x(); - qreal dy = p1.y() - p2.y(); - qreal dist = sqrt(dx*dx + dy*dy); - QPointF sceneCenter = (p1 + p2)/2; - qreal angle = QLineF(p1, p2).angle(); - if (angle > 180) - angle -= 360; - if (!d->inPinch) { - if (qAbs(p1.x()-d->sceneStartPoint1.x()) > dragThreshold - || qAbs(p1.y()-d->sceneStartPoint1.y()) > dragThreshold - || qAbs(p2.x()-d->sceneStartPoint2.x()) > dragThreshold - || qAbs(p2.y()-d->sceneStartPoint2.y()) > dragThreshold) { - d->sceneStartCenter = sceneCenter; - d->sceneLastCenter = sceneCenter; - d->pinchStartCenter = mapFromScene(sceneCenter); - d->pinchStartDist = dist; - d->pinchStartAngle = angle; - d->pinchLastScale = 1.0; - d->pinchLastAngle = angle; - d->lastPoint1 = d->touchPoints.at(0).pos(); - d->lastPoint2 = d->touchPoints.at(1).pos(); - QDeclarativePinchEvent pe(d->pinchStartCenter, 1.0, angle, 0.0); - pe.setStartCenter(d->pinchStartCenter); - pe.setPreviousCenter(d->pinchStartCenter); - pe.setPreviousAngle(d->pinchLastAngle); - pe.setPreviousScale(d->pinchLastScale); - pe.setStartPoint1(mapFromScene(d->sceneStartPoint1)); - pe.setStartPoint2(mapFromScene(d->sceneStartPoint2)); - pe.setPoint1(d->lastPoint1); - pe.setPoint2(d->lastPoint2); - emit pinchStarted(&pe); - if (pe.accepted()) { - d->inPinch = true; - d->stealMouse = true; - QGraphicsScene *s = scene(); - if (s && s->mouseGrabberItem() != this) - grabMouse(); - setKeepMouseGrab(true); - if (d->pinch && d->pinch->target()) { - d->pinchStartPos = pinch()->target()->pos(); - d->pinchStartScale = d->pinch->target()->scale(); - d->pinchStartRotation = d->pinch->target()->rotation(); - d->pinch->setActive(true); - } - } else { - d->pinchRejected = true; - } - } - } else if (d->pinchStartDist > 0) { - qreal scale = dist / d->pinchStartDist; - qreal rotationAngle = d->pinchStartAngle - angle; - if (rotationAngle > 180) - rotationAngle -= 360; - QPointF pinchCenter = mapFromScene(sceneCenter); - QDeclarativePinchEvent pe(pinchCenter, scale, angle, rotationAngle); + d->pinchActivated = true; + } else if (d->pinchActivated && !d->pinchRejected) { + const int dragThreshold = QApplication::startDragDistance(); + QPointF p1 = touchPoint1.scenePos(); + QPointF p2 = touchPoint2.scenePos(); + qreal dx = p1.x() - p2.x(); + qreal dy = p1.y() - p2.y(); + qreal dist = sqrt(dx*dx + dy*dy); + QPointF sceneCenter = (p1 + p2)/2; + qreal angle = QLineF(p1, p2).angle(); + if (d->touchPoints.count() == 1) { + // If we only have one point then just move the center + if (d->id1 == touchPoint1.id()) + sceneCenter = d->sceneLastCenter + touchPoint1.scenePos() - d->lastPoint1; + else + sceneCenter = d->sceneLastCenter + touchPoint2.scenePos() - d->lastPoint2; + angle = d->pinchLastAngle; + } + d->id1 = touchPoint1.id(); + if (angle > 180) + angle -= 360; + if (!d->inPinch) { + if (d->touchPoints.count() >= 2 + && (qAbs(p1.x()-d->sceneStartPoint1.x()) > dragThreshold + || qAbs(p1.y()-d->sceneStartPoint1.y()) > dragThreshold + || qAbs(p2.x()-d->sceneStartPoint2.x()) > dragThreshold + || qAbs(p2.y()-d->sceneStartPoint2.y()) > dragThreshold)) { + d->sceneStartCenter = sceneCenter; + d->sceneLastCenter = sceneCenter; + d->pinchStartCenter = mapFromScene(sceneCenter); + d->pinchStartDist = dist; + d->pinchStartAngle = angle; + d->pinchLastScale = 1.0; + d->pinchLastAngle = angle; + d->pinchRotation = 0.0; + d->lastPoint1 = p1; + d->lastPoint2 = p2; + QDeclarativePinchEvent pe(d->pinchStartCenter, 1.0, angle, 0.0); pe.setStartCenter(d->pinchStartCenter); - pe.setPreviousCenter(mapFromScene(d->sceneLastCenter)); + pe.setPreviousCenter(d->pinchStartCenter); pe.setPreviousAngle(d->pinchLastAngle); pe.setPreviousScale(d->pinchLastScale); pe.setStartPoint1(mapFromScene(d->sceneStartPoint1)); pe.setStartPoint2(mapFromScene(d->sceneStartPoint2)); - pe.setPoint1(d->touchPoints.at(0).pos()); - pe.setPoint2(d->touchPoints.at(1).pos()); - d->pinchLastScale = scale; - d->sceneLastCenter = sceneCenter; - d->pinchLastAngle = angle; - d->lastPoint1 = d->touchPoints.at(0).pos(); - d->lastPoint2 = d->touchPoints.at(1).pos(); - emit pinchUpdated(&pe); - if (d->pinch && d->pinch->target()) { - qreal s = d->pinchStartScale * scale; - s = qMin(qMax(pinch()->minimumScale(),s), pinch()->maximumScale()); - pinch()->target()->setScale(s); - QPointF pos = sceneCenter - d->sceneStartCenter + d->pinchStartPos; - if (pinch()->axis() & QDeclarativePinch::XAxis) { - qreal x = pos.x(); - if (x < pinch()->xmin()) - x = pinch()->xmin(); - else if (x > pinch()->xmax()) - x = pinch()->xmax(); - pinch()->target()->setX(x); - } - if (pinch()->axis() & QDeclarativePinch::YAxis) { - qreal y = pos.y(); - if (y < pinch()->ymin()) - y = pinch()->ymin(); - else if (y > pinch()->ymax()) - y = pinch()->ymax(); - pinch()->target()->setY(y); - } - if (d->pinchStartRotation >= pinch()->minimumRotation() - && d->pinchStartRotation <= pinch()->maximumRotation()) { - qreal r = rotationAngle + d->pinchStartRotation; - r = qMin(qMax(pinch()->minimumRotation(),r), pinch()->maximumRotation()); - pinch()->target()->setRotation(r); + pe.setPoint1(mapFromScene(d->lastPoint1)); + pe.setPoint2(mapFromScene(d->lastPoint2)); + pe.setPointCount(d->touchPoints.count()); + emit pinchStarted(&pe); + if (pe.accepted()) { + d->inPinch = true; + d->stealMouse = true; + QGraphicsScene *s = scene(); + if (s && s->mouseGrabberItem() != this) + grabMouse(); + setKeepMouseGrab(true); + if (d->pinch && d->pinch->target()) { + d->pinchStartPos = pinch()->target()->pos(); + d->pinchStartScale = d->pinch->target()->scale(); + d->pinchStartRotation = d->pinch->target()->rotation(); + d->pinch->setActive(true); } + } else { + d->pinchRejected = true; + } + } + } else if (d->pinchStartDist > 0) { + qreal scale = dist ? dist / d->pinchStartDist : d->pinchLastScale; + qreal da = d->pinchLastAngle - angle; + if (da > 180) + da -= 360; + else if (da < -180) + da += 360; + d->pinchRotation += da; + QPointF pinchCenter = mapFromScene(sceneCenter); + QDeclarativePinchEvent pe(pinchCenter, scale, angle, d->pinchRotation); + pe.setStartCenter(d->pinchStartCenter); + pe.setPreviousCenter(mapFromScene(d->sceneLastCenter)); + pe.setPreviousAngle(d->pinchLastAngle); + pe.setPreviousScale(d->pinchLastScale); + pe.setStartPoint1(mapFromScene(d->sceneStartPoint1)); + pe.setStartPoint2(mapFromScene(d->sceneStartPoint2)); + pe.setPoint1(touchPoint1.pos()); + pe.setPoint2(touchPoint2.pos()); + pe.setPointCount(d->touchPoints.count()); + d->pinchLastScale = scale; + d->sceneLastCenter = sceneCenter; + d->pinchLastAngle = angle; + d->lastPoint1 = touchPoint1.scenePos(); + d->lastPoint2 = touchPoint2.scenePos(); + emit pinchUpdated(&pe); + if (d->pinch && d->pinch->target()) { + qreal s = d->pinchStartScale * scale; + s = qMin(qMax(pinch()->minimumScale(),s), pinch()->maximumScale()); + pinch()->target()->setScale(s); + QPointF pos = sceneCenter - d->sceneStartCenter + d->pinchStartPos; + if (pinch()->axis() & QDeclarativePinch::XAxis) { + qreal x = pos.x(); + if (x < pinch()->xmin()) + x = pinch()->xmin(); + else if (x > pinch()->xmax()) + x = pinch()->xmax(); + pinch()->target()->setX(x); + } + if (pinch()->axis() & QDeclarativePinch::YAxis) { + qreal y = pos.y(); + if (y < pinch()->ymin()) + y = pinch()->ymin(); + else if (y > pinch()->ymax()) + y = pinch()->ymax(); + pinch()->target()->setY(y); + } + if (d->pinchStartRotation >= pinch()->minimumRotation() + && d->pinchStartRotation <= pinch()->maximumRotation()) { + qreal r = d->pinchRotation + d->pinchStartRotation; + r = qMin(qMax(pinch()->minimumRotation(),r), pinch()->maximumRotation()); + pinch()->target()->setRotation(r); } } } diff --git a/src/declarative/graphicsitems/qdeclarativepincharea_p.h b/src/declarative/graphicsitems/qdeclarativepincharea_p.h index 6d04708..b5afea9 100644 --- a/src/declarative/graphicsitems/qdeclarativepincharea_p.h +++ b/src/declarative/graphicsitems/qdeclarativepincharea_p.h @@ -203,11 +203,13 @@ class Q_AUTOTEST_EXPORT QDeclarativePinchEvent : public QObject Q_PROPERTY(QPointF startPoint1 READ startPoint1) Q_PROPERTY(QPointF point2 READ point2) Q_PROPERTY(QPointF startPoint2 READ startPoint2) + Q_PROPERTY(int pointCount READ pointCount) Q_PROPERTY(bool accepted READ accepted WRITE setAccepted) public: QDeclarativePinchEvent(QPointF c, qreal s, qreal a, qreal r) - : QObject(), m_center(c), m_scale(s), m_angle(a), m_rotation(r), m_accepted(true) {} + : QObject(), m_center(c), m_scale(s), m_angle(a), m_rotation(r) + , m_pointCount(0), m_accepted(true) {} QPointF center() const { return m_center; } QPointF startCenter() const { return m_startCenter; } @@ -229,6 +231,8 @@ public: void setPoint2(QPointF p) { m_point2 = p; } QPointF startPoint2() const { return m_startPoint2; } void setStartPoint2(QPointF p) { m_startPoint2 = p; } + int pointCount() const { return m_pointCount; } + void setPointCount(int count) { m_pointCount = count; } bool accepted() const { return m_accepted; } void setAccepted(bool a) { m_accepted = a; } @@ -246,6 +250,7 @@ private: QPointF m_point2; QPointF m_startPoint1; QPointF m_startPoint2; + int m_pointCount; bool m_accepted; }; diff --git a/src/declarative/graphicsitems/qdeclarativepincharea_p_p.h b/src/declarative/graphicsitems/qdeclarativepincharea_p_p.h index 5641e35..3264948 100644 --- a/src/declarative/graphicsitems/qdeclarativepincharea_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativepincharea_p_p.h @@ -68,7 +68,10 @@ class QDeclarativePinchAreaPrivate : public QDeclarativeItemPrivate public: QDeclarativePinchAreaPrivate() : absorb(true), stealMouse(false), inPinch(false) - , pinchRejected(false), pinch(0), pinchStartDist(0) + , pinchRejected(false), pinchActivated(false) + , pinch(0), pinchStartDist(0), pinchStartScale(1.0) + , pinchLastScale(1.0), pinchStartRotation(0.0), pinchStartAngle(0.0) + , pinchLastAngle(0.0), pinchRotation(0.0) { } @@ -86,6 +89,7 @@ public: bool stealMouse : 1; bool inPinch : 1; bool pinchRejected : 1; + bool pinchActivated : 1; QDeclarativePinch *pinch; QPointF sceneStartPoint1; QPointF sceneStartPoint2; @@ -97,11 +101,13 @@ public: qreal pinchStartRotation; qreal pinchStartAngle; qreal pinchLastAngle; + qreal pinchRotation; QPointF sceneStartCenter; QPointF pinchStartCenter; QPointF sceneLastCenter; QPointF pinchStartPos; QList<QTouchEvent::TouchPoint> touchPoints; + int id1; }; QT_END_NAMESPACE diff --git a/src/declarative/graphicsitems/qdeclarativepositioners.cpp b/src/declarative/graphicsitems/qdeclarativepositioners.cpp index c0be2a2..e76fc03 100644 --- a/src/declarative/graphicsitems/qdeclarativepositioners.cpp +++ b/src/declarative/graphicsitems/qdeclarativepositioners.cpp @@ -385,7 +385,7 @@ void QDeclarativeBasePositioner::finishApplyTransitions() Items with a width or height of 0 will not be positioned. - \sa Row, Grid, Flow, {declarative/positioners/addandremove}{Positioners example} + \sa Row, Grid, Flow, {declarative/positioners}{Positioners example} */ /*! \qmlproperty Transition Column::add @@ -425,7 +425,7 @@ void QDeclarativeBasePositioner::finishApplyTransitions() } \endqml - \sa add, {declarative/positioners/addandremove}{Positioners example} + \sa add, {declarative/positioners}{Positioners example} */ /*! \qmlproperty int Column::spacing @@ -528,7 +528,7 @@ void QDeclarativeColumn::reportConflictingAnchors() Items with a width or height of 0 will not be positioned. - \sa Column, Grid, Flow, {declarative/positioners/addandremove}{Positioners example} + \sa Column, Grid, Flow, {declarative/positioners}{Positioners example} */ /*! \qmlproperty Transition Row::add @@ -567,7 +567,7 @@ void QDeclarativeColumn::reportConflictingAnchors() } \endqml - \sa add, {declarative/positioners/addandremove}{Positioners example} + \sa add, {declarative/positioners}{Positioners example} */ /*! \qmlproperty int Row::spacing @@ -578,7 +578,7 @@ void QDeclarativeColumn::reportConflictingAnchors() \sa Grid::spacing */ QDeclarativeRow::QDeclarativeRow(QDeclarativeItem *parent) -: QDeclarativeBasePositioner(Horizontal, parent), m_layoutDirection(Qt::LeftToRight) +: QDeclarativeBasePositioner(Horizontal, parent) { } @@ -597,24 +597,48 @@ QDeclarativeRow::QDeclarativeRow(QDeclarativeItem *parent) the right anchor remains to the right of the row. \endlist - \sa Grid::layoutDirection, Flow::layoutDirection, {declarative/positioners/layoutdirection}{Layout directions example} + \sa Grid::layoutDirection, Flow::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example} */ Qt::LayoutDirection QDeclarativeRow::layoutDirection() const { - return m_layoutDirection; + return QDeclarativeBasePositionerPrivate::getLayoutDirection(this); } void QDeclarativeRow::setLayoutDirection(Qt::LayoutDirection layoutDirection) { - if (m_layoutDirection != layoutDirection) { - m_layoutDirection = layoutDirection; + QDeclarativeBasePositionerPrivate *d = static_cast<QDeclarativeBasePositionerPrivate* >(QDeclarativeBasePositionerPrivate::get(this)); + if (d->layoutDirection != layoutDirection) { + d->layoutDirection = layoutDirection; + // For RTL layout the positioning changes when the width changes. + if (d->layoutDirection == Qt::RightToLeft) + d->addItemChangeListener(d, QDeclarativeItemPrivate::Geometry); + else + d->removeItemChangeListener(d, QDeclarativeItemPrivate::Geometry); prePositioning(); emit layoutDirectionChanged(); + emit effectiveLayoutDirectionChanged(); } } +/*! + \qmlproperty enumeration Row::effectiveLayoutDirection + This property holds the effective layout direction of the row positioner. + + When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts, + the visual layout direction of the row positioner will be mirrored. However, the + property \l {Row::layoutDirection}{layoutDirection} will remain unchanged. + + \sa Row::layoutDirection, {LayoutMirroring}{LayoutMirroring} +*/ + +Qt::LayoutDirection QDeclarativeRow::effectiveLayoutDirection() const +{ + return QDeclarativeBasePositionerPrivate::getEffectiveLayoutDirection(this); +} + void QDeclarativeRow::doPositioning(QSizeF *contentSize) { + QDeclarativeBasePositionerPrivate *d = static_cast<QDeclarativeBasePositionerPrivate*>(QDeclarativeBasePositionerPrivate::get(this)); int hoffset = 0; QList<int> hoffsets; @@ -623,7 +647,7 @@ void QDeclarativeRow::doPositioning(QSizeF *contentSize) if (!child.item || !child.isVisible) continue; - if(m_layoutDirection == Qt::LeftToRight){ + if(d->isLeftToRight()){ if(child.item->x() != hoffset) positionX(hoffset, child); }else{ @@ -638,7 +662,7 @@ void QDeclarativeRow::doPositioning(QSizeF *contentSize) contentSize->setWidth(hoffset - spacing()); - if(m_layoutDirection == Qt::LeftToRight) + if(d->isLeftToRight()) return; //Right to Left layout @@ -734,7 +758,7 @@ void QDeclarativeRow::reportConflictingAnchors() Items with a width or height of 0 will not be positioned. - \sa Flow, Row, Column, {declarative/positioners/addandremove}{Positioners example} + \sa Flow, Row, Column, {declarative/positioners}{Positioners example} */ /*! \qmlproperty Transition Grid::add @@ -772,7 +796,7 @@ void QDeclarativeRow::reportConflictingAnchors() } \endqml - \sa add, {declarative/positioners/addandremove}{Positioners example} + \sa add, {declarative/positioners}{Positioners example} */ /*! \qmlproperty int Grid::spacing @@ -792,7 +816,7 @@ void QDeclarativeRow::reportConflictingAnchors() \sa rows, columns */ QDeclarativeGrid::QDeclarativeGrid(QDeclarativeItem *parent) : - QDeclarativeBasePositioner(Both, parent), m_rows(-1), m_columns(-1), m_flow(LeftToRight), m_layoutDirection(Qt::LeftToRight) + QDeclarativeBasePositioner(Both, parent), m_rows(-1), m_columns(-1), m_flow(LeftToRight) { } @@ -868,33 +892,56 @@ void QDeclarativeGrid::setFlow(Flow flow) Possible values are: \list - \o Qt.LeftToRight (default) - Items are positioned beginning - from the top, left anchor. The flow direction is dependent - on the \l Grid::flow property. - \o Qt.RightToLeft - Items are positioned beginning from the - top, right anchor. The flow direction is dependent on the + \o Qt.LeftToRight (default) - Items are positioned from the top to bottom, + and left to right. The flow direction is dependent on the + \l Grid::flow property. + \o Qt.RightToLeft - Items are positioned from the top to bottom, + and right to left. The flow direction is dependent on the \l Grid::flow property. \endlist - \sa Flow::layoutDirection, Row::layoutDirection, {declarative/positioners/layoutdirection}{Layout directions example} + \sa Flow::layoutDirection, Row::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example} */ Qt::LayoutDirection QDeclarativeGrid::layoutDirection() const { - return m_layoutDirection; + return QDeclarativeBasePositionerPrivate::getLayoutDirection(this); } void QDeclarativeGrid::setLayoutDirection(Qt::LayoutDirection layoutDirection) { - if (m_layoutDirection != layoutDirection) { - m_layoutDirection = layoutDirection; + QDeclarativeBasePositionerPrivate *d = static_cast<QDeclarativeBasePositionerPrivate*>(QDeclarativeBasePositionerPrivate::get(this)); + if (d->layoutDirection != layoutDirection) { + d->layoutDirection = layoutDirection; + // For RTL layout the positioning changes when the width changes. + if (d->layoutDirection == Qt::RightToLeft) + d->addItemChangeListener(d, QDeclarativeItemPrivate::Geometry); + else + d->removeItemChangeListener(d, QDeclarativeItemPrivate::Geometry); prePositioning(); emit layoutDirectionChanged(); + emit effectiveLayoutDirectionChanged(); } } -void QDeclarativeGrid::doPositioning(QSizeF *contentSize) +/*! + \qmlproperty enumeration Grid::effectiveLayoutDirection + This property holds the effective layout direction of the grid positioner. + + When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts, + the visual layout direction of the grid positioner will be mirrored. However, the + property \l {Grid::layoutDirection}{layoutDirection} will remain unchanged. + + \sa Grid::layoutDirection, {LayoutMirroring}{LayoutMirroring} +*/ + +Qt::LayoutDirection QDeclarativeGrid::effectiveLayoutDirection() const { + return QDeclarativeBasePositionerPrivate::getEffectiveLayoutDirection(this); +} +void QDeclarativeGrid::doPositioning(QSizeF *contentSize) +{ + QDeclarativeBasePositionerPrivate *d = static_cast<QDeclarativeBasePositionerPrivate*>(QDeclarativeBasePositionerPrivate::get(this)); int c = m_columns; int r = m_rows; //Is allocating the extra QPODVector too much overhead? @@ -984,7 +1031,7 @@ void QDeclarativeGrid::doPositioning(QSizeF *contentSize) end = widthSum; int xoffset=0; - if(m_layoutDirection == Qt::RightToLeft) + if(!d->isLeftToRight()) xoffset=end; int yoffset=0; int curRow =0; @@ -992,7 +1039,7 @@ void QDeclarativeGrid::doPositioning(QSizeF *contentSize) for (int i = 0; i < visibleItems.count(); ++i) { const PositionedItem &child = visibleItems.at(i); int childXOffset = xoffset; - if(m_layoutDirection == Qt::RightToLeft) + if(!d->isLeftToRight()) childXOffset -= QGraphicsItemPrivate::get(child.item)->width(); if((child.item->x()!=childXOffset)||(child.item->y()!=yoffset)){ positionX(childXOffset, child); @@ -1000,7 +1047,7 @@ void QDeclarativeGrid::doPositioning(QSizeF *contentSize) } if (m_flow == LeftToRight) { - if(m_layoutDirection == Qt::LeftToRight) + if(d->isLeftToRight()) xoffset+=maxColWidth[curCol]+spacing(); else xoffset-=maxColWidth[curCol]+spacing(); @@ -1008,7 +1055,7 @@ void QDeclarativeGrid::doPositioning(QSizeF *contentSize) curCol%=c; if (!curCol){ yoffset+=maxRowHeight[curRow]+spacing(); - if(m_layoutDirection == Qt::LeftToRight) + if(d->isLeftToRight()) xoffset=0; else xoffset=end; @@ -1021,7 +1068,7 @@ void QDeclarativeGrid::doPositioning(QSizeF *contentSize) curRow++; curRow%=r; if (!curRow){ - if(m_layoutDirection == Qt::LeftToRight) + if(d->isLeftToRight()) xoffset+=maxColWidth[curCol]+spacing(); else xoffset-=maxColWidth[curCol]+spacing(); @@ -1100,7 +1147,7 @@ void QDeclarativeGrid::reportConflictingAnchors() Items with a width or height of 0 will not be positioned. - \sa Column, Row, Grid, {declarative/positioners/addandremove}{Positioners example} + \sa Column, Row, Grid, {declarative/positioners}{Positioners example} */ /*! \qmlproperty Transition Flow::add @@ -1139,7 +1186,7 @@ void QDeclarativeGrid::reportConflictingAnchors() } \endqml - \sa add, {declarative/positioners/addandremove}{Positioners example} + \sa add, {declarative/positioners}{Positioners example} */ /*! \qmlproperty int Flow::spacing @@ -1156,12 +1203,10 @@ class QDeclarativeFlowPrivate : public QDeclarativeBasePositionerPrivate public: QDeclarativeFlowPrivate() - : QDeclarativeBasePositionerPrivate(), flow(QDeclarativeFlow::LeftToRight), - layoutDirection(Qt::LeftToRight) + : QDeclarativeBasePositionerPrivate(), flow(QDeclarativeFlow::LeftToRight) {} QDeclarativeFlow::Flow flow; - Qt::LayoutDirection layoutDirection; }; QDeclarativeFlow::QDeclarativeFlow(QDeclarativeItem *parent) @@ -1212,15 +1257,15 @@ void QDeclarativeFlow::setFlow(Flow flow) Possible values are: \list - \o Qt.LeftToRight (default) - Items are positioned beginning - from the top, left anchor. The flow direction is dependent - on the \l Flow::flow property. - \o Qt.RightToLeft - Items are positioned beginning from the - top, right anchor. The flow direction is dependent on the + \o Qt.LeftToRight (default) - Items are positioned from the top to bottom, + and left to right. The flow direction is dependent on the + \l Flow::flow property. + \o Qt.RightToLeft - Items are positioned from the top to bottom, + and right to left. The flow direction is dependent on the \l Flow::flow property. \endlist - \sa Grid::layoutDirection, Row::layoutDirection, {declarative/positioners/layoutdirection}{Layout directions example} + \sa Grid::layoutDirection, Row::layoutDirection, {declarative/righttoleft/layoutdirection}{Layout directions example} */ Qt::LayoutDirection QDeclarativeFlow::layoutDirection() const @@ -1236,9 +1281,26 @@ void QDeclarativeFlow::setLayoutDirection(Qt::LayoutDirection layoutDirection) d->layoutDirection = layoutDirection; prePositioning(); emit layoutDirectionChanged(); + emit effectiveLayoutDirectionChanged(); } } +/*! + \qmlproperty enumeration Flow::effectiveLayoutDirection + This property holds the effective layout direction of the flow positioner. + + When using the attached property \l {LayoutMirroring::enabled}{LayoutMirroring::enabled} for locale layouts, + the visual layout direction of the grid positioner will be mirrored. However, the + property \l {Flow::layoutDirection}{layoutDirection} will remain unchanged. + + \sa Flow::layoutDirection, {LayoutMirroring}{LayoutMirroring} +*/ + +Qt::LayoutDirection QDeclarativeFlow::effectiveLayoutDirection() const +{ + return QDeclarativeBasePositionerPrivate::getEffectiveLayoutDirection(this); +} + void QDeclarativeFlow::doPositioning(QSizeF *contentSize) { Q_D(QDeclarativeFlow); @@ -1268,7 +1330,7 @@ void QDeclarativeFlow::doPositioning(QSizeF *contentSize) } } - if(d->layoutDirection == Qt::LeftToRight){ + if(d->isLeftToRight()){ if(child.item->x() != hoffset) positionX(hoffset, child); }else{ @@ -1291,7 +1353,7 @@ void QDeclarativeFlow::doPositioning(QSizeF *contentSize) } } - if(d->layoutDirection == Qt::LeftToRight) + if(d->isLeftToRight()) return; int end; diff --git a/src/declarative/graphicsitems/qdeclarativepositioners_p.h b/src/declarative/graphicsitems/qdeclarativepositioners_p.h index 55d8fa1..214c04f 100644 --- a/src/declarative/graphicsitems/qdeclarativepositioners_p.h +++ b/src/declarative/graphicsitems/qdeclarativepositioners_p.h @@ -130,20 +130,22 @@ class Q_AUTOTEST_EXPORT QDeclarativeRow: public QDeclarativeBasePositioner { Q_OBJECT Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged REVISION 1) + Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged REVISION 1) public: QDeclarativeRow(QDeclarativeItem *parent=0); Qt::LayoutDirection layoutDirection() const; void setLayoutDirection (Qt::LayoutDirection); + Qt::LayoutDirection effectiveLayoutDirection() const; Q_SIGNALS: Q_REVISION(1) void layoutDirectionChanged(); + Q_REVISION(1) void effectiveLayoutDirectionChanged(); protected: virtual void doPositioning(QSizeF *contentSize); virtual void reportConflictingAnchors(); private: - Qt::LayoutDirection m_layoutDirection; Q_DISABLE_COPY(QDeclarativeRow) }; @@ -154,7 +156,7 @@ class Q_AUTOTEST_EXPORT QDeclarativeGrid : public QDeclarativeBasePositioner Q_PROPERTY(int columns READ columns WRITE setColumns NOTIFY columnsChanged) Q_PROPERTY(Flow flow READ flow WRITE setFlow NOTIFY flowChanged) Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged REVISION 1) - + Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged REVISION 1) public: QDeclarativeGrid(QDeclarativeItem *parent=0); @@ -171,12 +173,14 @@ public: Qt::LayoutDirection layoutDirection() const; void setLayoutDirection (Qt::LayoutDirection); + Qt::LayoutDirection effectiveLayoutDirection() const; Q_SIGNALS: void rowsChanged(); void columnsChanged(); void flowChanged(); Q_REVISION(1) void layoutDirectionChanged(); + Q_REVISION(1) void effectiveLayoutDirectionChanged(); protected: virtual void doPositioning(QSizeF *contentSize); @@ -186,7 +190,6 @@ private: int m_rows; int m_columns; Flow m_flow; - Qt::LayoutDirection m_layoutDirection; Q_DISABLE_COPY(QDeclarativeGrid) }; @@ -194,8 +197,9 @@ class QDeclarativeFlowPrivate; class Q_AUTOTEST_EXPORT QDeclarativeFlow: public QDeclarativeBasePositioner { Q_OBJECT - Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged REVISION 1) Q_PROPERTY(Flow flow READ flow WRITE setFlow NOTIFY flowChanged) + Q_PROPERTY(Qt::LayoutDirection layoutDirection READ layoutDirection WRITE setLayoutDirection NOTIFY layoutDirectionChanged REVISION 1) + Q_PROPERTY(Qt::LayoutDirection effectiveLayoutDirection READ effectiveLayoutDirection NOTIFY effectiveLayoutDirectionChanged REVISION 1) public: QDeclarativeFlow(QDeclarativeItem *parent=0); @@ -206,10 +210,11 @@ public: Qt::LayoutDirection layoutDirection() const; void setLayoutDirection (Qt::LayoutDirection); - + Qt::LayoutDirection effectiveLayoutDirection() const; Q_SIGNALS: void flowChanged(); Q_REVISION(1) void layoutDirectionChanged(); + Q_REVISION(1) void effectiveLayoutDirectionChanged(); protected: virtual void doPositioning(QSizeF *contentSize); diff --git a/src/declarative/graphicsitems/qdeclarativepositioners_p_p.h b/src/declarative/graphicsitems/qdeclarativepositioners_p_p.h index df105c6..e80129d 100644 --- a/src/declarative/graphicsitems/qdeclarativepositioners_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativepositioners_p_p.h @@ -75,7 +75,7 @@ public: QDeclarativeBasePositionerPrivate() : spacing(0), type(QDeclarativeBasePositioner::None) , moveTransition(0), addTransition(0), queuedPositioning(false) - , doingPositioning(false), anchorConflict(false) + , doingPositioning(false), anchorConflict(false), layoutDirection(Qt::LeftToRight) { } @@ -100,6 +100,9 @@ public: bool doingPositioning : 1; bool anchorConflict : 1; + Qt::LayoutDirection layoutDirection; + + void schedulePositioning() { Q_Q(QDeclarativeBasePositioner); @@ -109,6 +112,18 @@ public: } } + void mirrorChange() { + Q_Q(QDeclarativeBasePositioner); + if (type != QDeclarativeBasePositioner::Vertical) + q->prePositioning(); + } + bool isLeftToRight() const { + if (type == QDeclarativeBasePositioner::Vertical) + return true; + else + return effectiveLayoutMirror ? layoutDirection == Qt::RightToLeft : layoutDirection == Qt::LeftToRight; + } + virtual void itemSiblingOrderChanged(QDeclarativeItem* other) { Q_UNUSED(other); @@ -139,6 +154,19 @@ public: Q_Q(QDeclarativeBasePositioner); q->positionedItems.removeOne(QDeclarativeBasePositioner::PositionedItem(item)); } + + static Qt::LayoutDirection getLayoutDirection(const QDeclarativeBasePositioner *positioner) + { + return positioner->d_func()->layoutDirection; + } + + static Qt::LayoutDirection getEffectiveLayoutDirection(const QDeclarativeBasePositioner *positioner) + { + if (positioner->d_func()->effectiveLayoutMirror) + return positioner->d_func()->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft; + else + return positioner->d_func()->layoutDirection; + } }; QT_END_NAMESPACE diff --git a/src/declarative/graphicsitems/qdeclarativerectangle.cpp b/src/declarative/graphicsitems/qdeclarativerectangle.cpp index d962919..b3235ef 100644 --- a/src/declarative/graphicsitems/qdeclarativerectangle.cpp +++ b/src/declarative/graphicsitems/qdeclarativerectangle.cpp @@ -70,7 +70,7 @@ QT_BEGIN_NAMESPACE void QDeclarativePen::setColor(const QColor &c) { _color = c; - _valid = _color.alpha() ? true : false; + _valid = (_color.alpha() && _width >= 1) ? true : false; emit penChanged(); } @@ -80,7 +80,7 @@ void QDeclarativePen::setWidth(int w) return; _width = w; - _valid = (_width < 1) ? false : true; + _valid = (_color.alpha() && _width >= 1) ? true : false; emit penChanged(); } @@ -134,7 +134,7 @@ void QDeclarativeGradientStop::updateGradient() \section1 Example Usage - \div {float-right} + \div {class="float-right"} \inlineimage qml-gradient.png \enddiv @@ -220,7 +220,7 @@ void QDeclarativeGradient::doUpdate() \section1 Example Usage - \div {float-right} + \div {class="float-right"} \inlineimage declarative-rect.png \enddiv @@ -272,7 +272,7 @@ void QDeclarativeRectangle::doUpdate() rectangle (as documented for QRect rendering). This can cause unintended effects if \c border.width is 1 and the rectangle is \l{Item::clip}{clipped} by a parent item: - \div {float-right} + \div {class="float-right"} \inlineimage rect-border-width.png \enddiv @@ -296,7 +296,7 @@ QDeclarativePen *QDeclarativeRectangle::border() This property allows for the construction of simple vertical gradients. Other gradients may by formed by adding rotation to the rectangle. - \div {float-left} + \div {class="float-left"} \inlineimage declarative-rect_gradient.png \enddiv @@ -364,7 +364,7 @@ void QDeclarativeRectangle::setRadius(qreal radius) The default color is white. - \div {float-right} + \div {class="float-right"} \inlineimage rect-color.png \enddiv diff --git a/src/declarative/graphicsitems/qdeclarativetext.cpp b/src/declarative/graphicsitems/qdeclarativetext.cpp index 044425d..720692c 100644 --- a/src/declarative/graphicsitems/qdeclarativetext.cpp +++ b/src/declarative/graphicsitems/qdeclarativetext.cpp @@ -50,7 +50,6 @@ #include <QTextLayout> #include <QTextLine> #include <QTextDocument> -#include <QTextCursor> #include <QGraphicsSceneMouseEvent> #include <QPainter> #include <QAbstractTextDocumentLayout> @@ -97,13 +96,12 @@ DEFINE_BOOL_CONFIG_OPTION(enableImageCache, QML_ENABLE_TEXT_IMAGE_CACHE); QString QDeclarativeTextPrivate::elideChar = QString(0x2026); QDeclarativeTextPrivate::QDeclarativeTextPrivate() -: color((QRgb)0), style(QDeclarativeText::Normal), hAlign(QDeclarativeText::AlignLeft), +: color((QRgb)0), style(QDeclarativeText::Normal), hAlign(QDeclarativeText::AlignLeft), vAlign(QDeclarativeText::AlignTop), elideMode(QDeclarativeText::ElideNone), format(QDeclarativeText::AutoText), wrapMode(QDeclarativeText::NoWrap), lineHeight(1), - lineHeightMode(QDeclarativeText::ProportionalHeight), - lineCount(1), truncated(false), maximumLineCount(INT_MAX), + lineHeightMode(QDeclarativeText::ProportionalHeight), lineCount(1), truncated(false), maximumLineCount(INT_MAX), maximumLineCountValid(false), imageCacheDirty(true), updateOnComponentComplete(true), richText(false), singleline(false), - cacheAllTextAsImage(true), internalWidthUpdate(false), requireImplicitWidth(false), naturalWidth(0), doc(0) + cacheAllTextAsImage(true), internalWidthUpdate(false), requireImplicitWidth(false), hAlignImplicit(true), rightToLeftText(false), naturalWidth(0), doc(0) { cacheAllTextAsImage = enableImageCache(); QGraphicsItemPrivate::acceptedMouseButtons = Qt::LeftButton; @@ -283,18 +281,26 @@ void QDeclarativeTextPrivate::updateSize() //setup instance of QTextLayout for all cases other than richtext if (!richText) { - size = setupTextLayout(); - if (layedOutTextSize != size) { + QRect textRect = setupTextLayout(); + if (layedOutTextRect.size() != textRect.size()) q->prepareGeometryChange(); - layedOutTextSize = size; - } + layedOutTextRect = textRect; + size = textRect.size(); dy -= size.height(); } else { singleline = false; // richtext can't elide or be optimized for single-line case ensureDoc(); doc->setDefaultFont(font); + + QDeclarativeText::HAlignment horizontalAlignment = q->effectiveHAlign(); + if (rightToLeftText) { + if (horizontalAlignment == QDeclarativeText::AlignLeft) + horizontalAlignment = QDeclarativeText::AlignRight; + else if (horizontalAlignment == QDeclarativeText::AlignRight) + horizontalAlignment = QDeclarativeText::AlignLeft; + } QTextOption option; - option.setAlignment((Qt::Alignment)int(hAlign | vAlign)); + option.setAlignment((Qt::Alignment)int(horizontalAlignment | vAlign)); option.setWrapMode(QTextOption::WrapMode(wrapMode)); doc->setDefaultTextOption(option); if (requireImplicitWidth && q->widthValid()) { @@ -307,9 +313,9 @@ void QDeclarativeTextPrivate::updateSize() doc->setTextWidth(doc->idealWidth()); // ### Text does not align if width is not set (QTextDoc bug) dy -= (int)doc->size().height(); QSize dsize = doc->size().toSize(); - if (dsize != layedOutTextSize) { + if (dsize != layedOutTextRect.size()) { q->prepareGeometryChange(); - layedOutTextSize = dsize; + layedOutTextRect = QRect(QPoint(0,0), dsize); } size = QSize(int(doc->idealWidth()),dsize.height()); } @@ -344,45 +350,29 @@ void QDeclarativeTextPrivate::updateSize() Returns the size of the final text. This can be used to position the text vertically (the text is already absolutely positioned horizontally). */ -QSize QDeclarativeTextPrivate::setupTextLayout() +QRect QDeclarativeTextPrivate::setupTextLayout() { // ### text layout handling should be profiled and optimized as needed // what about QStackTextEngine engine(tmp, d->font.font()); QTextLayout textLayout(&engine); Q_Q(QDeclarativeText); layout.setCacheEnabled(true); - qreal height = 0; - qreal widthUsed = 0; qreal lineWidth = 0; - int visibleTextLength = 0; int visibleCount = 0; //set manual width - if ((wrapMode != QDeclarativeText::NoWrap || elideMode != QDeclarativeText::ElideNone) && q->widthValid()) + if (q->widthValid()) lineWidth = q->width(); QTextOption textOption = layout.textOption(); - if (hAlign == QDeclarativeText::AlignJustify) - textOption.setAlignment(Qt::Alignment(hAlign)); + textOption.setAlignment(Qt::Alignment(q->effectiveHAlign())); textOption.setWrapMode(QTextOption::WrapMode(wrapMode)); layout.setTextOption(textOption); - QDeclarativeText::HAlignment hAlignment = hAlign; - if(text.isRightToLeft()) { - if ((hAlign == QDeclarativeText::AlignLeft) || (hAlign == QDeclarativeText::AlignJustify)) { - hAlignment = QDeclarativeText::AlignRight; - } else if (hAlign == QDeclarativeText::AlignRight) { - hAlignment = QDeclarativeText::AlignLeft; - } else { - hAlignment = hAlign; - } - } - bool elideText = false; bool truncate = false; QFontMetrics fm(layout.font()); - qreal elideWidth = fm.width(elideChar); elidePos = QPointF(); if (requireImplicitWidth && q->widthValid()) { @@ -394,47 +384,47 @@ QSize QDeclarativeTextPrivate::setupTextLayout() break; } layout.endLayout(); - naturalWidth = 0; + QRectF br; for (int i = 0; i < layout.lineCount(); ++i) { QTextLine line = layout.lineAt(i); - naturalWidth = qMax(naturalWidth, line.naturalTextWidth()); + br = br.united(line.naturalTextRect()); } + naturalWidth = br.width(); } if (maximumLineCountValid) { layout.beginLayout(); if (!lineWidth) lineWidth = INT_MAX; - int y = 0; int linesLeft = maximumLineCount; + int visibleTextLength = 0; while (linesLeft > 0) { QTextLine line = layout.createLine(); if (!line.isValid()) break; visibleCount++; - line.setLineWidth(lineWidth); + if (lineWidth) + line.setLineWidth(lineWidth); visibleTextLength += line.textLength(); if (--linesLeft == 0) { if (visibleTextLength < text.length()) { truncate = true; if (elideMode==QDeclarativeText::ElideRight && q->widthValid()) { + qreal elideWidth = fm.width(elideChar); // Need to correct for alignment line.setLineWidth(lineWidth-elideWidth); - int x = line.naturalTextWidth(); - if (hAlignment == QDeclarativeText::AlignRight) { - x = q->width()-elideWidth; - } else if (hAlignment == QDeclarativeText::AlignHCenter) { - x = (q->width()+line.naturalTextWidth()-elideWidth)/2; + if (layout.text().mid(line.textStart(), line.textLength()).isRightToLeft()) { + line.setPosition(QPointF(line.position().x() + elideWidth, line.position().y())); + elidePos.setX(line.naturalTextRect().left() - elideWidth); + } else { + elidePos.setX(line.naturalTextRect().right()); } - elidePos = QPointF(x, y + fm.ascent()); elideText = true; } } } - - y += line.height(); } layout.endLayout(); @@ -456,36 +446,23 @@ QSize QDeclarativeTextPrivate::setupTextLayout() layout.endLayout(); } + qreal height = 0; + QRectF br; for (int i = 0; i < layout.lineCount(); ++i) { QTextLine line = layout.lineAt(i); - widthUsed = qMax(widthUsed, line.naturalTextWidth()); + // set line spacing + line.setPosition(QPointF(line.position().x(), height)); + if (elideText && i == layout.lineCount()-1) { + elidePos.setY(height + fm.ascent()); + br = br.united(QRectF(elidePos, QSizeF(fm.width(elideChar), fm.ascent()))); + } + br = br.united(line.naturalTextRect()); + height += (lineHeightMode == QDeclarativeText::FixedHeight) ? lineHeight : line.height() * lineHeight; } + br.setHeight(height); - qreal layoutWidth = q->widthValid() ? q->width() : widthUsed; if (!q->widthValid()) - naturalWidth = layoutWidth; - - qreal x = 0; - for (int i = 0; i < layout.lineCount(); ++i) { - QTextLine line = layout.lineAt(i); - line.setPosition(QPointF(0, height)); - height += (lineHeightMode == QDeclarativeText::FixedHeight) ? lineHeight : line.height() * lineHeight; - - if (!cacheAllTextAsImage) { - if ((hAlignment == QDeclarativeText::AlignLeft) || (hAlignment == QDeclarativeText::AlignJustify)) { - x = 0; - } else if (hAlignment == QDeclarativeText::AlignRight) { - x = layoutWidth - line.naturalTextWidth(); - if (elideText && i == layout.lineCount()-1) - x -= elideWidth; // Correct for when eliding multilines - } else if (hAlignment == QDeclarativeText::AlignHCenter) { - x = (layoutWidth - line.naturalTextWidth()) / 2; - if (elideText && i == layout.lineCount()-1) - x -= elideWidth/2; // Correct for when eliding multilines - } - line.setPosition(QPointF(x, line.y())); - } - } + naturalWidth = br.width(); //Update the number of visible lines if (lineCount != visibleCount) { @@ -493,7 +470,7 @@ QSize QDeclarativeTextPrivate::setupTextLayout() emit q->lineCountChanged(); } - return QSize(qCeil(widthUsed), qCeil(height)); + return QRect(qRound(br.x()), qRound(br.y()), qCeil(br.width()), qCeil(br.height())); } /*! @@ -503,21 +480,7 @@ QSize QDeclarativeTextPrivate::setupTextLayout() QPixmap QDeclarativeTextPrivate::textLayoutImage(bool drawStyle) { //do layout - QSize size = layedOutTextSize; - - qreal x = 0; - for (int i = 0; i < layout.lineCount(); ++i) { - QTextLine line = layout.lineAt(i); - if ((hAlign == QDeclarativeText::AlignLeft) || (hAlign == QDeclarativeText::AlignJustify)) { - x = 0; - } else if (hAlign == QDeclarativeText::AlignRight) { - x = size.width() - line.naturalTextWidth(); - } else if (hAlign == QDeclarativeText::AlignHCenter) { - x = (size.width() - line.naturalTextWidth()) / 2; - } - line.setPosition(QPointF(x, line.y())); - } - + QSize size = layedOutTextRect.size(); //paint text QPixmap img(size); if (!size.isEmpty()) { @@ -530,7 +493,7 @@ QPixmap QDeclarativeTextPrivate::textLayoutImage(bool drawStyle) #ifdef Q_WS_MAC qt_applefontsmoothing_enabled = oldSmooth; #endif - drawTextLayout(&p, QPointF(0,0), drawStyle); + drawTextLayout(&p, QPointF(-layedOutTextRect.x(),0), drawStyle); } return img; } @@ -548,7 +511,7 @@ void QDeclarativeTextPrivate::drawTextLayout(QPainter *painter, const QPointF &p painter->setFont(font); layout.draw(painter, pos); if (!elidePos.isNull()) - painter->drawText(elidePos, elideChar); + painter->drawText(pos + elidePos, elideChar); } /*! @@ -953,14 +916,18 @@ void QDeclarativeText::setText(const QString &n) return; d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(n)); - if (d->richText && isComponentComplete()) { - d->ensureDoc(); - d->doc->setText(n); - } - d->text = n; + if (isComponentComplete()) { + if (d->richText) { + d->ensureDoc(); + d->doc->setText(n); + d->rightToLeftText = d->doc->toPlainText().isRightToLeft(); + } else { + d->rightToLeftText = d->text.isRightToLeft(); + } + d->determineHorizontalAlignment(); + } d->updateLayout(); - emit textChanged(d->text); } @@ -1083,9 +1050,12 @@ void QDeclarativeText::setStyleColor(const QColor &color) /*! \qmlproperty enumeration Text::horizontalAlignment \qmlproperty enumeration Text::verticalAlignment + \qmlproperty enumeration Text::effectiveHorizontalAlignment Sets the horizontal and vertical alignment of the text within the Text items - width and height. By default, the text is top-left aligned. + width and height. By default, the text is vertically aligned to the top. Horizontal + alignment follows the natural alignment of the text, for example text that is read + from left to right will be aligned to the left. The valid values for \c horizontalAlignment are \c Text.AlignLeft, \c Text.AlignRight, \c Text.AlignHCenter and \c Text.AlignJustify. The valid values for \c verticalAlignment are \c Text.AlignTop, \c Text.AlignBottom @@ -1095,6 +1065,11 @@ void QDeclarativeText::setStyleColor(const QColor &color) all alignments are equivalent. If you want the text to be, say, centered in its parent, then you will need to either modify the Item::anchors, or set horizontalAlignment to Text.AlignHCenter and bind the width to that of the parent. + + When using the attached property LayoutMirroring::enabled to mirror application + layouts, the horizontal alignment of text will also be mirrored. However, the property + \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment + of Text, use the read-only property \c effectiveHorizontalAlignment. */ QDeclarativeText::HAlignment QDeclarativeText::hAlign() const { @@ -1105,16 +1080,78 @@ QDeclarativeText::HAlignment QDeclarativeText::hAlign() const void QDeclarativeText::setHAlign(HAlignment align) { Q_D(QDeclarativeText); - if (d->hAlign == align) - return; + bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror; + d->hAlignImplicit = false; + if (d->setHAlign(align, forceAlign) && isComponentComplete()) + d->updateLayout(); +} - if (isComponentComplete()) - prepareGeometryChange(); +void QDeclarativeText::resetHAlign() +{ + Q_D(QDeclarativeText); + d->hAlignImplicit = true; + if (d->determineHorizontalAlignment() && isComponentComplete()) + d->updateLayout(); +} - d->hAlign = align; - d->updateLayout(); +QDeclarativeText::HAlignment QDeclarativeText::effectiveHAlign() const +{ + Q_D(const QDeclarativeText); + QDeclarativeText::HAlignment effectiveAlignment = d->hAlign; + if (!d->hAlignImplicit && d->effectiveLayoutMirror) { + switch (d->hAlign) { + case QDeclarativeText::AlignLeft: + effectiveAlignment = QDeclarativeText::AlignRight; + break; + case QDeclarativeText::AlignRight: + effectiveAlignment = QDeclarativeText::AlignLeft; + break; + default: + break; + } + } + return effectiveAlignment; +} + +bool QDeclarativeTextPrivate::setHAlign(QDeclarativeText::HAlignment alignment, bool forceAlign) +{ + Q_Q(QDeclarativeText); + if (hAlign != alignment || forceAlign) { + QDeclarativeText::HAlignment oldEffectiveHAlign = q->effectiveHAlign(); + hAlign = alignment; + + emit q->horizontalAlignmentChanged(hAlign); + if (oldEffectiveHAlign != q->effectiveHAlign()) + emit q->effectiveHorizontalAlignmentChanged(); + return true; + } + return false; +} + +bool QDeclarativeTextPrivate::determineHorizontalAlignment() +{ + Q_Q(QDeclarativeText); + if (hAlignImplicit && q->isComponentComplete()) { + bool alignToRight = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText; + return setHAlign(alignToRight ? QDeclarativeText::AlignRight : QDeclarativeText::AlignLeft); + } + return false; +} - emit horizontalAlignmentChanged(align); +void QDeclarativeTextPrivate::mirrorChange() +{ + Q_Q(QDeclarativeText); + if (q->isComponentComplete()) { + if (!hAlignImplicit && (hAlign == QDeclarativeText::AlignRight || hAlign == QDeclarativeText::AlignLeft)) { + updateLayout(); + emit q->effectiveHorizontalAlignmentChanged(); + } + } +} + +QTextDocument *QDeclarativeTextPrivate::textDocument() +{ + return doc; } QDeclarativeText::VAlignment QDeclarativeText::vAlign() const @@ -1368,44 +1405,25 @@ QRectF QDeclarativeText::boundingRect() const { Q_D(const QDeclarativeText); - int w = width(); - int h = height(); - - int x = 0; - int y = 0; - - QSize size = d->layedOutTextSize; + QRect rect = d->layedOutTextRect; if (d->style != Normal) - size += QSize(2,2); + rect.adjust(-1, 0, 1, 2); // Could include font max left/right bearings to either side of rectangle. - switch (d->hAlign) { - case AlignLeft: - case AlignJustify: - x = 0; - break; - case AlignRight: - x = w - size.width(); - break; - case AlignHCenter: - x = (w - size.width()) / 2; - break; - } - + int h = height(); switch (d->vAlign) { case AlignTop: - y = 0; break; case AlignBottom: - y = h - size.height(); + rect.moveTop(h - rect.height()); break; case AlignVCenter: - y = (h - size.height()) / 2; + rect.moveTop((h - rect.height()) / 2); break; } - return QRectF(x,y,size.width(),size.height()); + return QRectF(rect); } /*! \internal */ @@ -1551,8 +1569,8 @@ void QDeclarativeText::paint(QPainter *p, const QStyleOptionGraphicsItem *, QWid } else { QRectF bounds = boundingRect(); - bool needClip = clip() && (d->layedOutTextSize.width() > width() || - d->layedOutTextSize.height() > height()); + bool needClip = clip() && (d->layedOutTextRect.width() > width() || + d->layedOutTextRect.height() > height()); if (needClip) { p->save(); @@ -1584,7 +1602,11 @@ void QDeclarativeText::componentComplete() if (d->richText) { d->ensureDoc(); d->doc->setText(d->text); + d->rightToLeftText = d->doc->toPlainText().isRightToLeft(); + } else { + d->rightToLeftText = d->text.isRightToLeft(); } + d->determineHorizontalAlignment(); d->updateLayout(); } } diff --git a/src/declarative/graphicsitems/qdeclarativetext_p.h b/src/declarative/graphicsitems/qdeclarativetext_p.h index b8835d1..a1153c2 100644 --- a/src/declarative/graphicsitems/qdeclarativetext_p.h +++ b/src/declarative/graphicsitems/qdeclarativetext_p.h @@ -69,7 +69,8 @@ class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeText : public QDeclarativeImplici Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) Q_PROPERTY(TextStyle style READ style WRITE setStyle NOTIFY styleChanged) Q_PROPERTY(QColor styleColor READ styleColor WRITE setStyleColor NOTIFY styleColorChanged) - Q_PROPERTY(HAlignment horizontalAlignment READ hAlign WRITE setHAlign NOTIFY horizontalAlignmentChanged) + Q_PROPERTY(HAlignment horizontalAlignment READ hAlign WRITE setHAlign RESET resetHAlign NOTIFY horizontalAlignmentChanged) + Q_PROPERTY(HAlignment effectiveHorizontalAlignment READ effectiveHAlign NOTIFY effectiveHorizontalAlignmentChanged REVISION 1) Q_PROPERTY(VAlignment verticalAlignment READ vAlign WRITE setVAlign NOTIFY verticalAlignmentChanged) Q_PROPERTY(WrapMode wrapMode READ wrapMode WRITE setWrapMode NOTIFY wrapModeChanged) Q_PROPERTY(int lineCount READ lineCount NOTIFY lineCountChanged REVISION 1) @@ -133,6 +134,8 @@ public: HAlignment hAlign() const; void setHAlign(HAlignment align); + void resetHAlign(); + HAlignment effectiveHAlign() const; VAlignment vAlign() const; void setVAlign(VAlignment align); @@ -188,6 +191,7 @@ Q_SIGNALS: void paintedSizeChanged(); Q_REVISION(1) void lineHeightChanged(qreal lineHeight); Q_REVISION(1) void lineHeightModeChanged(LineHeightMode mode); + Q_REVISION(1) void effectiveHorizontalAlignmentChanged(); protected: void mousePressEvent(QGraphicsSceneMouseEvent *event); diff --git a/src/declarative/graphicsitems/qdeclarativetext_p_p.h b/src/declarative/graphicsitems/qdeclarativetext_p_p.h index 36ae123..e3ab62a 100644 --- a/src/declarative/graphicsitems/qdeclarativetext_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativetext_p_p.h @@ -76,6 +76,10 @@ public: void updateSize(); void updateLayout(); + bool determineHorizontalAlignment(); + bool setHAlign(QDeclarativeText::HAlignment, bool forceAlign = false); + void mirrorChange(); + QTextDocument *textDocument(); QString text; QFont font; @@ -110,8 +114,10 @@ public: bool cacheAllTextAsImage:1; bool internalWidthUpdate:1; bool requireImplicitWidth:1; + bool hAlignImplicit:1; + bool rightToLeftText:1; - QSize layedOutTextSize; + QRect layedOutTextRect; QSize paintedSize; qreal naturalWidth; virtual qreal implicitWidth() const; @@ -119,7 +125,7 @@ public: QPixmap textDocumentImage(bool drawStyle); QTextDocumentWithImageResources *doc; - QSize setupTextLayout(); + QRect setupTextLayout(); QPixmap textLayoutImage(bool drawStyle); void drawTextLayout(QPainter *p, const QPointF &pos, bool drawStyle); QDeclarativeTextLayout layout; diff --git a/src/declarative/graphicsitems/qdeclarativetextedit.cpp b/src/declarative/graphicsitems/qdeclarativetextedit.cpp index d3c5b82..af2c8f3 100644 --- a/src/declarative/graphicsitems/qdeclarativetextedit.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextedit.cpp @@ -48,6 +48,7 @@ #include <QtCore/qmath.h> +#include <private/qtextengine_p.h> #include <QTextLayout> #include <QTextLine> #include <QTextDocument> @@ -249,6 +250,7 @@ void QDeclarativeTextEdit::setText(const QString &text) Q_D(QDeclarativeTextEdit); if (QDeclarativeTextEdit::text() == text) return; + d->richText = d->format == RichText || (d->format == AutoText && Qt::mightBeRichText(text)); if (d->richText) { #ifndef QT_NO_TEXTHTMLPARSER @@ -457,9 +459,12 @@ void QDeclarativeTextEdit::setSelectedTextColor(const QColor &color) /*! \qmlproperty enumeration TextEdit::horizontalAlignment \qmlproperty enumeration TextEdit::verticalAlignment + \qmlproperty enumeration TextEdit::effectiveHorizontalAlignment Sets the horizontal and vertical alignment of the text within the TextEdit item's - width and height. By default, the text is top-left aligned. + width and height. By default, the text alignment follows the natural alignment + of the text, for example text that is read from left to right will be aligned to + the left. Valid values for \c horizontalAlignment are: \list @@ -473,8 +478,13 @@ void QDeclarativeTextEdit::setSelectedTextColor(const QColor &color) \list \o TextEdit.AlignTop (default) \o TextEdit.AlignBottom - \c TextEdit.AlignVCenter + \o TextEdit.AlignVCenter \endlist + + When using the attached property LayoutMirroring::enabled to mirror application + layouts, the horizontal alignment of text will also be mirrored. However, the property + \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment + of TextEdit, use the read-only property \c effectiveHorizontalAlignment. */ QDeclarativeTextEdit::HAlignment QDeclarativeTextEdit::hAlign() const { @@ -482,15 +492,80 @@ QDeclarativeTextEdit::HAlignment QDeclarativeTextEdit::hAlign() const return d->hAlign; } -void QDeclarativeTextEdit::setHAlign(QDeclarativeTextEdit::HAlignment alignment) +void QDeclarativeTextEdit::setHAlign(HAlignment align) { Q_D(QDeclarativeTextEdit); - if (alignment == d->hAlign) - return; - d->hAlign = alignment; - d->updateDefaultTextOption(); - updateSize(); - emit horizontalAlignmentChanged(d->hAlign); + bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror; + d->hAlignImplicit = false; + if (d->setHAlign(align, forceAlign) && isComponentComplete()) { + d->updateDefaultTextOption(); + updateSize(); + } +} + +void QDeclarativeTextEdit::resetHAlign() +{ + Q_D(QDeclarativeTextEdit); + d->hAlignImplicit = true; + if (d->determineHorizontalAlignment() && isComponentComplete()) { + d->updateDefaultTextOption(); + updateSize(); + } +} + +QDeclarativeTextEdit::HAlignment QDeclarativeTextEdit::effectiveHAlign() const +{ + Q_D(const QDeclarativeTextEdit); + QDeclarativeTextEdit::HAlignment effectiveAlignment = d->hAlign; + if (!d->hAlignImplicit && d->effectiveLayoutMirror) { + switch (d->hAlign) { + case QDeclarativeTextEdit::AlignLeft: + effectiveAlignment = QDeclarativeTextEdit::AlignRight; + break; + case QDeclarativeTextEdit::AlignRight: + effectiveAlignment = QDeclarativeTextEdit::AlignLeft; + break; + default: + break; + } + } + return effectiveAlignment; +} + +bool QDeclarativeTextEditPrivate::setHAlign(QDeclarativeTextEdit::HAlignment alignment, bool forceAlign) +{ + Q_Q(QDeclarativeTextEdit); + if (hAlign != alignment || forceAlign) { + QDeclarativeTextEdit::HAlignment oldEffectiveHAlign = q->effectiveHAlign(); + hAlign = alignment; + emit q->horizontalAlignmentChanged(alignment); + if (oldEffectiveHAlign != q->effectiveHAlign()) + emit q->effectiveHorizontalAlignmentChanged(); + return true; + } + return false; +} + +bool QDeclarativeTextEditPrivate::determineHorizontalAlignment() +{ + Q_Q(QDeclarativeTextEdit); + if (hAlignImplicit && q->isComponentComplete()) { + bool alignToRight = text.isEmpty() ? QApplication::keyboardInputDirection() == Qt::RightToLeft : rightToLeftText; + return setHAlign(alignToRight ? QDeclarativeTextEdit::AlignRight : QDeclarativeTextEdit::AlignLeft); + } + return false; +} + +void QDeclarativeTextEditPrivate::mirrorChange() +{ + Q_Q(QDeclarativeTextEdit); + if (q->isComponentComplete()) { + if (!hAlignImplicit && (hAlign == QDeclarativeTextEdit::AlignRight || hAlign == QDeclarativeTextEdit::AlignLeft)) { + updateDefaultTextOption(); + q->updateSize(); + emit q->effectiveHorizontalAlignmentChanged(); + } + } } QDeclarativeTextEdit::VAlignment QDeclarativeTextEdit::vAlign() const @@ -507,6 +582,7 @@ void QDeclarativeTextEdit::setVAlign(QDeclarativeTextEdit::VAlignment alignment) d->vAlign = alignment; d->updateDefaultTextOption(); updateSize(); + moveCursorDelegate(); emit verticalAlignmentChanged(d->vAlign); } @@ -795,8 +871,6 @@ void QDeclarativeTextEdit::setCursorDelegate(QDeclarativeComponent* c) Q_D(QDeclarativeTextEdit); if(d->cursorComponent){ if(d->cursor){ - disconnect(d->control, SIGNAL(cursorPositionChanged()), - this, SLOT(moveCursorDelegate())); d->control->setCursorWidth(-1); dirtyCache(cursorRectangle()); delete d->cursor; @@ -822,8 +896,6 @@ void QDeclarativeTextEdit::loadCursorDelegate() return; d->cursor = qobject_cast<QDeclarativeItem*>(d->cursorComponent->create(qmlContext(this))); if(d->cursor){ - connect(d->control, SIGNAL(cursorPositionChanged()), - this, SLOT(moveCursorDelegate())); d->control->setCursorWidth(0); dirtyCache(cursorRectangle()); QDeclarative_setParent_noEvent(d->cursor, this); @@ -967,6 +1039,8 @@ void QDeclarativeTextEdit::componentComplete() Q_D(QDeclarativeTextEdit); QDeclarativePaintedItem::componentComplete(); if (d->dirty) { + d->determineHorizontalAlignment(); + d->updateDefaultTextOption(); updateSize(); d->dirty = false; } @@ -1096,7 +1170,7 @@ Qt::TextInteractionFlags QDeclarativeTextEdit::textInteractionFlags() const QRect QDeclarativeTextEdit::cursorRectangle() const { Q_D(const QDeclarativeTextEdit); - return d->control->cursorRect().toRect().translated(0,-d->yoff); + return d->control->cursorRect().toRect().translated(0,d->yoff); } @@ -1216,6 +1290,23 @@ void QDeclarativeTextEdit::select(int start, int end) updateSelectionMarkers(); } +/*! + \qmlmethod void TextEdit::isRightToLeft(int start, int end) + + Returns true if the natural reading direction of the editor text + found between positions \a start and \a end is right to left. +*/ +bool QDeclarativeTextEdit::isRightToLeft(int start, int end) +{ + Q_D(QDeclarativeTextEdit); + if (start > end) { + qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start."; + return false; + } else { + return d->text.mid(start, end - start).isRightToLeft(); + } +} + #ifndef QT_NO_CLIPBOARD /*! \qmlmethod TextEdit::cut() @@ -1414,7 +1505,7 @@ bool QDeclarativeTextEdit::canPaste() const } /*! - \qmlproperty bool TextEdit::isInputMethodComposing() + \qmlproperty bool TextEdit::inputMethodComposing \since QtQuick 1.1 @@ -1464,7 +1555,7 @@ void QDeclarativeTextEditPrivate::init() QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers())); QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers())); QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged())); - QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorRectangleChanged())); + QObject::connect(control, SIGNAL(microFocusChanged()), q, SLOT(moveCursorDelegate())); QObject::connect(control, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString))); #ifndef QT_NO_CLIPBOARD QObject::connect(q, SIGNAL(readOnlyChanged(bool)), q, SLOT(q_canPasteChanged())); @@ -1484,18 +1575,22 @@ void QDeclarativeTextEdit::q_textChanged() { Q_D(QDeclarativeTextEdit); d->text = text(); + d->rightToLeftText = d->document->begin().layout()->engine()->isRightToLeft(); + d->determineHorizontalAlignment(); + d->updateDefaultTextOption(); updateSize(); updateTotalLines(); - updateMicroFocus(); emit textChanged(d->text); } void QDeclarativeTextEdit::moveCursorDelegate() { Q_D(QDeclarativeTextEdit); + updateMicroFocus(); + emit cursorRectangleChanged(); if(!d->cursor) return; - QRectF cursorRect = d->control->cursorRect(); + QRectF cursorRect = cursorRectangle(); d->cursor->setX(cursorRect.x()); d->cursor->setY(cursorRect.y()); } @@ -1528,7 +1623,6 @@ void QDeclarativeTextEdit::updateSelectionMarkers() d->lastSelectionEnd = d->control->textCursor().selectionEnd(); emit selectionEndChanged(); } - updateMicroFocus(); } QRectF QDeclarativeTextEdit::boundingRect() const @@ -1648,9 +1742,18 @@ void QDeclarativeTextEdit::updateTotalLines() void QDeclarativeTextEditPrivate::updateDefaultTextOption() { + Q_Q(QDeclarativeTextEdit); QTextOption opt = document->defaultTextOption(); int oldAlignment = opt.alignment(); - opt.setAlignment((Qt::Alignment)(int)(hAlign | vAlign)); + + QDeclarativeTextEdit::HAlignment horizontalAlignment = q->effectiveHAlign(); + if (rightToLeftText) { + if (horizontalAlignment == QDeclarativeTextEdit::AlignLeft) + horizontalAlignment = QDeclarativeTextEdit::AlignRight; + else if (horizontalAlignment == QDeclarativeTextEdit::AlignRight) + horizontalAlignment = QDeclarativeTextEdit::AlignLeft; + } + opt.setAlignment((Qt::Alignment)(int)(horizontalAlignment | vAlign)); QTextOption::WrapMode oldWrapMode = opt.wrapMode(); opt.setWrapMode(QTextOption::WrapMode(wrapMode)); diff --git a/src/declarative/graphicsitems/qdeclarativetextedit_p.h b/src/declarative/graphicsitems/qdeclarativetextedit_p.h index 612f9a9..25ca1e7 100644 --- a/src/declarative/graphicsitems/qdeclarativetextedit_p.h +++ b/src/declarative/graphicsitems/qdeclarativetextedit_p.h @@ -72,7 +72,8 @@ class Q_AUTOTEST_EXPORT QDeclarativeTextEdit : public QDeclarativeImplicitSizePa Q_PROPERTY(QColor selectionColor READ selectionColor WRITE setSelectionColor NOTIFY selectionColorChanged) Q_PROPERTY(QColor selectedTextColor READ selectedTextColor WRITE setSelectedTextColor NOTIFY selectedTextColorChanged) Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged) - Q_PROPERTY(HAlignment horizontalAlignment READ hAlign WRITE setHAlign NOTIFY horizontalAlignmentChanged) + Q_PROPERTY(HAlignment horizontalAlignment READ hAlign WRITE setHAlign RESET resetHAlign NOTIFY horizontalAlignmentChanged) + Q_PROPERTY(HAlignment effectiveHorizontalAlignment READ effectiveHAlign NOTIFY effectiveHorizontalAlignmentChanged REVISION 1) Q_PROPERTY(VAlignment verticalAlignment READ vAlign WRITE setVAlign NOTIFY verticalAlignmentChanged) Q_PROPERTY(WrapMode wrapMode READ wrapMode WRITE setWrapMode NOTIFY wrapModeChanged) Q_PROPERTY(int lineCount READ lineCount NOTIFY lineCountChanged REVISION 1) @@ -153,6 +154,8 @@ public: HAlignment hAlign() const; void setHAlign(HAlignment align); + void resetHAlign(); + HAlignment effectiveHAlign() const; VAlignment vAlign() const; void setVAlign(VAlignment align); @@ -246,12 +249,14 @@ Q_SIGNALS: Q_REVISION(1) void linkActivated(const QString &link); Q_REVISION(1) void canPasteChanged(); Q_REVISION(1) void inputMethodComposingChanged(); + Q_REVISION(1) void effectiveHorizontalAlignmentChanged(); public Q_SLOTS: void selectAll(); void selectWord(); void select(int start, int end); Q_REVISION(1) void deselect(); + Q_REVISION(1) bool isRightToLeft(int start, int end); #ifndef QT_NO_CLIPBOARD void cut(); void copy(); diff --git a/src/declarative/graphicsitems/qdeclarativetextedit_p_p.h b/src/declarative/graphicsitems/qdeclarativetextedit_p_p.h index 111cc02..36e1b51 100644 --- a/src/declarative/graphicsitems/qdeclarativetextedit_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativetextedit_p_p.h @@ -71,8 +71,8 @@ public: : color("black"), hAlign(QDeclarativeTextEdit::AlignLeft), vAlign(QDeclarativeTextEdit::AlignTop), imgDirty(true), dirty(false), richText(false), cursorVisible(false), focusOnPress(true), showInputPanelOnFocus(true), clickCausedFocus(false), persistentSelection(true), requireImplicitWidth(false), - textMargin(0.0), lastSelectionStart(0), lastSelectionEnd(0), cursorComponent(0), cursor(0), - format(QDeclarativeTextEdit::AutoText), document(0), wrapMode(QDeclarativeTextEdit::NoWrap), + hAlignImplicit(true), rightToLeftText(false), textMargin(0.0), lastSelectionStart(0), lastSelectionEnd(0), + cursorComponent(0), cursor(0), format(QDeclarativeTextEdit::AutoText), document(0), wrapMode(QDeclarativeTextEdit::NoWrap), mouseSelectionMode(QDeclarativeTextEdit::SelectCharacters), selectByMouse(false), canPaste(false), yoff(0) { @@ -88,6 +88,9 @@ public: void updateDefaultTextOption(); void relayoutDocument(); void updateSelection(); + bool determineHorizontalAlignment(); + bool setHAlign(QDeclarativeTextEdit::HAlignment, bool forceAlign = false); + void mirrorChange(); qreal implicitWidth() const; void focusChanged(bool); @@ -112,6 +115,8 @@ public: bool clickCausedFocus : 1; bool persistentSelection : 1; bool requireImplicitWidth:1; + bool hAlignImplicit:1; + bool rightToLeftText:1; qreal textMargin; int lastSelectionStart; int lastSelectionEnd; diff --git a/src/declarative/graphicsitems/qdeclarativetextinput.cpp b/src/declarative/graphicsitems/qdeclarativetextinput.cpp index 29b1f6b..e1c2107 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextinput.cpp @@ -326,9 +326,12 @@ void QDeclarativeTextInput::setSelectedTextColor(const QColor &color) /*! \qmlproperty enumeration TextInput::horizontalAlignment + \qmlproperty enumeration TextInput::effectiveHorizontalAlignment Sets the horizontal alignment of the text within the TextInput item's - width and height. By default, the text is left aligned. + width and height. By default, the text alignment follows the natural alignment + of the text, for example text that is read from left to right will be aligned to + the left. TextInput does not have vertical alignment, as the natural height is exactly the height of the single line of text. If you set the height @@ -338,6 +341,11 @@ void QDeclarativeTextInput::setSelectedTextColor(const QColor &color) The valid values for \c horizontalAlignment are \c TextInput.AlignLeft, \c TextInput.AlignRight and \c TextInput.AlignHCenter. + + When using the attached property LayoutMirroring::enabled to mirror application + layouts, the horizontal alignment of text will also be mirrored. However, the property + \c horizontalAlignment will remain unchanged. To query the effective horizontal alignment + of TextInput, use the read-only property \c effectiveHorizontalAlignment. */ QDeclarativeTextInput::HAlignment QDeclarativeTextInput::hAlign() const { @@ -348,12 +356,78 @@ QDeclarativeTextInput::HAlignment QDeclarativeTextInput::hAlign() const void QDeclarativeTextInput::setHAlign(HAlignment align) { Q_D(QDeclarativeTextInput); - if(align == d->hAlign) - return; - d->hAlign = align; - updateRect(); - d->updateHorizontalScroll(); - emit horizontalAlignmentChanged(d->hAlign); + bool forceAlign = d->hAlignImplicit && d->effectiveLayoutMirror; + d->hAlignImplicit = false; + if (d->setHAlign(align, forceAlign) && isComponentComplete()) { + updateRect(); + d->updateHorizontalScroll(); + } +} + +void QDeclarativeTextInput::resetHAlign() +{ + Q_D(QDeclarativeTextInput); + d->hAlignImplicit = true; + if (d->determineHorizontalAlignment() && isComponentComplete()) { + updateRect(); + d->updateHorizontalScroll(); + } +} + +QDeclarativeTextInput::HAlignment QDeclarativeTextInput::effectiveHAlign() const +{ + Q_D(const QDeclarativeTextInput); + QDeclarativeTextInput::HAlignment effectiveAlignment = d->hAlign; + if (!d->hAlignImplicit && d->effectiveLayoutMirror) { + switch (d->hAlign) { + case QDeclarativeTextInput::AlignLeft: + effectiveAlignment = QDeclarativeTextInput::AlignRight; + break; + case QDeclarativeTextInput::AlignRight: + effectiveAlignment = QDeclarativeTextInput::AlignLeft; + break; + default: + break; + } + } + return effectiveAlignment; +} + +bool QDeclarativeTextInputPrivate::setHAlign(QDeclarativeTextInput::HAlignment alignment, bool forceAlign) +{ + Q_Q(QDeclarativeTextInput); + if ((hAlign != alignment || forceAlign) && alignment <= QDeclarativeTextInput::AlignHCenter) { // justify not supported + QDeclarativeTextInput::HAlignment oldEffectiveHAlign = q->effectiveHAlign(); + hAlign = alignment; + emit q->horizontalAlignmentChanged(alignment); + if (oldEffectiveHAlign != q->effectiveHAlign()) + emit q->effectiveHorizontalAlignmentChanged(); + return true; + } + return false; +} + +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(); + return setHAlign(isRightToLeft ? QDeclarativeTextInput::AlignRight : QDeclarativeTextInput::AlignLeft); + } + return false; +} + +void QDeclarativeTextInputPrivate::mirrorChange() +{ + Q_Q(QDeclarativeTextInput); + if (q->isComponentComplete()) { + if (!hAlignImplicit && (hAlign == QDeclarativeTextInput::AlignRight || hAlign == QDeclarativeTextInput::AlignLeft)) { + q->updateRect(); + updateHorizontalScroll(); + emit q->effectiveHorizontalAlignmentChanged(); + } + } } /*! @@ -481,8 +555,10 @@ QRect QDeclarativeTextInput::cursorRectangle() const { Q_D(const QDeclarativeTextInput); QRect r = d->control->cursorRect(); - r.setHeight(r.height()-1); // Make consistent with TextEdit (QLineControl inexplicably adds 1) - r.moveLeft(r.x() - d->hscroll); + // Scroll and make consistent with TextEdit + // QLineControl inexplicably adds 1 to the height and horizontal padding + // for unicode direction markers. + r.adjust(5 - d->hscroll, 0, -4 - d->hscroll, -1); return r; } @@ -986,16 +1062,21 @@ void QDeclarativeTextInput::keyPressEvent(QKeyEvent* ev) keyPressPreHandler(ev); if (ev->isAccepted()) return; - if (((ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier) // Don't allow MacOSX up/down support, and we don't allow a completer. - || (((d->control->cursor() == 0 && ev->key() == Qt::Key_Left) - || (d->control->cursor() == d->control->text().length() - && ev->key() == Qt::Key_Right)) - && (d->lastSelectionStart == d->lastSelectionEnd))) - { - //ignore when moving off the end - //unless there is a selection, because then moving will do something (deselect) + + // Don't allow MacOSX up/down support, and we don't allow a completer. + bool ignore = (ev->key() == Qt::Key_Up || ev->key() == Qt::Key_Down) && ev->modifiers() == Qt::NoModifier; + if (!ignore && (d->lastSelectionStart == d->lastSelectionEnd) && (ev->key() == Qt::Key_Right || ev->key() == Qt::Key_Left)) { + // Ignore when moving off the end unless there is a selection, + // because then moving will do something (deselect). + int cursorPosition = d->control->cursor(); + if (cursorPosition == 0) + ignore = ev->key() == (d->control->layoutDirection() == Qt::LeftToRight ? Qt::Key_Left : Qt::Key_Right); + if (cursorPosition == d->control->text().length()) + ignore = ev->key() == (d->control->layoutDirection() == Qt::LeftToRight ? Qt::Key_Right : Qt::Key_Left); + } + if (ignore) { ev->ignore(); - }else{ + } else { d->control->processKeyEvent(ev); } if (!ev->isAccepted()) @@ -1204,11 +1285,12 @@ void QDeclarativeTextInputPrivate::updateHorizontalScroll() int cix = qRound(control->cursorToX(control->cursor() + preeditLength)); QRect br(q->boundingRect().toRect()); int widthUsed = calculateTextWidth(); - Qt::Alignment va = QStyle::visualAlignment(control->layoutDirection(), QFlag(Qt::Alignment(hAlign))); + + QDeclarativeTextInput::HAlignment effectiveHAlign = q->effectiveHAlign(); if (autoScroll) { if (widthUsed <= br.width()) { // text fits in br; use hscroll for alignment - switch (va & ~(Qt::AlignAbsolute|Qt::AlignVertical_Mask)) { + switch (effectiveHAlign & ~(Qt::AlignAbsolute|Qt::AlignVertical_Mask)) { case Qt::AlignRight: hscroll = widthUsed - br.width() - 1; break; @@ -1240,11 +1322,11 @@ void QDeclarativeTextInputPrivate::updateHorizontalScroll() hscroll = cix; } } else { - switch (va & ~(Qt::AlignAbsolute|Qt::AlignVertical_Mask)) { - case Qt::AlignRight: + switch (effectiveHAlign) { + case QDeclarativeTextInput::AlignRight: hscroll = q->width() - widthUsed; break; - case Qt::AlignHCenter: + case QDeclarativeTextInput::AlignHCenter: hscroll = (q->width() - widthUsed) / 2; break; default: @@ -1294,7 +1376,10 @@ QVariant QDeclarativeTextInput::inputMethodQuery(Qt::InputMethodQuery property) case Qt::ImCursorPosition: return QVariant(d->control->cursor()); case Qt::ImSurroundingText: - return QVariant(text()); + if (d->control->echoMode() == PasswordEchoOnEdit && !d->control->passwordEchoEditing()) + return QVariant(displayText()); + else + return QVariant(text()); case Qt::ImCurrentSelection: return QVariant(selectedText()); case Qt::ImMaximumTextLength: @@ -1334,6 +1419,23 @@ void QDeclarativeTextInput::selectAll() d->control->setSelection(0, d->control->text().length()); } +/*! + \qmlmethod void TextInput::isRightToLeft(int start, int end) + + Returns true if the natural reading direction of the editor text + found between positions \a start and \a end is right to left. +*/ +bool QDeclarativeTextInput::isRightToLeft(int start, int end) +{ + Q_D(QDeclarativeTextInput); + if (start > end) { + qmlInfo(this) << "isRightToLeft(start, end) called with the end property being smaller than the start."; + return false; + } else { + return d->control->text().mid(start, end - start).isRightToLeft(); + } +} + #ifndef QT_NO_CLIPBOARD /*! \qmlmethod TextInput::cut() @@ -1575,8 +1677,8 @@ void QDeclarativeTextInput::moveCursorSelection(int pos, SelectionMode mode) finder.setPosition(anchor); const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons(); - if (anchor < text.length() && !(reasons & QTextBoundaryFinder::StartWord) - || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor)) { + if (anchor < text.length() && (!(reasons & QTextBoundaryFinder::StartWord) + || ((reasons & QTextBoundaryFinder::EndWord) && anchor > cursor))) { finder.toPreviousBoundary(); } anchor = finder.position() != -1 ? finder.position() : 0; @@ -1593,8 +1695,8 @@ void QDeclarativeTextInput::moveCursorSelection(int pos, SelectionMode mode) finder.setPosition(anchor); const QTextBoundaryFinder::BoundaryReasons reasons = finder.boundaryReasons(); - if (anchor > 0 && !(reasons & QTextBoundaryFinder::EndWord) - || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor)) { + if (anchor > 0 && (!(reasons & QTextBoundaryFinder::EndWord) + || ((reasons & QTextBoundaryFinder::StartWord) && anchor < cursor))) { finder.toNextBoundary(); } anchor = finder.position() != -1 ? finder.position() : text.length(); @@ -1724,7 +1826,7 @@ void QDeclarativeTextInput::focusInEvent(QFocusEvent *event) } /*! - \qmlproperty bool TextInput::isInputMethodComposing() + \qmlproperty bool TextInput::inputMethodComposing \since QtQuick 1.1 @@ -1770,6 +1872,8 @@ void QDeclarativeTextInputPrivate::init() #endif // QT_NO_CLIPBOARD q->connect(control, SIGNAL(updateMicroFocus()), q, SLOT(updateMicroFocus())); + q->connect(control, SIGNAL(displayTextChanged(QString)), + q, SLOT(updateRect())); q->updateSize(); oldValidity = control->hasAcceptableInput(); lastSelectionStart = 0; @@ -1777,6 +1881,7 @@ void QDeclarativeTextInputPrivate::init() QPalette p = control->palette(); selectedTextColor = p.color(QPalette::HighlightedText); selectionColor = p.color(QPalette::Highlight); + determineHorizontalAlignment(); } void QDeclarativeTextInput::cursorPosChanged() @@ -1824,6 +1929,7 @@ void QDeclarativeTextInput::q_textChanged() { Q_D(QDeclarativeTextInput); updateSize(); + d->determineHorizontalAlignment(); d->updateHorizontalScroll(); updateMicroFocus(); emit textChanged(); diff --git a/src/declarative/graphicsitems/qdeclarativetextinput_p.h b/src/declarative/graphicsitems/qdeclarativetextinput_p.h index 822d5e2..8c873b3 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput_p.h +++ b/src/declarative/graphicsitems/qdeclarativetextinput_p.h @@ -70,8 +70,8 @@ class Q_AUTOTEST_EXPORT QDeclarativeTextInput : public QDeclarativeImplicitSizeP Q_PROPERTY(QColor selectionColor READ selectionColor WRITE setSelectionColor NOTIFY selectionColorChanged) Q_PROPERTY(QColor selectedTextColor READ selectedTextColor WRITE setSelectedTextColor NOTIFY selectedTextColorChanged) Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged) - Q_PROPERTY(HAlignment horizontalAlignment READ hAlign WRITE setHAlign NOTIFY horizontalAlignmentChanged) - + Q_PROPERTY(HAlignment horizontalAlignment READ hAlign WRITE setHAlign RESET resetHAlign NOTIFY horizontalAlignmentChanged) + Q_PROPERTY(HAlignment effectiveHorizontalAlignment READ effectiveHAlign NOTIFY effectiveHorizontalAlignmentChanged REVISION 1) Q_PROPERTY(bool readOnly READ isReadOnly WRITE setReadOnly NOTIFY readOnlyChanged) Q_PROPERTY(bool cursorVisible READ isCursorVisible WRITE setCursorVisible NOTIFY cursorVisibleChanged) Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorPositionChanged) @@ -153,6 +153,8 @@ public: HAlignment hAlign() const; void setHAlign(HAlignment align); + void resetHAlign(); + HAlignment effectiveHAlign() const; bool isReadOnly() const; void setReadOnly(bool); @@ -241,6 +243,7 @@ Q_SIGNALS: Q_REVISION(1) void mouseSelectionModeChanged(SelectionMode mode); Q_REVISION(1) void canPasteChanged(); Q_REVISION(1) void inputMethodComposingChanged(); + Q_REVISION(1) void effectiveHorizontalAlignmentChanged(); protected: virtual void geometryChanged(const QRectF &newGeometry, @@ -261,6 +264,7 @@ public Q_SLOTS: void selectWord(); void select(int start, int end); Q_REVISION(1) void deselect(); + Q_REVISION(1) bool isRightToLeft(int start, int end); #ifndef QT_NO_CLIPBOARD void cut(); void copy(); diff --git a/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h b/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h index ab2838b..fd4da2e 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h @@ -74,9 +74,9 @@ public: color((QRgb)0), style(QDeclarativeText::Normal), styleColor((QRgb)0), hAlign(QDeclarativeTextInput::AlignLeft), mouseSelectionMode(QDeclarativeTextInput::SelectCharacters), - hscroll(0), oldScroll(0), focused(false), focusOnPress(true), + hscroll(0), oldScroll(0), oldValidity(false), focused(false), focusOnPress(true), showInputPanelOnFocus(true), clickCausedFocus(false), cursorVisible(false), - autoScroll(true), selectByMouse(false), canPaste(false) + autoScroll(true), selectByMouse(false), canPaste(false), hAlignImplicit(true) { #ifdef Q_OS_SYMBIAN if (QSysInfo::symbianVersion() == QSysInfo::SV_SF_1 || QSysInfo::symbianVersion() == QSysInfo::SV_SF_3) { @@ -103,6 +103,9 @@ public: void startCreatingCursor(); void focusChanged(bool hasFocus); void updateHorizontalScroll(); + bool determineHorizontalAlignment(); + bool setHAlign(QDeclarativeTextInput::HAlignment, bool forceAlign = false); + void mirrorChange(); int calculateTextWidth(); bool sendMouseEventToInputContext(QGraphicsSceneMouseEvent *event, QEvent::Type eventType); @@ -125,17 +128,18 @@ public: int lastSelectionEnd; int oldHeight; int oldWidth; - bool oldValidity; int hscroll; int oldScroll; - bool focused; - bool focusOnPress; - bool showInputPanelOnFocus; - bool clickCausedFocus; - bool cursorVisible; - bool autoScroll; - bool selectByMouse; - bool canPaste; + bool oldValidity:1; + bool focused:1; + bool focusOnPress:1; + bool showInputPanelOnFocus:1; + bool clickCausedFocus:1; + bool cursorVisible:1; + bool autoScroll:1; + bool selectByMouse:1; + bool canPaste:1; + bool hAlignImplicit:1; static inline QDeclarativeTextInputPrivate *get(QDeclarativeTextInput *t) { return t->d_func(); diff --git a/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp b/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp index a8082f8..97ce059 100644 --- a/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp +++ b/src/declarative/graphicsitems/qdeclarativevisualitemmodel.cpp @@ -839,7 +839,8 @@ void QDeclarativeVisualDataModel::setDelegate(QDeclarativeComponent *delegate) QML only operates on list data. \c rootIndex allows the children of any node in a QAbstractItemModel to be provided by this model. - This property only affects models of type QAbstractItemModel. + This property only affects models of type QAbstractItemModel that + are hierarchical (e.g, a tree model). For example, here is a simple interactive file system browser. When a directory name is clicked, the view's \c rootIndex is set to the diff --git a/src/declarative/qml/qdeclarativeboundsignal.cpp b/src/declarative/qml/qdeclarativeboundsignal.cpp index 28dfea9..47a15cb 100644 --- a/src/declarative/qml/qdeclarativeboundsignal.cpp +++ b/src/declarative/qml/qdeclarativeboundsignal.cpp @@ -225,9 +225,35 @@ QDeclarativeBoundSignalParameters::QDeclarativeBoundSignalParameters(const QMeta QMetaPropertyBuilder prop = mob.addProperty(name, "QObject*"); prop.setWritable(false); } else { + QByteArray propType = type; + if (t >= QVariant::UserType || t == QVariant::Invalid) { + //copy of QDeclarativeObjectScriptClass::enumType() + QByteArray scope; + QByteArray name; + int scopeIdx = propType.lastIndexOf("::"); + if (scopeIdx != -1) { + scope = propType.left(scopeIdx); + name = propType.mid(scopeIdx + 2); + } else { + name = propType; + } + const QMetaObject *meta; + if (scope == "Qt") + meta = &QObject::staticQtMetaObject; + else + meta = parent->parent()->metaObject(); //### assumes parent->parent() + for (int i = meta->enumeratorCount() - 1; i >= 0; --i) { + QMetaEnum m = meta->enumerator(i); + if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope))) { + t = QVariant::Int; + propType = "int"; + break; + } + } + } if (QDeclarativeMetaType::canCopy(t)) { types[ii] = t; - QMetaPropertyBuilder prop = mob.addProperty(name, type); + QMetaPropertyBuilder prop = mob.addProperty(name, propType); prop.setWritable(false); } else { types[ii] = 0x80000000 | t; diff --git a/src/declarative/qml/qdeclarativecomponent.cpp b/src/declarative/qml/qdeclarativecomponent.cpp index fc393d1..8238252 100644 --- a/src/declarative/qml/qdeclarativecomponent.cpp +++ b/src/declarative/qml/qdeclarativecomponent.cpp @@ -137,7 +137,7 @@ class QByteArray; } \endcode - \sa {Using QML in C++ Applications}, {Integrating QML with existing Qt UI code} + \sa {Using QML Bindings in C++ Applications}, {Integrating QML Code with Existing Qt UI Code} */ /*! @@ -643,11 +643,11 @@ QDeclarativeComponent::QDeclarativeComponent(QDeclarativeComponentPrivate &dd, Q The \a properties argument is specified as a map of property-value items. For example, the code below creates an object with initial \c x and \c y values of 100 and 200, respectively: - \qml + \js var component = Qt.createComponent("Button.qml"); if (component.status == Component.Ready) component.createObject(parent, {"x": 100, "y": 100}); - \endqml + \endjs Dynamically created instances can be deleted with the \c destroy() method. See \l {Dynamic Object Management in QML} for more information. @@ -880,6 +880,7 @@ QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentCon state->bindValues = enginePriv->bindValues; state->parserStatus = enginePriv->parserStatus; + state->finalizedParserStatus = enginePriv->finalizedParserStatus; state->componentAttached = enginePriv->componentAttached; if (state->componentAttached) state->componentAttached->prev = &state->componentAttached; @@ -887,6 +888,7 @@ QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentCon enginePriv->componentAttached = 0; enginePriv->bindValues.clear(); enginePriv->parserStatus.clear(); + enginePriv->finalizedParserStatus.clear(); state->completePending = true; enginePriv->inProgressCreations++; } @@ -917,6 +919,7 @@ void QDeclarativeComponentPrivate::beginDeferred(QDeclarativeEnginePrivate *engi state->bindValues = enginePriv->bindValues; state->parserStatus = enginePriv->parserStatus; + state->finalizedParserStatus = enginePriv->finalizedParserStatus; state->componentAttached = enginePriv->componentAttached; if (state->componentAttached) state->componentAttached->prev = &state->componentAttached; @@ -924,6 +927,7 @@ void QDeclarativeComponentPrivate::beginDeferred(QDeclarativeEnginePrivate *engi enginePriv->componentAttached = 0; enginePriv->bindValues.clear(); enginePriv->parserStatus.clear(); + enginePriv->finalizedParserStatus.clear(); state->completePending = true; enginePriv->inProgressCreations++; } @@ -961,6 +965,18 @@ void QDeclarativeComponentPrivate::complete(QDeclarativeEnginePrivate *enginePri QDeclarativeEnginePrivate::clear(ps); } + for (int ii = 0; ii < state->finalizedParserStatus.count(); ++ii) { + QPair<QDeclarativeGuard<QObject>, int> status = state->finalizedParserStatus.at(ii); + QObject *obj = status.first; + if (obj) { + void *args[] = { 0 }; + QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, + status.second, args); + } + } + + //componentComplete() can register additional finalization objects + //that are then never handled. Handle them manually here. if (1 == enginePriv->inProgressCreations) { for (int ii = 0; ii < enginePriv->finalizedParserStatus.count(); ++ii) { QPair<QDeclarativeGuard<QObject>, int> status = enginePriv->finalizedParserStatus.at(ii); @@ -986,6 +1002,7 @@ void QDeclarativeComponentPrivate::complete(QDeclarativeEnginePrivate *enginePri state->bindValues.clear(); state->parserStatus.clear(); + state->finalizedParserStatus.clear(); state->completePending = false; enginePriv->inProgressCreations--; diff --git a/src/declarative/qml/qdeclarativecomponent_p.h b/src/declarative/qml/qdeclarativecomponent_p.h index 020c5e0..f8bec2b 100644 --- a/src/declarative/qml/qdeclarativecomponent_p.h +++ b/src/declarative/qml/qdeclarativecomponent_p.h @@ -101,6 +101,7 @@ public: ConstructionState() : componentAttached(0), completePending(false) {} QList<QDeclarativeEnginePrivate::SimpleList<QDeclarativeAbstractBinding> > bindValues; QList<QDeclarativeEnginePrivate::SimpleList<QDeclarativeParserStatus> > parserStatus; + QList<QPair<QDeclarativeGuard<QObject>, int> > finalizedParserStatus; QDeclarativeComponentAttached *componentAttached; QList<QDeclarativeError> errors; bool completePending; diff --git a/src/declarative/qml/qdeclarativecontext.cpp b/src/declarative/qml/qdeclarativecontext.cpp index dc6b085..7637b72 100644 --- a/src/declarative/qml/qdeclarativecontext.cpp +++ b/src/declarative/qml/qdeclarativecontext.cpp @@ -72,10 +72,10 @@ QDeclarativeContextPrivate::QDeclarativeContextPrivate() Contexts allow data to be exposed to the QML components instantiated by the QML engine. - Each QDeclarativeContext contains a set of properties, distinct from its QObject - properties, that allow data to be explicitly bound to a context by name. The - context properties are defined and updated by calling - QDeclarativeContext::setContextProperty(). The following example shows a Qt model + Each QDeclarativeContext contains a set of properties, distinct from its QObject + properties, that allow data to be explicitly bound to a context by name. The + context properties are defined and updated by calling + QDeclarativeContext::setContextProperty(). The following example shows a Qt model being bound to a context and then accessed from a QML file. \code @@ -97,8 +97,8 @@ QDeclarativeContextPrivate::QDeclarativeContextPrivate() To simplify binding and maintaining larger data sets, a context object can be set on a QDeclarativeContext. All the properties of the context object are available by name in the context, as though they were all individually added through calls - to QDeclarativeContext::setContextProperty(). Changes to the property's values are - detected through the property's notify signal. Setting a context object is both + to QDeclarativeContext::setContextProperty(). Changes to the property's values are + detected through the property's notify signal. Setting a context object is both faster and easier than manually adding and maintaing context property values. The following example has the same effect as the previous one, but it uses a context @@ -121,7 +121,7 @@ QDeclarativeContextPrivate::QDeclarativeContextPrivate() component.create(context); \endcode - All properties added explicitly by QDeclarativeContext::setContextProperty() take + All properties added explicitly by QDeclarativeContext::setContextProperty() take precedence over the context object's properties. \section2 The Context Hierarchy @@ -147,8 +147,8 @@ QDeclarativeContextPrivate::QDeclarativeContextPrivate() context2->setContextProperty("b", 15); \endcode - While QML objects instantiated in a context are not strictly owned by that - context, their bindings are. If a context is destroyed, the property bindings of + While QML objects instantiated in a context are not strictly owned by that + context, their bindings are. If a context is destroyed, the property bindings of outstanding QML objects will stop evaluating. \warning Setting the context object or adding new context properties after an object @@ -156,7 +156,7 @@ QDeclarativeContextPrivate::QDeclarativeContextPrivate() to reevaluate). Thus whenever possible you should complete "setup" of the context before using it to create any objects. - \sa {Using QML in C++ Applications} + \sa {Using QML Bindings in C++ Applications} */ /*! \internal */ @@ -223,7 +223,7 @@ QDeclarativeContext::~QDeclarativeContext() /*! Returns whether the context is valid. - To be valid, a context must have a engine, and it's contextObject(), if any, + To be valid, a context must have a engine, and it's contextObject(), if any, must not have been deleted. */ bool QDeclarativeContext::isValid() const @@ -384,7 +384,7 @@ QVariant QDeclarativeContext::contextProperty(const QString &name) const if (data->contextObject) { QObject *obj = data->contextObject; QDeclarativePropertyCache::Data local; - QDeclarativePropertyCache::Data *property = + QDeclarativePropertyCache::Data *property = QDeclarativePropertyCache::property(data->engine, obj, name, local); if (property) value = obj->metaObject()->property(property->coreIndex).read(obj); @@ -461,7 +461,7 @@ QUrl QDeclarativeContext::baseUrl() const { Q_D(const QDeclarativeContext); const QDeclarativeContextData* data = d->data; - while (data && data->url.isEmpty()) + while (data && data->url.isEmpty()) data = data->parent; if (data) @@ -515,7 +515,7 @@ QDeclarativeContextData::QDeclarativeContextData(QDeclarativeContext *ctxt) void QDeclarativeContextData::invalidate() { - while (childContexts) + while (childContexts) childContexts->invalidate(); while (componentAttached) { @@ -570,7 +570,7 @@ void QDeclarativeContextData::clearContext() void QDeclarativeContextData::destroy() { - if (linkedContext) + if (linkedContext) linkedContext->destroy(); if (engine) invalidate(); @@ -626,9 +626,9 @@ void QDeclarativeContextData::setParent(QDeclarativeContextData *p) } } -/* -Refreshes all expressions that could possibly depend on this context. Refreshing flushes all -context-tree dependent caches in the expressions, and should occur every time the context tree +/* +Refreshes all expressions that could possibly depend on this context. Refreshing flushes all +context-tree dependent caches in the expressions, and should occur every time the context tree *structure* (not values) changes. */ void QDeclarativeContextData::refreshExpressions() @@ -656,7 +656,7 @@ void QDeclarativeContextData::addObject(QObject *o) data->outerContext = this; data->nextContextObject = contextObjects; - if (data->nextContextObject) + if (data->nextContextObject) data->nextContextObject->prevContextObject = &data->nextContextObject; data->prevContextObject = &contextObjects; contextObjects = data; @@ -664,7 +664,7 @@ void QDeclarativeContextData::addObject(QObject *o) void QDeclarativeContextData::addImportedScript(const QDeclarativeParser::Object::ScriptBlock &script) { - if (!engine) + if (!engine) return; QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine); @@ -684,7 +684,7 @@ void QDeclarativeContextData::addImportedScript(const QDeclarativeParser::Object scriptContext->pushScope(enginePriv->contextClass->newUrlContext(url)); scriptContext->pushScope(enginePriv->globalClass->staticGlobalObject()); - + QScriptValue scope = QScriptDeclarativeClass::newStaticScopeObject(scriptEngine); scriptContext->pushScope(scope); @@ -752,7 +752,7 @@ QString QDeclarativeContextData::findObjectId(const QObject *obj) const for (int i=0; i<idValueCount; i++) { if (idValues[i] == obj) return propertyNames->findId(i); - } + } if (linkedContext) return linkedContext->findObjectId(obj); @@ -761,7 +761,7 @@ QString QDeclarativeContextData::findObjectId(const QObject *obj) const QDeclarativeContext *QDeclarativeContextData::asQDeclarativeContext() { - if (!publicContext) + if (!publicContext) publicContext = new QDeclarativeContext(this); return publicContext; } diff --git a/src/declarative/qml/qdeclarativecontextscriptclass.cpp b/src/declarative/qml/qdeclarativecontextscriptclass.cpp index bb4ece4..3abd787 100644 --- a/src/declarative/qml/qdeclarativecontextscriptclass.cpp +++ b/src/declarative/qml/qdeclarativecontextscriptclass.cpp @@ -227,6 +227,7 @@ QDeclarativeContextScriptClass::queryProperty(QDeclarativeContextData *bindConte if (data) { lastData = data; lastContext = bindContext; + lastScopeObject = scopeObject; return QScriptClass::HandlesReadAccess; } } @@ -268,17 +269,12 @@ QDeclarativeContextScriptClass::property(Object *object, const Identifier &name) QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); - if (lastScopeObject) { - - return ep->objectClass->property(lastScopeObject, name); - - } else if (lastData) { + if (lastData) { if (lastData->type) { - return Value(scriptEngine, ep->typeNameClass->newObject(bindContext->contextObject, lastData->type)); + return Value(scriptEngine, ep->typeNameClass->newObject(lastScopeObject, lastData->type)); } else if (lastData->typeNamespace) { - return Value(scriptEngine, ep->typeNameClass->newObject(bindContext->contextObject, - lastData->typeNamespace)); + return Value(scriptEngine, ep->typeNameClass->newObject(lastScopeObject, lastData->typeNamespace)); } else { int index = lastData->importedScriptIndex; if (index < bindContext->importedScripts.count()) { @@ -288,6 +284,10 @@ QDeclarativeContextScriptClass::property(Object *object, const Identifier &name) } } + } else if (lastScopeObject) { + + return ep->objectClass->property(lastScopeObject, name); + } else if (lastPropertyIndex != -1) { QScriptValue rv; diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp index 854d910..824aeab 100644 --- a/src/declarative/qml/qdeclarativeengine.cpp +++ b/src/declarative/qml/qdeclarativeengine.cpp @@ -2117,7 +2117,7 @@ QVariant QDeclarativeEnginePrivate::scriptValueToVariant(const QScriptValue &val The newly added \a path will be first in the importPathList(). - \sa setImportPathList(), \l {QML Modules} + \sa setImportPathList(), {QML Modules} */ void QDeclarativeEngine::addImportPath(const QString& path) { diff --git a/src/declarative/qml/qdeclarativescriptparser.cpp b/src/declarative/qml/qdeclarativescriptparser.cpp index 996920a..d9e3ebf 100644 --- a/src/declarative/qml/qdeclarativescriptparser.cpp +++ b/src/declarative/qml/qdeclarativescriptparser.cpp @@ -776,7 +776,10 @@ bool ProcessAST::visit(AST::UiSourceElement *node) f = f->finish(); } - QString body = textAt(funDecl->lbraceToken, funDecl->rbraceToken); + AST::SourceLocation loc = funDecl->rparenToken; + loc.offset = loc.end(); + loc.startColumn += 1; + QString body = textAt(loc, funDecl->rbraceToken); slot.name = funDecl->name->asString().toUtf8(); slot.body = body; obj->dynamicSlots << slot; @@ -937,7 +940,7 @@ QDeclarativeParser::Object::ScriptBlock::Pragmas QDeclarativeScriptParser::extra if (l.currentLineNo() == startLine) return rv; - if (pragmaValue == QLatin1String("library")) { + if (pragmaValue == library) { rv |= QDeclarativeParser::Object::ScriptBlock::Shared; replaceWithSpace(script, startOffset, endOffset - startOffset); } else { diff --git a/src/declarative/qml/qdeclarativetypeloader.cpp b/src/declarative/qml/qdeclarativetypeloader.cpp index 36cdde9..26f3996 100644 --- a/src/declarative/qml/qdeclarativetypeloader.cpp +++ b/src/declarative/qml/qdeclarativetypeloader.cpp @@ -629,7 +629,18 @@ QDeclarativeTypeLoader::~QDeclarativeTypeLoader() } /*! -Return a QDeclarativeTypeData for \a url. The QDeclarativeTypeData may be cached. +\enum QDeclarativeTypeLoader::Option + +This enum defines the options that control the way type data is handled. + +\value None The default value, indicating that no other options + are enabled. +\value PreserveParser The parser used to handle the type data is preserved + after the data has been parsed. +*/ + +/*! +Returns a QDeclarativeTypeData for the specified \a url. The QDeclarativeTypeData may be cached. */ QDeclarativeTypeData *QDeclarativeTypeLoader::get(const QUrl &url) { @@ -650,8 +661,10 @@ QDeclarativeTypeData *QDeclarativeTypeLoader::get(const QUrl &url) } /*! -Return a QDeclarativeTypeData for \a data with the provided base \a url. The +Returns a QDeclarativeTypeData for the given \a data with the provided base \a url. The QDeclarativeTypeData will not be cached. + +The specified \a options control how the loader handles type data. */ QDeclarativeTypeData *QDeclarativeTypeLoader::get(const QByteArray &data, const QUrl &url, Options options) { diff --git a/src/declarative/qml/qdeclarativetypeloader_p.h b/src/declarative/qml/qdeclarativetypeloader_p.h index 6938892..7f487a0 100644 --- a/src/declarative/qml/qdeclarativetypeloader_p.h +++ b/src/declarative/qml/qdeclarativetypeloader_p.h @@ -79,7 +79,7 @@ public: Loading, // Prior to data being received and dataReceived() being called WaitingForDependencies, // While there are outstanding addDependency()s Complete, // Finished - Error, // Error + Error // Error }; enum Type { diff --git a/src/declarative/qml/qdeclarativetypenamescriptclass.cpp b/src/declarative/qml/qdeclarativetypenamescriptclass.cpp index d3e2025..0314a7a 100644 --- a/src/declarative/qml/qdeclarativetypenamescriptclass.cpp +++ b/src/declarative/qml/qdeclarativetypenamescriptclass.cpp @@ -158,7 +158,7 @@ void QDeclarativeTypeNameScriptClass::setProperty(Object *o, const Identifier &n Q_ASSERT(!type); QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); - ep->objectClass->setProperty(((TypeNameData *)o)->object, n, v, context()); + ep->objectClass->setProperty(object, n, v, context()); } QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp index 2d551f2..781e1b8 100644 --- a/src/declarative/qml/qdeclarativevme.cpp +++ b/src/declarative/qml/qdeclarativevme.cpp @@ -127,6 +127,22 @@ void QDeclarativeVME::runDeferred(QObject *object) run(stack, ctxt, comp, start, count, QBitField()); } +inline bool fastHasBinding(QObject *o, int index) +{ + QDeclarativeData *ddata = static_cast<QDeclarativeData *>(QObjectPrivate::get(o)->declarativeData); + + return ddata && (ddata->bindingBitsSize > index) && + (ddata->bindingBits[index / 32] & (1 << (index % 32))); +} + +static void removeBindingOnProperty(QObject *o, int index) +{ + QDeclarativeAbstractBinding *binding = QDeclarativePropertyPrivate::setBinding(o, index, -1, 0); + if (binding) binding->destroy(); +} + +#define CLEAN_PROPERTY(o, index) if (fastHasBinding(o, index)) removeBindingOnProperty(o, index) + QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, QDeclarativeContextData *ctxt, QDeclarativeCompiledData *comp, @@ -336,6 +352,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, case QDeclarativeInstruction::StoreVariant: { QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeString.propertyIndex); + // XXX - can be more efficient QVariant v = QDeclarativeStringConverters::variantFromString(primitives.at(instr.storeString.value)); void *a[] = { &v, 0, &status, &flags }; @@ -347,6 +365,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, case QDeclarativeInstruction::StoreVariantInteger: { QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeString.propertyIndex); + QVariant v(instr.storeInteger.value); void *a[] = { &v, 0, &status, &flags }; QMetaObject::metacall(target, QMetaObject::WriteProperty, @@ -357,6 +377,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, case QDeclarativeInstruction::StoreVariantDouble: { QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeString.propertyIndex); + QVariant v(instr.storeDouble.value); void *a[] = { &v, 0, &status, &flags }; QMetaObject::metacall(target, QMetaObject::WriteProperty, @@ -367,6 +389,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, case QDeclarativeInstruction::StoreVariantBool: { QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeString.propertyIndex); + QVariant v(instr.storeBool.value); void *a[] = { &v, 0, &status, &flags }; QMetaObject::metacall(target, QMetaObject::WriteProperty, @@ -377,6 +401,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, case QDeclarativeInstruction::StoreString: { QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeString.propertyIndex); + void *a[] = { (void *)&primitives.at(instr.storeString.value), 0, &status, &flags }; QMetaObject::metacall(target, QMetaObject::WriteProperty, instr.storeString.propertyIndex, a); @@ -386,6 +412,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, case QDeclarativeInstruction::StoreUrl: { QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeUrl.propertyIndex); + void *a[] = { (void *)&urls.at(instr.storeUrl.value), 0, &status, &flags }; QMetaObject::metacall(target, QMetaObject::WriteProperty, instr.storeUrl.propertyIndex, a); @@ -395,6 +423,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, case QDeclarativeInstruction::StoreFloat: { QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeFloat.propertyIndex); + float f = instr.storeFloat.value; void *a[] = { &f, 0, &status, &flags }; QMetaObject::metacall(target, QMetaObject::WriteProperty, @@ -405,6 +435,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, case QDeclarativeInstruction::StoreDouble: { QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeDouble.propertyIndex); + double d = instr.storeDouble.value; void *a[] = { &d, 0, &status, &flags }; QMetaObject::metacall(target, QMetaObject::WriteProperty, @@ -415,6 +447,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, case QDeclarativeInstruction::StoreBool: { QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeBool.propertyIndex); + void *a[] = { (void *)&instr.storeBool.value, 0, &status, &flags }; QMetaObject::metacall(target, QMetaObject::WriteProperty, instr.storeBool.propertyIndex, a); @@ -424,6 +458,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, case QDeclarativeInstruction::StoreInteger: { QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeInteger.propertyIndex); + void *a[] = { (void *)&instr.storeInteger.value, 0, &status, &flags }; QMetaObject::metacall(target, QMetaObject::WriteProperty, instr.storeInteger.propertyIndex, a); @@ -433,6 +469,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, case QDeclarativeInstruction::StoreColor: { QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeColor.propertyIndex); + QColor c = QColor::fromRgba(instr.storeColor.value); void *a[] = { &c, 0, &status, &flags }; QMetaObject::metacall(target, QMetaObject::WriteProperty, @@ -443,6 +481,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, case QDeclarativeInstruction::StoreDate: { QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeDate.propertyIndex); + QDate d = QDate::fromJulianDay(instr.storeDate.value); void *a[] = { &d, 0, &status, &flags }; QMetaObject::metacall(target, QMetaObject::WriteProperty, @@ -453,6 +493,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, case QDeclarativeInstruction::StoreTime: { QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeTime.propertyIndex); + QTime t; t.setHMS(intData.at(instr.storeTime.valueIndex), intData.at(instr.storeTime.valueIndex+1), @@ -467,6 +509,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, case QDeclarativeInstruction::StoreDateTime: { QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeDateTime.propertyIndex); + QTime t; t.setHMS(intData.at(instr.storeDateTime.valueIndex+1), intData.at(instr.storeDateTime.valueIndex+2), @@ -482,6 +526,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, case QDeclarativeInstruction::StorePoint: { QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeRealPair.propertyIndex); + QPoint p = QPointF(floatData.at(instr.storeRealPair.valueIndex), floatData.at(instr.storeRealPair.valueIndex+1)).toPoint(); void *a[] = { &p, 0, &status, &flags }; @@ -493,6 +539,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, case QDeclarativeInstruction::StorePointF: { QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeRealPair.propertyIndex); + QPointF p(floatData.at(instr.storeRealPair.valueIndex), floatData.at(instr.storeRealPair.valueIndex+1)); void *a[] = { &p, 0, &status, &flags }; @@ -504,6 +552,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, case QDeclarativeInstruction::StoreSize: { QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeRealPair.propertyIndex); + QSize p = QSizeF(floatData.at(instr.storeRealPair.valueIndex), floatData.at(instr.storeRealPair.valueIndex+1)).toSize(); void *a[] = { &p, 0, &status, &flags }; @@ -515,6 +565,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, case QDeclarativeInstruction::StoreSizeF: { QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeRealPair.propertyIndex); + QSizeF s(floatData.at(instr.storeRealPair.valueIndex), floatData.at(instr.storeRealPair.valueIndex+1)); void *a[] = { &s, 0, &status, &flags }; @@ -526,6 +578,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, case QDeclarativeInstruction::StoreRect: { QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeRect.propertyIndex); + QRect r = QRectF(floatData.at(instr.storeRect.valueIndex), floatData.at(instr.storeRect.valueIndex+1), floatData.at(instr.storeRect.valueIndex+2), @@ -539,6 +593,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, case QDeclarativeInstruction::StoreRectF: { QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeRect.propertyIndex); + QRectF r(floatData.at(instr.storeRect.valueIndex), floatData.at(instr.storeRect.valueIndex+1), floatData.at(instr.storeRect.valueIndex+2), @@ -552,6 +608,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, case QDeclarativeInstruction::StoreVector3D: { QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeVector3D.propertyIndex); + QVector3D p(floatData.at(instr.storeVector3D.valueIndex), floatData.at(instr.storeVector3D.valueIndex+1), floatData.at(instr.storeVector3D.valueIndex+2)); @@ -565,6 +623,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, { QObject *assignObj = stack.pop(); QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeObject.propertyIndex); void *a[] = { (void *)&assignObj, 0, &status, &flags }; QMetaObject::metacall(target, QMetaObject::WriteProperty, @@ -576,6 +635,8 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, case QDeclarativeInstruction::AssignCustomType: { QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.assignCustomType.propertyIndex); + QDeclarativeCompiledData::CustomTypeData data = customTypeData.at(instr.assignCustomType.valueIndex); const QString &primitive = primitives.at(data.index); QDeclarativeMetaType::StringConverter converter = @@ -780,6 +841,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, { QObject *assign = stack.pop(); QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeObject.propertyIndex); QVariant v = QVariant::fromValue(assign); void *a[] = { &v, 0, &status, &flags }; @@ -792,6 +854,7 @@ QObject *QDeclarativeVME::run(QDeclarativeVMEStack<QObject *> &stack, { QObject *assign = stack.pop(); QObject *target = stack.top(); + CLEAN_PROPERTY(target, instr.storeObject.propertyIndex); int coreIdx = instr.storeObject.propertyIndex; QMetaProperty prop = target->metaObject()->property(coreIdx); diff --git a/src/declarative/qml/qdeclarativeworkerscript.cpp b/src/declarative/qml/qdeclarativeworkerscript.cpp index f8d52b5..1ff0caa 100644 --- a/src/declarative/qml/qdeclarativeworkerscript.cpp +++ b/src/declarative/qml/qdeclarativeworkerscript.cpp @@ -313,7 +313,7 @@ void QDeclarativeWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url) QScriptContext *ctxt = QScriptDeclarativeClass::pushCleanContext(workerEngine); QScriptValue urlContext = workerEngine->newObject(); - urlContext.setData(QScriptValue(workerEngine, fileName)); + urlContext.setData(QScriptValue(workerEngine, url.toString())); ctxt->pushScope(urlContext); ctxt->pushScope(activation); ctxt->setActivationObject(activation); diff --git a/src/declarative/util/qdeclarativeanimation.cpp b/src/declarative/util/qdeclarativeanimation.cpp index ac9c3c0..6a6dfe1 100644 --- a/src/declarative/util/qdeclarativeanimation.cpp +++ b/src/declarative/util/qdeclarativeanimation.cpp @@ -74,7 +74,7 @@ QT_BEGIN_NAMESPACE /*! \qmlclass Animation QDeclarativeAbstractAnimation - \ingroup qml-animation-transition + \ingroup qml-animation-transition \since 4.7 \brief The Animation element is the base of all QML animations. @@ -554,7 +554,7 @@ void QDeclarativeAbstractAnimation::timelineComplete() /*! \qmlclass PauseAnimation QDeclarativePauseAnimation - \ingroup qml-animation-transition + \ingroup qml-animation-transition \since 4.7 \inherits Animation \brief The PauseAnimation element provides a pause for an animation. @@ -571,7 +571,7 @@ void QDeclarativeAbstractAnimation::timelineComplete() } \endcode - \sa {QML Animation}, {declarative/animation/basics}{Animation basics example} + \sa {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example} */ QDeclarativePauseAnimation::QDeclarativePauseAnimation(QObject *parent) : QDeclarativeAbstractAnimation(*(new QDeclarativePauseAnimationPrivate), parent) @@ -630,27 +630,27 @@ QAbstractAnimation *QDeclarativePauseAnimation::qtAnimation() \inherits PropertyAnimation \brief The ColorAnimation element animates changes in color values. - ColorAnimation is a specialized PropertyAnimation that defines an + ColorAnimation is a specialized PropertyAnimation that defines an animation to be applied when a color value changes. - Here is a ColorAnimation applied to the \c color property of a \l Rectangle - as a property value source. It animates the \c color property's value from + Here is a ColorAnimation applied to the \c color property of a \l Rectangle + as a property value source. It animates the \c color property's value from its current value to a value of "red", over 1000 milliseconds: \snippet doc/src/snippets/declarative/coloranimation.qml 0 Like any other animation element, a ColorAnimation can be applied in a - number of ways, including transitions, behaviors and property value - sources. The \l {QML Animation} documentation shows a variety of methods - for creating animations. - - For convenience, when a ColorAnimation is used in a \l Transition, it will - animate any \c color properties that have been modified during the state - change. If a \l{PropertyAnimation::}{property} or - \l{PropertyAnimation::}{properties} are explicitly set for the animation, + number of ways, including transitions, behaviors and property value + sources. The \l {QML Animation and Transitions} documentation shows a + variety of methods for creating animations. + + For convenience, when a ColorAnimation is used in a \l Transition, it will + animate any \c color properties that have been modified during the state + change. If a \l{PropertyAnimation::}{property} or + \l{PropertyAnimation::}{properties} are explicitly set for the animation, then those are used instead. - \sa {QML Animation}, {declarative/animation/basics}{Animation basics example} + \sa {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example} */ QDeclarativeColorAnimation::QDeclarativeColorAnimation(QObject *parent) : QDeclarativePropertyAnimation(parent) @@ -686,10 +686,10 @@ QDeclarativeColorAnimation::~QDeclarativeColorAnimation() If the ColorAnimation is defined within a \l Transition or \l Behavior, this value defaults to the value defined in the starting state of the - \l Transition, or the current value of the property at the moment the + \l Transition, or the current value of the property at the moment the \l Behavior is triggered. - \sa {QML Animation} + \sa {QML Animation and Transitions} */ QColor QDeclarativeColorAnimation::from() const { @@ -712,7 +712,7 @@ void QDeclarativeColorAnimation::setFrom(const QColor &f) \l Transition, or the value of the property change that triggered the \l Behavior. - \sa {QML Animation} + \sa {QML Animation and Transitions} */ QColor QDeclarativeColorAnimation::to() const { @@ -868,7 +868,7 @@ QAbstractAnimation *QDeclarativeScriptAction::qtAnimation() \inherits Animation \brief The PropertyAction element allows immediate property changes during animation. - PropertyAction is used to specify an immediate property change during an + PropertyAction is used to specify an immediate property change during an animation. The property change is not animated. It is useful for setting non-animated property values during an animation. @@ -879,9 +879,9 @@ QAbstractAnimation *QDeclarativeScriptAction::qtAnimation() \snippet doc/src/snippets/declarative/propertyaction.qml standalone - PropertyAction is also useful for setting the exact point at which a property - change should occur during a \l Transition. For example, if PropertyChanges - was used in a \l State to rotate an item around a particular + PropertyAction is also useful for setting the exact point at which a property + change should occur during a \l Transition. For example, if PropertyChanges + was used in a \l State to rotate an item around a particular \l {Item::}{transformOrigin}, it might be implemented like this: \snippet doc/src/snippets/declarative/propertyaction.qml transition @@ -893,13 +893,13 @@ QAbstractAnimation *QDeclarativeScriptAction::qtAnimation() before the RotationAnimation begins: \snippet doc/src/snippets/declarative/propertyaction-sequential.qml sequential - + This immediately sets the \c transformOrigin property to the value defined - in the end state of the \l Transition (i.e. the value defined in the + in the end state of the \l Transition (i.e. the value defined in the PropertyAction object) so that the rotation animation begins with the correct transform origin. - \sa {QML Animation}, QtDeclarative + \sa {QML Animation and Transitions}, QtDeclarative */ QDeclarativePropertyAction::QDeclarativePropertyAction(QObject *parent) : QDeclarativeAbstractAnimation(*(new QDeclarativePropertyActionPrivate), parent) @@ -1129,25 +1129,25 @@ void QDeclarativePropertyAction::transition(QDeclarativeStateActions &actions, \inherits PropertyAnimation \brief The NumberAnimation element animates changes in qreal-type values. - NumberAnimation is a specialized PropertyAnimation that defines an + NumberAnimation is a specialized PropertyAnimation that defines an animation to be applied when a numerical value changes. - Here is a NumberAnimation applied to the \c x property of a \l Rectangle - as a property value source. It animates the \c x value from its current + Here is a NumberAnimation applied to the \c x property of a \l Rectangle + as a property value source. It animates the \c x value from its current value to a value of 50, over 1000 milliseconds: \snippet doc/src/snippets/declarative/numberanimation.qml 0 Like any other animation element, a NumberAnimation can be applied in a - number of ways, including transitions, behaviors and property value - sources. The \l {QML Animation} documentation shows a variety of methods - for creating animations. + number of ways, including transitions, behaviors and property value + sources. The \l {QML Animation and Transitions} documentation shows a + variety of methods for creating animations. Note that NumberAnimation may not animate smoothly if there are irregular changes in the number value that it is tracking. If this is the case, use SmoothedAnimation instead. - \sa {QML Animation}, {declarative/animation/basics}{Animation basics example} + \sa {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example} */ QDeclarativeNumberAnimation::QDeclarativeNumberAnimation(QObject *parent) : QDeclarativePropertyAnimation(parent) @@ -1193,10 +1193,10 @@ void QDeclarativeNumberAnimation::init() If the NumberAnimation is defined within a \l Transition or \l Behavior, this value defaults to the value defined in the starting state of the - \l Transition, or the current value of the property at the moment the + \l Transition, or the current value of the property at the moment the \l Behavior is triggered. - \sa {QML Animation} + \sa {QML Animation and Transitions} */ qreal QDeclarativeNumberAnimation::from() const @@ -1219,7 +1219,7 @@ void QDeclarativeNumberAnimation::setFrom(qreal f) \l Transition, or the value of the property change that triggered the \l Behavior. - \sa {QML Animation} + \sa {QML Animation and Transitions} */ qreal QDeclarativeNumberAnimation::to() const { @@ -1241,15 +1241,15 @@ void QDeclarativeNumberAnimation::setTo(qreal t) \inherits PropertyAnimation \brief The Vector3dAnimation element animates changes in QVector3d values. - Vector3dAnimation is a specialized PropertyAnimation that defines an + Vector3dAnimation is a specialized PropertyAnimation that defines an animation to be applied when a Vector3d value changes. Like any other animation element, a Vector3dAnimation can be applied in a - number of ways, including transitions, behaviors and property value - sources. The \l {QML Animation} documentation shows a variety of methods - for creating animations. + number of ways, including transitions, behaviors and property value + sources. The \l {QML Animation and Transitions} documentation shows a + variety of methods for creating animations. - \sa {QML Animation}, {declarative/animation/basics}{Animation basics example} + \sa {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example} */ QDeclarativeVector3dAnimation::QDeclarativeVector3dAnimation(QObject *parent) : QDeclarativePropertyAnimation(parent) @@ -1270,10 +1270,10 @@ QDeclarativeVector3dAnimation::~QDeclarativeVector3dAnimation() If the Vector3dAnimation is defined within a \l Transition or \l Behavior, this value defaults to the value defined in the starting state of the - \l Transition, or the current value of the property at the moment the + \l Transition, or the current value of the property at the moment the \l Behavior is triggered. - \sa {QML Animation} + \sa {QML Animation and Transitions} */ QVector3D QDeclarativeVector3dAnimation::from() const { @@ -1295,7 +1295,7 @@ void QDeclarativeVector3dAnimation::setFrom(QVector3D f) \l Transition, or the value of the property change that triggered the \l Behavior. - \sa {QML Animation} + \sa {QML Animation and Transitions} */ QVector3D QDeclarativeVector3dAnimation::to() const { @@ -1318,7 +1318,7 @@ void QDeclarativeVector3dAnimation::setTo(QVector3D t) \brief The RotationAnimation element animates changes in rotation values. RotationAnimation is a specialized PropertyAnimation that gives control - over the direction of rotation during an animation. + over the direction of rotation during an animation. By default, it rotates in the direction of the numerical change; a rotation from 0 to 240 will rotate 240 degrees @@ -1334,7 +1334,7 @@ void QDeclarativeVector3dAnimation::setTo(QVector3D t) Notice the RotationAnimation did not need to set a \l target value. As a convenience, when used in a transition, RotationAnimation will rotate all properties named "rotation" or "angle". You can override this by providing - your own properties via \l {PropertyAnimation::properties}{properties} or + your own properties via \l {PropertyAnimation::properties}{properties} or \l {PropertyAnimation::property}{property}. Also, note the \l Rectangle will be rotated around its default @@ -1344,11 +1344,11 @@ void QDeclarativeVector3dAnimation::setTo(QVector3D t) PropertyAction documentation for more details. Like any other animation element, a RotationAnimation can be applied in a - number of ways, including transitions, behaviors and property value - sources. The \l {QML Animation} documentation shows a variety of methods - for creating animations. + number of ways, including transitions, behaviors and property value + sources. The \l {QML Animation and Transitions} documentation shows a + variety of methods for creating animations. - \sa {QML Animation}, {declarative/animation/basics}{Animation basics example} + \sa {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example} */ QVariant _q_interpolateShortestRotation(qreal &f, qreal &t, qreal progress) { @@ -1421,10 +1421,10 @@ QDeclarativeRotationAnimation::~QDeclarativeRotationAnimation() If the RotationAnimation is defined within a \l Transition or \l Behavior, this value defaults to the value defined in the starting state of the - \l Transition, or the current value of the property at the moment the + \l Transition, or the current value of the property at the moment the \l Behavior is triggered. - \sa {QML Animation} + \sa {QML Animation and Transitions} */ qreal QDeclarativeRotationAnimation::from() const { @@ -1446,7 +1446,7 @@ void QDeclarativeRotationAnimation::setFrom(qreal f) \l Transition, or the value of the property change that triggered the \l Behavior. - \sa {QML Animation} + \sa {QML Animation and Transitions} */ qreal QDeclarativeRotationAnimation::to() const { @@ -1572,15 +1572,15 @@ QDeclarativeListProperty<QDeclarativeAbstractAnimation> QDeclarativeAnimationGro if this is the preferred behavior. Like any other animation element, a SequentialAnimation can be applied in a - number of ways, including transitions, behaviors and property value - sources. The \l {QML Animation} documentation shows a variety of methods - for creating animations. + number of ways, including transitions, behaviors and property value + sources. The \l {QML Animation and Transitions} documentation shows a + variety of methods for creating animations. - \note Once an animation has been grouped into a SequentialAnimation or + \note Once an animation has been grouped into a SequentialAnimation or ParallelAnimation, it cannot be individually started and stopped; the SequentialAnimation or ParallelAnimation must be started and stopped as a group. - - \sa ParallelAnimation, {QML Animation}, {declarative/animation/basics}{Animation basics example} + + \sa ParallelAnimation, {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example} */ QDeclarativeSequentialAnimation::QDeclarativeSequentialAnimation(QObject *parent) : @@ -1642,15 +1642,15 @@ void QDeclarativeSequentialAnimation::transition(QDeclarativeStateActions &actio \snippet doc/src/snippets/declarative/parallelanimation.qml 0 Like any other animation element, a ParallelAnimation can be applied in a - number of ways, including transitions, behaviors and property value - sources. The \l {QML Animation} documentation shows a variety of methods - for creating animations. + number of ways, including transitions, behaviors and property value + sources. The \l {QML Animation and Transitions} documentation shows a + variety of methods for creating animations. - \note Once an animation has been grouped into a SequentialAnimation or + \note Once an animation has been grouped into a SequentialAnimation or ParallelAnimation, it cannot be individually started and stopped; the SequentialAnimation or ParallelAnimation must be started and stopped as a group. - \sa SequentialAnimation, {QML Animation}, {declarative/animation/basics}{Animation basics example} + \sa SequentialAnimation, {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example} */ QDeclarativeParallelAnimation::QDeclarativeParallelAnimation(QObject *parent) : QDeclarativeAnimationGroup(parent) @@ -1745,14 +1745,14 @@ void QDeclarativePropertyAnimationPrivate::convertVariant(QVariant &variant, int \inherits Animation \brief The PropertyAnimation element animates changes in property values. - PropertyAnimation provides a way to animate changes to a property's value. + PropertyAnimation provides a way to animate changes to a property's value. It can be used to define animations in a number of ways: - + \list \o In a \l Transition - For example, to animate any objects that have changed their \c x or \c y properties + For example, to animate any objects that have changed their \c x or \c y properties as a result of a state change, using an \c InOutQuad easing curve: \snippet doc/src/snippets/declarative/propertyanimation.qml transition @@ -1792,12 +1792,12 @@ void QDeclarativePropertyAnimationPrivate::convertVariant(QVariant &variant, int Depending on how the animation is used, the set of properties normally used will be different. For more information see the individual property documentation, as well - as the \l{QML Animation} introduction. + as the \l{QML Animation and Transitions} introduction. Note that PropertyAnimation inherits the abstract \l Animation element. This includes additional properties and methods for controlling the animation. - \sa {QML Animation}, {declarative/animation/basics}{Animation basics example} + \sa {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example} */ QDeclarativePropertyAnimation::QDeclarativePropertyAnimation(QObject *parent) @@ -1857,10 +1857,10 @@ void QDeclarativePropertyAnimation::setDuration(int duration) If the PropertyAnimation is defined within a \l Transition or \l Behavior, this value defaults to the value defined in the starting state of the - \l Transition, or the current value of the property at the moment the + \l Transition, or the current value of the property at the moment the \l Behavior is triggered. - \sa {QML Animation} + \sa {QML Animation and Transitions} */ QVariant QDeclarativePropertyAnimation::from() const { @@ -1887,7 +1887,7 @@ void QDeclarativePropertyAnimation::setFrom(const QVariant &f) \l Transition, or the value of the property change that triggered the \l Behavior. - \sa {QML Animation} + \sa {QML Animation and Transitions} */ QVariant QDeclarativePropertyAnimation::to() const { @@ -2254,7 +2254,7 @@ void QDeclarativePropertyAnimation::setProperties(const QString &prop) As seen in the above example, properties is specified as a comma-separated string of property names to animate. - \sa exclude, {QML Animation} + \sa exclude, {QML Animation and Transitions} */ QDeclarativeListProperty<QObject> QDeclarativePropertyAnimation::targets() { @@ -2437,7 +2437,7 @@ void QDeclarativePropertyAnimation::transition(QDeclarativeStateActions &actions ParentAnimation is used to animate a parent change for an \l Item. For example, the following ParentChange changes \c blueRect to become - a child of \c redRect when it is clicked. The inclusion of the + a child of \c redRect when it is clicked. The inclusion of the ParentAnimation, which defines a NumberAnimation to be applied during the transition, ensures the item animates smoothly as it moves to its new parent: @@ -2452,17 +2452,17 @@ void QDeclarativePropertyAnimation::transition(QDeclarativeStateActions &actions to animate the parent change via another item that does not have clipping enabled. Such an item can be set using the \l via property. - For convenience, when a ParentAnimation is used in a \l Transition, it will - animate any ParentChange that has occurred during the state change. + For convenience, when a ParentAnimation is used in a \l Transition, it will + animate any ParentChange that has occurred during the state change. This can be overridden by setting a specific target item using the \l target property. Like any other animation element, a ParentAnimation can be applied in a - number of ways, including transitions, behaviors and property value - sources. The \l {QML Animation} documentation shows a variety of methods - for creating animations. + number of ways, including transitions, behaviors and property value + sources. The \l {QML Animation and Transitions} documentation shows a + variety of methods for creating animations. - \sa {QML Animation}, {declarative/animation/basics}{Animation basics example} + \sa {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example} */ QDeclarativeParentAnimation::QDeclarativeParentAnimation(QObject *parent) : QDeclarativeAnimationGroup(*(new QDeclarativeParentAnimationPrivate), parent) @@ -2765,6 +2765,8 @@ void QDeclarativeParentAnimation::transition(QDeclarativeStateActions &actions, d->endAction->setAnimAction(d->via ? viaData : data, QActionAnimation::DeleteWhenStopped); d->startAction->setAnimAction(d->via ? data : 0, QActionAnimation::DeleteWhenStopped); } + if (!d->via) + delete viaData; } else { delete data; delete viaData; @@ -2793,23 +2795,23 @@ QAbstractAnimation *QDeclarativeParentAnimation::qtAnimation() \inherits Animation \brief The AnchorAnimation element animates changes in anchor values. - AnchorAnimation is used to animate an anchor change. + AnchorAnimation is used to animate an anchor change. In the following snippet we animate the addition of a right anchor to a \l Rectangle: \snippet doc/src/snippets/declarative/anchoranimation.qml 0 - For convenience, when an AnchorAnimation is used in a \l Transition, it will - animate any AnchorChanges that have occurred during the state change. + For convenience, when an AnchorAnimation is used in a \l Transition, it will + animate any AnchorChanges that have occurred during the state change. This can be overridden by setting a specific target item using the \l target property. Like any other animation element, an AnchorAnimation can be applied in a - number of ways, including transitions, behaviors and property value - sources. The \l {QML Animation} documentation shows a variety of methods - for creating animations. + number of ways, including transitions, behaviors and property value + sources. The \l {QML Animation and Transitions} documentation shows a + variety of methods for creating animations. - \sa {QML Animation}, AnchorChanges + \sa {QML Animation and Transitions}, AnchorChanges */ QDeclarativeAnchorAnimation::QDeclarativeAnchorAnimation(QObject *parent) diff --git a/src/declarative/util/qdeclarativebehavior.cpp b/src/declarative/util/qdeclarativebehavior.cpp index e584476..a1321e2 100644 --- a/src/declarative/util/qdeclarativebehavior.cpp +++ b/src/declarative/util/qdeclarativebehavior.cpp @@ -72,11 +72,11 @@ public: /*! \qmlclass Behavior QDeclarativeBehavior - \ingroup qml-animation-transition + \ingroup qml-animation-transition \since 4.7 \brief The Behavior element allows you to specify a default animation for a property change. - A Behavior defines the default animation to be applied whenever a + A Behavior defines the default animation to be applied whenever a particular property value changes. For example, the following Behavior defines a NumberAnimation to be run @@ -91,9 +91,10 @@ public: If a \l{QML States}{state change} has a \l Transition that matches the same property as a Behavior, the \l Transition animation overrides the Behavior for that - state change. + state change. For general advice on using Behaviors to animate state changes, see + \l{Using QML Behaviors with States}. - \sa {QML Animation}, {declarative/animation/behaviors}{Behavior example}, QtDeclarative + \sa {QML Animation and Transitions}, {declarative/animation/behaviors}{Behavior example}, QtDeclarative */ @@ -205,7 +206,7 @@ void QDeclarativeBehavior::write(const QVariant &value) d->animation->qtAnimation()->start(); d->blockRunningChanged = false; if (!after.contains(d->property)) - QDeclarativePropertyPrivate::write(d->property, value, QDeclarativePropertyPrivate::BypassInterceptor | QDeclarativePropertyPrivate::DontRemoveBinding); + QDeclarativePropertyPrivate::write(d->property, value, QDeclarativePropertyPrivate::BypassInterceptor | QDeclarativePropertyPrivate::DontRemoveBinding); } void QDeclarativeBehavior::setTarget(const QDeclarativeProperty &property) diff --git a/src/declarative/util/qdeclarativeconnections.cpp b/src/declarative/util/qdeclarativeconnections.cpp index 5a66aab..83a7d83 100644 --- a/src/declarative/util/qdeclarativeconnections.cpp +++ b/src/declarative/util/qdeclarativeconnections.cpp @@ -117,6 +117,8 @@ public: id: area } // ... + \endqml + \qml Connections { target: area onClicked: foo(parameters) diff --git a/src/declarative/util/qdeclarativelistmodel.cpp b/src/declarative/util/qdeclarativelistmodel.cpp index 9332de4..258bc81 100644 --- a/src/declarative/util/qdeclarativelistmodel.cpp +++ b/src/declarative/util/qdeclarativelistmodel.cpp @@ -108,7 +108,7 @@ QDeclarativeListModelParser::ListInstruction *QDeclarativeListModelParser::ListM The following example shows a ListModel containing three elements, with the roles "name" and "cost". - \div {float-right} + \div {class="float-right"} \inlineimage listmodel.png \enddiv @@ -133,7 +133,7 @@ QDeclarativeListModelParser::ListInstruction *QDeclarativeListModelParser::ListM The delegate displays all the fruit attributes: - \div {float-right} + \div {class="float-right"} \inlineimage listmodel-nested.png \enddiv @@ -143,7 +143,7 @@ QDeclarativeListModelParser::ListInstruction *QDeclarativeListModelParser::ListM \section1 Modifying List Models The content of a ListModel may be created and modified using the clear(), - append(), set() and setProperty() methods. For example: + append(), set(), insert() and setProperty() methods. For example: \snippet doc/src/snippets/declarative/listmodel-modify.qml delegate @@ -1301,9 +1301,6 @@ int NestedListModel::count() const void NestedListModel::clear() { - _rolesOk = false; - roleStrings.clear(); - if (_root) _root->clear(); } diff --git a/src/declarative/util/qdeclarativepixmapcache.cpp b/src/declarative/util/qdeclarativepixmapcache.cpp index 5190eab..9221d78 100644 --- a/src/declarative/util/qdeclarativepixmapcache.cpp +++ b/src/declarative/util/qdeclarativepixmapcache.cpp @@ -426,7 +426,8 @@ void QDeclarativePixmapReader::processJobs() replies.remove(reply); reply->close(); } - delete job; + // deleteLater, since not owned by this thread + job->deleteLater(); } cancelled.clear(); } diff --git a/src/declarative/util/qdeclarativepropertychanges.cpp b/src/declarative/util/qdeclarativepropertychanges.cpp index 9bcb263..b03630d 100644 --- a/src/declarative/util/qdeclarativepropertychanges.cpp +++ b/src/declarative/util/qdeclarativepropertychanges.cpp @@ -118,12 +118,13 @@ QT_BEGIN_NAMESPACE \section2 Immediate property changes in transitions - When \l Transitions are used to animate state changes, they animate - properties from their values in the current state to those defined in the - new state (as defined by PropertyChanges objects). However, - it is sometimes desirable to set a property value \e immediately during a - \l Transition, without animation; in these cases, the PropertyAction - element can be used to force an immediate property change. + When \l{QML Animation and Transitions}{Transitions} are used to animate + state changes, they animate properties from their values in the current + state to those defined in the new state (as defined by PropertyChanges + objects). However, it is sometimes desirable to set a property value + \e immediately during a \l Transition, without animation; in these cases, + the PropertyAction element can be used to force an immediate property + change. See the PropertyAction documentation for more details. diff --git a/src/declarative/util/qdeclarativesmoothedanimation.cpp b/src/declarative/util/qdeclarativesmoothedanimation.cpp index e2f6e3c..9def5b4 100644 --- a/src/declarative/util/qdeclarativesmoothedanimation.cpp +++ b/src/declarative/util/qdeclarativesmoothedanimation.cpp @@ -257,8 +257,8 @@ void QSmoothedAnimation::init() A SmoothedAnimation animates a property's value to a set target value using an ease in/out quad easing curve. When the target value changes, - the easing curves used to animate between the old and new target values - are smoothly spliced together to create a smooth movement to the new + the easing curves used to animate between the old and new target values + are smoothly spliced together to create a smooth movement to the new target value that maintains the current velocity. The follow example shows one \l Rectangle tracking the position of another @@ -288,11 +288,11 @@ void QSmoothedAnimation::init() of 0.5 will take 2000 ms to complete. Like any other animation element, a SmoothedAnimation can be applied in a - number of ways, including transitions, behaviors and property value - sources. The \l {QML Animation} documentation shows a variety of methods - for creating animations. + number of ways, including transitions, behaviors and property value + sources. The \l {QML Animation and Transitions} documentation shows a + variety of methods for creating animations. - \sa SpringAnimation, NumberAnimation, {QML Animation}, {declarative/animation/basics}{Animation basics example} + \sa SpringAnimation, NumberAnimation, {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example} */ QDeclarativeSmoothedAnimation::QDeclarativeSmoothedAnimation(QObject *parent) diff --git a/src/declarative/util/qdeclarativespringanimation.cpp b/src/declarative/util/qdeclarativespringanimation.cpp index 1212a1c..bb58b0a 100644 --- a/src/declarative/util/qdeclarativespringanimation.cpp +++ b/src/declarative/util/qdeclarativespringanimation.cpp @@ -246,19 +246,19 @@ void QDeclarativeSpringAnimationPrivate::updateMode() You can also limit the maximum \l velocity of the animation. - The following \l Rectangle moves to the position of the mouse using a + The following \l Rectangle moves to the position of the mouse using a SpringAnimation when the mouse is clicked. The use of the \l Behavior - on the \c x and \c y values indicates that whenever these values are + on the \c x and \c y values indicates that whenever these values are changed, a SpringAnimation should be applied. \snippet doc/src/snippets/declarative/springanimation.qml 0 Like any other animation element, a SpringAnimation can be applied in a - number of ways, including transitions, behaviors and property value - sources. The \l {QML Animation} documentation shows a variety of methods - for creating animations. + number of ways, including transitions, behaviors and property value + sources. The \l {QML Animation and Transitions} documentation shows a + variety of methods for creating animations. - \sa SmoothedAnimation, {QML Animation}, {declarative/animation/basics}{Animation basics example}, {declarative/toys/clocks}{Clocks example} + \sa SmoothedAnimation, {QML Animation and Transitions}, {declarative/animation/basics}{Animation basics example}, {declarative/toys/clocks}{Clocks example} */ QDeclarativeSpringAnimation::QDeclarativeSpringAnimation(QObject *parent) @@ -299,7 +299,7 @@ void QDeclarativeSpringAnimation::setVelocity(qreal velocity) This property describes how strongly the target is pulled towards the source. The default value is 0 (that is, the spring-like motion is disabled). - + The useful value range is 0 - 5.0. When this property is set and the \l velocity value is greater than 0, @@ -394,9 +394,9 @@ void QDeclarativeSpringAnimation::setModulus(qreal modulus) \qmlproperty real SpringAnimation::mass This property holds the "mass" of the property being moved. - The value is 1.0 by default. - - A greater mass causes slower movement and a greater spring-like + The value is 1.0 by default. + + A greater mass causes slower movement and a greater spring-like motion when an item comes to rest. */ qreal QDeclarativeSpringAnimation::mass() const diff --git a/src/declarative/util/qdeclarativestate.cpp b/src/declarative/util/qdeclarativestate.cpp index 5a4e2b1..5718e29 100644 --- a/src/declarative/util/qdeclarativestate.cpp +++ b/src/declarative/util/qdeclarativestate.cpp @@ -152,14 +152,14 @@ QDeclarativeStateOperation::QDeclarativeStateOperation(QObjectPrivate &dd, QObje Notice the default state is referred to using an empty string (""). - States are commonly used together with \l {Transitions} to provide + States are commonly used together with \l{QML Animation and Transitions}{Transitions} to provide animations when state changes occur. \note Setting the state of an object from within another state of the same object is not allowed. \sa {declarative/animation/states}{states example}, {qmlstates}{States}, - {qdeclarativeanimation.html#transitions}{QML Transitions}, QtDeclarative + {QML Animation and Transitions}{Transitions}, QtDeclarative */ QDeclarativeState::QDeclarativeState(QObject *parent) : QObject(*(new QDeclarativeStatePrivate), parent) diff --git a/src/declarative/util/qdeclarativestategroup.cpp b/src/declarative/util/qdeclarativestategroup.cpp index f1d0997..6459bf9 100644 --- a/src/declarative/util/qdeclarativestategroup.cpp +++ b/src/declarative/util/qdeclarativestategroup.cpp @@ -88,7 +88,7 @@ public: /*! \qmlclass StateGroup QDeclarativeStateGroup - \ingroup qml-state-elements + \ingroup qml-state-elements \since 4.7 \brief The StateGroup element provides state support for non-Item elements. @@ -113,7 +113,7 @@ public: } \endqml - \sa {qmlstate}{States} {Transitions}, {QtDeclarative} + \sa {qmlstate}{States} {QML Animation and Transitions}{Transitions}, {QtDeclarative} */ QDeclarativeStateGroup::QDeclarativeStateGroup(QObject *parent) @@ -213,7 +213,7 @@ void QDeclarativeStateGroupPrivate::clear_states(QDeclarativeListProperty<QDecla } \endqml - \sa {Transitions} + \sa {QML Animation and Transitions}{Transitions} */ QDeclarativeListProperty<QDeclarativeTransition> QDeclarativeStateGroup::transitionsProperty() { diff --git a/src/declarative/util/qdeclarativetransition.cpp b/src/declarative/util/qdeclarativetransition.cpp index 063ec3e..1a574b8 100644 --- a/src/declarative/util/qdeclarativetransition.cpp +++ b/src/declarative/util/qdeclarativetransition.cpp @@ -60,24 +60,24 @@ QT_BEGIN_NAMESPACE A Transition defines the animations to be applied when a \l State change occurs. For example, the following \l Rectangle has two states: the default state, and - an added "moved" state. In the "moved state, the rectangle's position changes + an added "moved" state. In the "moved state, the rectangle's position changes to (50, 50). The added Transition specifies that when the rectangle changes between the default and the "moved" state, any changes to the \c x and \c y properties should be animated, using an \c Easing.InOutQuad. \snippet doc/src/snippets/declarative/transition.qml 0 - Notice the example does not require \l{PropertyAnimation::}{to} and + Notice the example does not require \l{PropertyAnimation::}{to} and \l{PropertyAnimation::}{from} values for the NumberAnimation. As a convenience, these properties are automatically set to the values of \c x and \c y before and after the state change; the \c from values are provided by the current values of \c x and \c y, and the \c to values are provided by - the PropertyChanges object. If you wish, you can provide \l{PropertyAnimation::}{to} and + the PropertyChanges object. If you wish, you can provide \l{PropertyAnimation::}{to} and \l{PropertyAnimation::}{from} values anyway to override the default values. - By default, a Transition's animations are applied for any state change in the - parent item. The Transition \l {Transition::}{from} and \l {Transition::}{to} - values can be set to restrict the animations to only be applied when changing + By default, a Transition's animations are applied for any state change in the + parent item. The Transition \l {Transition::}{from} and \l {Transition::}{to} + values can be set to restrict the animations to only be applied when changing from one particular state to another. To define multiple transitions, specify \l Item::transitions as a list: @@ -92,7 +92,7 @@ QT_BEGIN_NAMESPACE \l Behavior, the Transition animation overrides the \l Behavior for that state change. - \sa {QML Animation}, {declarative/animation/states}{states example}, {qmlstates}{States}, {QtDeclarative} + \sa {QML Animation and Transitions}, {declarative/animation/states}{states example}, {qmlstates}{States}, {QtDeclarative} */ //ParallelAnimationWrapper allows us to do a "callback" when the animation finishes, rather than connecting @@ -111,8 +111,8 @@ class QDeclarativeTransitionPrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QDeclarativeTransition) public: - QDeclarativeTransitionPrivate() - : fromState(QLatin1String("*")), toState(QLatin1String("*")), + QDeclarativeTransitionPrivate() + : fromState(QLatin1String("*")), toState(QLatin1String("*")), reversed(false), reversible(false), endState(0) { group.trans = this; @@ -249,7 +249,7 @@ void QDeclarativeTransition::setFromState(const QString &f) is reversed, and it is not necessary to set this property to reverse the transition. - However, if a SequentialAnimation is used, or if the \l from or \l to + However, if a SequentialAnimation is used, or if the \l from or \l to properties have been set, this property will need to be set to reverse a transition when a state change is reverted. For example, the following transition applies a sequential animation when the mouse is pressed, @@ -257,7 +257,7 @@ void QDeclarativeTransition::setFromState(const QString &f) \snippet doc/src/snippets/declarative/transition-reversible.qml 0 - If the transition did not set the \c to and \c reversible values, then + If the transition did not set the \c to and \c reversible values, then on the mouse release, the transition would play the PropertyAnimation before the ColorAnimation instead of reversing the sequence. */ diff --git a/src/declarative/util/qdeclarativeview.cpp b/src/declarative/util/qdeclarativeview.cpp index c2e5efe..dcc078d 100644 --- a/src/declarative/util/qdeclarativeview.cpp +++ b/src/declarative/util/qdeclarativeview.cpp @@ -194,9 +194,9 @@ void QDeclarativeViewPrivate::itemGeometryChanged(QDeclarativeItem *resizeItem, \since 4.7 \brief The QDeclarativeView class provides a widget for displaying a Qt Declarative user interface. - QDeclarativeItem objects can be placed on a standard QGraphicsScene and - displayed with QGraphicsView. QDeclarativeView is a QGraphicsView subclass - provided as a convenience for displaying QML files, and connecting between + QDeclarativeItem objects can be placed on a standard QGraphicsScene and + displayed with QGraphicsView. QDeclarativeView is a QGraphicsView subclass + provided as a convenience for displaying QML files, and connecting between QML and C++ Qt objects. QDeclarativeView provides: @@ -236,7 +236,7 @@ void QDeclarativeViewPrivate::itemGeometryChanged(QDeclarativeItem *resizeItem, If you're using your own QGraphicsScene-based scene with QDeclarativeView, remember to enable scene's sticky focus mode and to set itemIndexMethod to QGraphicsScene::NoIndex. - \sa {Integrating QML with existing Qt UI code}, {Using QML in C++ Applications} + \sa {Integrating QML Code with Existing Qt UI Code}, {Using QML Bindings in C++ Applications} */ @@ -250,7 +250,7 @@ void QDeclarativeViewPrivate::itemGeometryChanged(QDeclarativeItem *resizeItem, /*! \fn QDeclarativeView::QDeclarativeView(QWidget *parent) - + Constructs a QDeclarativeView with the given \a parent. */ QDeclarativeView::QDeclarativeView(QWidget *parent) @@ -293,6 +293,13 @@ void QDeclarativeViewPrivate::init() q->setFocusPolicy(Qt::StrongFocus); q->scene()->setStickyFocus(true); //### needed for correct focus handling + +#ifdef QDECLARATIVEVIEW_NOBACKGROUND + q->setAttribute(Qt::WA_OpaquePaintEvent); + q->setAttribute(Qt::WA_NoSystemBackground); + q->viewport()->setAttribute(Qt::WA_OpaquePaintEvent); + q->viewport()->setAttribute(Qt::WA_NoSystemBackground); +#endif } /*! @@ -697,7 +704,7 @@ void QDeclarativeView::paintEvent(QPaintEvent *event) QDeclarativeDebugTrace::startRange(QDeclarativeDebugTrace::Painting); int time = 0; - if (frameRateDebug()) + if (frameRateDebug()) time = d->frameTimer.restart(); #ifdef Q_WS_MAC diff --git a/src/declarative/util/qdeclarativexmllistmodel.cpp b/src/declarative/util/qdeclarativexmllistmodel.cpp index 5af53e6..a61ac06 100644 --- a/src/declarative/util/qdeclarativexmllistmodel.cpp +++ b/src/declarative/util/qdeclarativexmllistmodel.cpp @@ -144,6 +144,7 @@ struct XmlQueryJob QList<void*> roleQueryErrorId; // the ptr to send back if there is an error QStringList keyRoleQueries; QStringList keyRoleResultsCache; + QString prefix; }; class QDeclarativeXmlQuery : public QObject @@ -172,6 +173,12 @@ public: } int doQuery(QString query, QString namespaces, QByteArray data, QList<QDeclarativeXmlListModelRole *>* roleObjects, QStringList keyRoleResultsCache) { + { + QMutexLocker m1(&m_mutex); + m_queryIds.ref(); + if (m_queryIds <= 0) + m_queryIds = 1; + } XmlQueryJob job; job.queryId = m_queryIds; @@ -194,9 +201,6 @@ public: { QMutexLocker ml(&m_mutex); m_jobs.insert(m_queryIds, job); - m_queryIds++; - if (m_queryIds <= 0) - m_queryIds = 1; } QMetaObject::invokeMethod(this, "processQuery", Qt::QueuedConnection, Q_ARG(int, job.queryId)); @@ -214,20 +218,15 @@ private slots: job = m_jobs.value(queryId); } - QDeclarativeXmlQueryResult r; - doQueryJob(&job); - doSubQueryJob(&job); - r.queryId = job.queryId; - r.size = m_size; - r.data = m_modelData; - r.inserted = m_insertedItemRanges; - r.removed = m_removedItemRanges; - r.keyRoleResultsCache = job.keyRoleResultsCache; + QDeclarativeXmlQueryResult result; + result.queryId = job.queryId; + doQueryJob(&job, &result); + doSubQueryJob(&job, &result); { QMutexLocker ml(&m_mutex); if (m_jobs.contains(queryId)) { - emit queryCompleted(r); + emit queryCompleted(result); m_jobs.remove(queryId); } } @@ -241,8 +240,8 @@ protected: private: - void doQueryJob(XmlQueryJob* job); - void doSubQueryJob(XmlQueryJob* job); + void doQueryJob(XmlQueryJob *job, QDeclarativeXmlQueryResult *currentResult); + void doSubQueryJob(XmlQueryJob *job, QDeclarativeXmlQueryResult *currentResult); void getValuesOfKeyRoles(const XmlQueryJob& currentJob, QStringList *values, QXmlQuery *query) const; void addIndexToRangeList(QList<QDeclarativeXmlListRange> *ranges, int index) const; @@ -250,17 +249,12 @@ private: QMutex m_mutex; QThread m_thread; QMap<int, XmlQueryJob> m_jobs; - int m_queryIds; - QString m_prefix; - int m_size; - QList<QList<QVariant> > m_modelData; - QList<QDeclarativeXmlListRange> m_insertedItemRanges; - QList<QDeclarativeXmlListRange> m_removedItemRanges; + QAtomicInt m_queryIds; }; Q_GLOBAL_STATIC(QDeclarativeXmlQuery, globalXmlQuery) -void QDeclarativeXmlQuery::doQueryJob(XmlQueryJob* currentJob) +void QDeclarativeXmlQuery::doQueryJob(XmlQueryJob *currentJob, QDeclarativeXmlQueryResult *currentResult) { Q_ASSERT(currentJob->queryId != -1); @@ -295,10 +289,8 @@ void QDeclarativeXmlQuery::doQueryJob(XmlQueryJob* currentJob) } currentJob->data = xml; - m_prefix = namespaces + prefix + QLatin1Char('/'); - m_size = 0; - if (count > 0) - m_size = count; + currentJob->prefix = namespaces + prefix + QLatin1Char('/'); + currentResult->size = (count > 0 ? count : 0); } void QDeclarativeXmlQuery::getValuesOfKeyRoles(const XmlQueryJob& currentJob, QStringList *values, QXmlQuery *query) const @@ -306,9 +298,9 @@ void QDeclarativeXmlQuery::getValuesOfKeyRoles(const XmlQueryJob& currentJob, QS const QStringList &keysQueries = currentJob.keyRoleQueries; QString keysQuery; if (keysQueries.count() == 1) - keysQuery = m_prefix + keysQueries[0]; + keysQuery = currentJob.prefix + keysQueries[0]; else if (keysQueries.count() > 1) - keysQuery = m_prefix + QLatin1String("concat(") + keysQueries.join(QLatin1String(",")) + QLatin1String(")"); + keysQuery = currentJob.prefix + QLatin1String("concat(") + keysQueries.join(QLatin1String(",")) + QLatin1String(")"); if (!keysQuery.isEmpty()) { query->setQuery(keysQuery); @@ -331,10 +323,9 @@ void QDeclarativeXmlQuery::addIndexToRangeList(QList<QDeclarativeXmlListRange> * ranges->append(qMakePair(index, 1)); } -void QDeclarativeXmlQuery::doSubQueryJob(XmlQueryJob* currentJob) +void QDeclarativeXmlQuery::doSubQueryJob(XmlQueryJob *currentJob, QDeclarativeXmlQueryResult *currentResult) { Q_ASSERT(currentJob->queryId != -1); - m_modelData.clear(); QBuffer b(¤tJob->data); b.open(QIODevice::ReadOnly); @@ -347,16 +338,14 @@ void QDeclarativeXmlQuery::doSubQueryJob(XmlQueryJob* currentJob) // See if any values of key roles have been inserted or removed. - m_insertedItemRanges.clear(); - m_removedItemRanges.clear(); if (currentJob->keyRoleResultsCache.isEmpty()) { - m_insertedItemRanges << qMakePair(0, m_size); + currentResult->inserted << qMakePair(0, currentResult->size); } else { if (keyRoleResults != currentJob->keyRoleResultsCache) { QStringList temp; for (int i=0; i<currentJob->keyRoleResultsCache.count(); i++) { if (!keyRoleResults.contains(currentJob->keyRoleResultsCache[i])) - addIndexToRangeList(&m_removedItemRanges, i); + addIndexToRangeList(¤tResult->removed, i); else temp << currentJob->keyRoleResultsCache[i]; } @@ -364,12 +353,12 @@ void QDeclarativeXmlQuery::doSubQueryJob(XmlQueryJob* currentJob) for (int i=0; i<keyRoleResults.count(); i++) { if (temp.count() == i || keyRoleResults[i] != temp[i]) { temp.insert(i, keyRoleResults[i]); - addIndexToRangeList(&m_insertedItemRanges, i); + addIndexToRangeList(¤tResult->inserted, i); } } } } - currentJob->keyRoleResultsCache = keyRoleResults; + currentResult->keyRoleResultsCache = keyRoleResults; // Get the new values for each role. //### we might be able to condense even further (query for everything in one go) @@ -377,7 +366,7 @@ void QDeclarativeXmlQuery::doSubQueryJob(XmlQueryJob* currentJob) for (int i = 0; i < queries.size(); ++i) { QList<QVariant> resultList; if (!queries[i].isEmpty()) { - subquery.setQuery(m_prefix + QLatin1String("(let $v := string(") + queries[i] + QLatin1String(") return if ($v) then ") + queries[i] + QLatin1String(" else \"\")")); + subquery.setQuery(currentJob->prefix + QLatin1String("(let $v := string(") + queries[i] + QLatin1String(") return if ($v) then ") + queries[i] + QLatin1String(" else \"\")")); if (subquery.isValid()) { QXmlResultItems resultItems; subquery.evaluateTo(&resultItems); @@ -391,9 +380,9 @@ void QDeclarativeXmlQuery::doSubQueryJob(XmlQueryJob* currentJob) } } //### should warn here if things have gone wrong. - while (resultList.count() < m_size) + while (resultList.count() < currentResult->size) resultList << QVariant(); - m_modelData << resultList; + currentResult->data << resultList; b.seek(0); } @@ -919,7 +908,7 @@ void QDeclarativeXmlListModel::reload() } else { d->notifyQueryStarted(true); QNetworkRequest req(d->src); - req.setRawHeader("Accept", "application/xml"); + req.setRawHeader("Accept", "application/xml,*/*"); d->reply = qmlContext(this)->engine()->networkAccessManager()->get(req); QObject::connect(d->reply, SIGNAL(finished()), this, SLOT(requestFinished())); QObject::connect(d->reply, SIGNAL(downloadProgress(qint64,qint64)), diff --git a/src/gui/dialogs/qabstractprintdialog.cpp b/src/gui/dialogs/qabstractprintdialog.cpp index 3317018..ef46697 100644 --- a/src/gui/dialogs/qabstractprintdialog.cpp +++ b/src/gui/dialogs/qabstractprintdialog.cpp @@ -381,19 +381,11 @@ void QAbstractPrintDialogPrivate::setPrinter(QPrinter *newPrinter) If the dialog is accepted by the user, the QPrinter object is correctly configured for printing. - \raw HTML - <table align="center"> - <tr><td> - \endraw - \inlineimage plastique-printdialog.png - \raw HTML - </td><td> - \endraw - \inlineimage plastique-printdialog-properties.png - \raw HTML - </td></tr> - </table> - \endraw + \table + \row + \o \inlineimage plastique-printdialog.png + \o \inlineimage plastique-printdialog-properties.png + \endtable The printer dialog (shown above in Plastique style) enables access to common printing properties. On X11 platforms that use the CUPS printing system, the diff --git a/src/gui/dialogs/qmessagebox.cpp b/src/gui/dialogs/qmessagebox.cpp index dd06445..8fd615a 100644 --- a/src/gui/dialogs/qmessagebox.cpp +++ b/src/gui/dialogs/qmessagebox.cpp @@ -1536,10 +1536,12 @@ static QMessageBox::StandardButton showNewMessageBox(QWidget *parent, /*! \since 4.2 - Opens an information message box with the specified \a title and - \a text. The standard \a buttons are added to the message box. \a - defaultButton specifies the button used when \key Enter is - pressed. \a defaultButton must refer to a button that was given in \a buttons. + Opens an information message box with the given \a title and + \a text in front of the specified \a parent widget. + + The standard \a buttons are added to the message box. + \a defaultButton specifies the button used when \key Enter is pressed. + \a defaultButton must refer to a button that was given in \a buttons. If \a defaultButton is QMessageBox::NoButton, QMessageBox chooses a suitable default automatically. @@ -1547,9 +1549,13 @@ static QMessageBox::StandardButton showNewMessageBox(QWidget *parent, \key Esc was pressed instead, the \l{Default and Escape Keys} {escape button} is returned. - The message box is an \l{Qt::ApplicationModal} {application modal} + The message box is an \l{Qt::ApplicationModal}{application modal} dialog box. + \warning Do not delete \a parent during the execution of the dialog. + If you want to do this, you should create the dialog + yourself using one of the QMessageBox constructors. + \sa question(), warning(), critical() */ QMessageBox::StandardButton QMessageBox::information(QWidget *parent, const QString &title, @@ -1564,8 +1570,10 @@ QMessageBox::StandardButton QMessageBox::information(QWidget *parent, const QStr /*! \since 4.2 - Opens a question message box with the specified \a title and \a - text. The standard \a buttons are added to the message box. \a + Opens a question message box with the given \a title and \a + text in front of the specified \a parent widget. + + The standard \a buttons are added to the message box. \a defaultButton specifies the button used when \key Enter is pressed. \a defaultButton must refer to a button that was given in \a buttons. If \a defaultButton is QMessageBox::NoButton, QMessageBox @@ -1578,6 +1586,10 @@ QMessageBox::StandardButton QMessageBox::information(QWidget *parent, const QStr The message box is an \l{Qt::ApplicationModal} {application modal} dialog box. + \warning Do not delete \a parent during the execution of the dialog. + If you want to do this, you should create the dialog + yourself using one of the QMessageBox constructors. + \sa information(), warning(), critical() */ QMessageBox::StandardButton QMessageBox::question(QWidget *parent, const QString &title, @@ -1590,8 +1602,10 @@ QMessageBox::StandardButton QMessageBox::question(QWidget *parent, const QString /*! \since 4.2 - Opens a warning message box with the specified \a title and \a - text. The standard \a buttons are added to the message box. \a + Opens a warning message box with the given \a title and \a + text in front of the specified \a parent widget. + + The standard \a buttons are added to the message box. \a defaultButton specifies the button used when \key Enter is pressed. \a defaultButton must refer to a button that was given in \a buttons. If \a defaultButton is QMessageBox::NoButton, QMessageBox @@ -1604,6 +1618,10 @@ QMessageBox::StandardButton QMessageBox::question(QWidget *parent, const QString The message box is an \l{Qt::ApplicationModal} {application modal} dialog box. + \warning Do not delete \a parent during the execution of the dialog. + If you want to do this, you should create the dialog + yourself using one of the QMessageBox constructors. + \sa question(), information(), critical() */ QMessageBox::StandardButton QMessageBox::warning(QWidget *parent, const QString &title, @@ -1616,8 +1634,10 @@ QMessageBox::StandardButton QMessageBox::warning(QWidget *parent, const QString /*! \since 4.2 - Opens a critical message box with the specified \a title and \a - text. The standard \a buttons are added to the message box. \a + Opens a critical message box with the given \a title and \a + text in front of the specified \a parent widget. + + The standard \a buttons are added to the message box. \a defaultButton specifies the button used when \key Enter is pressed. \a defaultButton must refer to a button that was given in \a buttons. If \a defaultButton is QMessageBox::NoButton, QMessageBox @@ -1630,9 +1650,9 @@ QMessageBox::StandardButton QMessageBox::warning(QWidget *parent, const QString The message box is an \l{Qt::ApplicationModal} {application modal} dialog box. - \warning Do not delete \a parent during the execution of the dialog. - If you want to do this, you should create the dialog - yourself using one of the QMessageBox constructors. + \warning Do not delete \a parent during the execution of the dialog. + If you want to do this, you should create the dialog + yourself using one of the QMessageBox constructors. \sa question(), warning(), information() */ diff --git a/src/gui/egl/qegl_symbian.cpp b/src/gui/egl/qegl_symbian.cpp index 6533d11..fabf9d1 100644 --- a/src/gui/egl/qegl_symbian.cpp +++ b/src/gui/egl/qegl_symbian.cpp @@ -42,6 +42,7 @@ #include <QtGui/qpaintdevice.h> #include <QtGui/qpixmap.h> #include <QtGui/qwidget.h> +#include <QtGui/private/qapplication_p.h> #include "qegl_p.h" #include "qeglcontext_p.h" @@ -73,10 +74,14 @@ void QEglProperties::setPaintDeviceFormat(QPaintDevice *dev) return; int devType = dev->devType(); - if (devType == QInternal::Image) + if (devType == QInternal::Image) { setPixelFormat(static_cast<QImage *>(dev)->format()); - else - setPixelFormat(QImage::Format_RGB32); + } else { + QImage::Format format = QImage::Format_RGB32; + if (QApplicationPrivate::instance() && QApplicationPrivate::instance()->useTranslucentEGLSurfaces) + format = QImage::Format_ARGB32_Premultiplied; + setPixelFormat(format); + } } diff --git a/src/gui/embedded/qvfbhdr.h b/src/gui/embedded/qvfbhdr.h index 31704b3..84f82ac 100644 --- a/src/gui/embedded/qvfbhdr.h +++ b/src/gui/embedded/qvfbhdr.h @@ -53,36 +53,37 @@ QT_BEGIN_NAMESPACE QT_MODULE(Gui) #ifndef QT_QWS_TEMP_DIR -#define QT_QWS_TEMP_DIR "/tmp" +# define QT_QWS_TEMP_DIR QLatin1String("/tmp") #endif #ifdef QT_PRIVATE_QWS -#define QT_VFB_DATADIR(DISPLAY) QString("%1/qtembedded-%2-%3") \ - .arg(QT_QWS_TEMP_DIR).arg(getuid()).arg(DISPLAY) - +#define QT_VFB_DATADIR(DISPLAY) QString::fromLatin1("%1/qtembedded-%2-%3") \ + .arg(QT_QWS_TEMP_DIR).arg(getuid()).arg(DISPLAY) #define QT_VFB_MOUSE_PIPE(DISPLAY) QT_VFB_DATADIR(DISPLAY) \ - .append("/qtvfb_mouse") + .append(QLatin1String("/qtvfb_mouse")) #define QT_VFB_KEYBOARD_PIPE(DISPLAY) QT_VFB_DATADIR(DISPLAY) \ - .append("/qtvfb_keyboard") + .append(QLatin1String("/qtvfb_keyboard")) #define QT_VFB_MAP(DISPLAY) QT_VFB_DATADIR(DISPLAY) \ - .append("/qtvfb_map") + .append(QLatin1String("/qtvfb_map")) #define QT_VFB_SOUND_PIPE(DISPLAY) QT_VFB_DATADIR(DISPLAY) \ - .append("/qt_soundserver") + .append(QLatin1String("/qt_soundserver")) #define QTE_PIPE(DISPLAY) QT_VFB_DATADIR(DISPLAY) \ - .append("/QtEmbedded") + .append(QLatin1String("/QtEmbedded")) #define QTE_PIPE_QVFB(DISPLAY) QTE_PIPE(DISPLAY) #else -#define QT_VFB_DATADIR(DISPLAY) QString("%1/qtembedded-%2") \ - .arg(QT_QWS_TEMP_DIR).arg(DISPLAY) -#define QT_VFB_MOUSE_PIPE(DISPLAY) QString("/tmp/.qtvfb_mouse-%1").arg(DISPLAY) -#define QT_VFB_KEYBOARD_PIPE(DISPLAY) QString("/tmp/.qtvfb_keyboard-%1").arg(DISPLAY) -#define QT_VFB_MAP(DISPLAY) QString("/tmp/.qtvfb_map-%1").arg(DISPLAY) -#define QT_VFB_SOUND_PIPE(DISPLAY) QString("/tmp/.qt_soundserver-%1").arg(DISPLAY) -#define QTE_PIPE(DISPLAY) QT_VFB_DATADIR(DISPLAY) \ - .append("/QtEmbedded-%1") \ - .arg(DISPLAY) -#define QTE_PIPE_QVFB(DISPLAY) QString("/tmp/qtembedded-%1/QtEmbedded-%1") \ - .arg(DISPLAY) +#define QT_VFB_DATADIR(DISPLAY) QString::fromLatin1("%1/qtembedded-%2") \ + .arg(QT_QWS_TEMP_DIR).arg(DISPLAY) +#define QT_VFB_MOUSE_PIPE(DISPLAY) QString::fromLatin1("%1/.qtvfb_mouse-%2") \ + .arg(QT_QWS_TEMP_DIR).arg(DISPLAY) +#define QT_VFB_KEYBOARD_PIPE(DISPLAY) QString::fromLatin1("%1/.qtvfb_keyboard-%2") \ + .arg(QT_QWS_TEMP_DIR).arg(DISPLAY) +#define QT_VFB_MAP(DISPLAY) QString::fromLatin1("%1/.qtvfb_map-%2") \ + .arg(QT_QWS_TEMP_DIR).arg(DISPLAY) +#define QT_VFB_SOUND_PIPE(DISPLAY) QString::fromLatin1("%1/.qt_soundserver-%2") \ + .arg(QT_QWS_TEMP_DIR).arg(DISPLAY) +#define QTE_PIPE(DISPLAY) QT_VFB_DATADIR(DISPLAY) \ + .append(QLatin1String("/QtEmbedded-%1")).arg(DISPLAY) +#define QTE_PIPE_QVFB(DISPLAY) QTE_PIPE(DISPLAY) #endif struct QVFbHeader diff --git a/src/gui/graphicsview/qgraphicsanchorlayout.cpp b/src/gui/graphicsview/qgraphicsanchorlayout.cpp index 014b61b..9bb5424 100644 --- a/src/gui/graphicsview/qgraphicsanchorlayout.cpp +++ b/src/gui/graphicsview/qgraphicsanchorlayout.cpp @@ -56,7 +56,7 @@ Items that are anchored are automatically added to the layout, and if items are removed, all their anchors will be automatically removed. - \div {float-left} + \div {class="float-left"} \inlineimage simpleanchorlayout-example.png Using an anchor layout to align simple colored widgets. \enddiv diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp index 4e2d4e2..d51fdfe 100644 --- a/src/gui/graphicsview/qgraphicsitem.cpp +++ b/src/gui/graphicsview/qgraphicsitem.cpp @@ -421,7 +421,7 @@ \omitvalue ItemStopsFocusHandling \omit Same as ItemStopsClickFocusPropagation, but also suppresses focus-out. This flag allows you to completely take over focus handling. - This flag was introduced in Qt 4.7. + This flag was introduced in Qt 4.7. \endomit */ /*! @@ -579,19 +579,21 @@ QGraphicsItem pointer). The return value is unused; you cannot adjust anything in this notification. - \value ItemSceneChange The item is moved to a new scene. This notification - is also sent when the item is added to its initial scene, and when it is - removed. The value argument is the new scene (i.e., a QGraphicsScene + \value ItemSceneChange The item is moved to a new scene. This notification is + also sent when the item is added to its initial scene, and when it is removed. + The item's scene() is the old scene (or 0 if the item has not been added to a + scene yet). The value argument is the new scene (i.e., a QGraphicsScene pointer), or a null pointer if the item is removed from a scene. Do not - override this change by passing this item to QGraphicsScene::addItem() as - this notification is delivered; instead, you can return the new scene from + override this change by passing this item to QGraphicsScene::addItem() as this + notification is delivered; instead, you can return the new scene from itemChange(). Use this feature with caution; objecting to a scene change can quickly lead to unwanted recursion. - \value ItemSceneHasChanged The item's scene has changed. The value - argument is the new scene (i.e., a pointer to a QGraphicsScene). Do not - call setScene() in itemChange() as this notification is delivered. The - return value is ignored. + \value ItemSceneHasChanged The item's scene has changed. The item's scene() is + the new scene. This notification is also sent when the item is added to its + initial scene, and when it is removed.The value argument is the new scene + (i.e., a pointer to a QGraphicsScene). Do not call setScene() in itemChange() + as this notification is delivered. The return value is ignored. \value ItemCursorChange The item's cursor changes. The value argument is the new cursor (i.e., a QCursor). Do not call setCursor() in itemChange() @@ -5582,8 +5584,10 @@ void QGraphicsItemPrivate::setSubFocus(QGraphicsItem *rootItem, QGraphicsItem *s parent->d_ptr->subFocusItemChange(); } while (!parent->isPanel() && (parent = parent->d_ptr->parent) && (visible || !parent->d_ptr->visible)); - if (scene && !scene->isActive()) + if (scene && !scene->isActive()) { + scene->d_func()->passiveFocusItem = subFocusItem; scene->d_func()->lastFocusItem = subFocusItem; + } } /*! diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp index 2d85de6..c0a4bf9 100644 --- a/src/gui/graphicsview/qgraphicsscene.cpp +++ b/src/gui/graphicsview/qgraphicsscene.cpp @@ -306,6 +306,7 @@ QGraphicsScenePrivate::QGraphicsScenePrivate() rectAdjust(2), focusItem(0), lastFocusItem(0), + passiveFocusItem(0), tabFocusFirst(0), activePanel(0), lastActivePanel(0), @@ -630,6 +631,8 @@ void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item) focusItem = 0; if (item == lastFocusItem) lastFocusItem = 0; + if (item == passiveFocusItem) + passiveFocusItem = 0; if (item == activePanel) { // ### deactivate... activePanel = 0; @@ -2982,7 +2985,7 @@ void QGraphicsScene::removeItem(QGraphicsItem *item) QGraphicsItem *QGraphicsScene::focusItem() const { Q_D(const QGraphicsScene); - return isActive() ? d->focusItem : d->lastFocusItem; + return isActive() ? d->focusItem : d->passiveFocusItem; } /*! @@ -3056,6 +3059,7 @@ void QGraphicsScene::clearFocus() Q_D(QGraphicsScene); if (d->hasFocus) { d->hasFocus = false; + d->passiveFocusItem = d->focusItem; setFocusItem(0, Qt::OtherFocusReason); } } @@ -3758,9 +3762,9 @@ void QGraphicsScene::focusInEvent(QFocusEvent *focusEvent) focusEvent->ignore(); break; default: - if (d->lastFocusItem) { + if (d->passiveFocusItem) { // Set focus on the last focus item - setFocusItem(d->lastFocusItem, focusEvent->reason()); + setFocusItem(d->passiveFocusItem, focusEvent->reason()); } break; } @@ -3779,6 +3783,7 @@ void QGraphicsScene::focusOutEvent(QFocusEvent *focusEvent) { Q_D(QGraphicsScene); d->hasFocus = false; + d->passiveFocusItem = d->focusItem; setFocusItem(0, focusEvent->reason()); // Remove all popups when the scene loses focus. @@ -5978,9 +5983,6 @@ bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEve } if (item && item->isPanel()) break; - if (item && (item->d_ptr->flags - & (QGraphicsItem::ItemStopsClickFocusPropagation | QGraphicsItem::ItemStopsFocusHandling))) - break; } touchEvent->setAccepted(eventAccepted); diff --git a/src/gui/graphicsview/qgraphicsscene_p.h b/src/gui/graphicsview/qgraphicsscene_p.h index 815c70b..2b47105 100644 --- a/src/gui/graphicsview/qgraphicsscene_p.h +++ b/src/gui/graphicsview/qgraphicsscene_p.h @@ -150,6 +150,7 @@ public: quint32 rectAdjust; QGraphicsItem *focusItem; QGraphicsItem *lastFocusItem; + QGraphicsItem *passiveFocusItem; QGraphicsWidget *tabFocusFirst; QGraphicsItem *activePanel; QGraphicsItem *lastActivePanel; diff --git a/src/gui/graphicsview/qgraphicstransform.cpp b/src/gui/graphicsview/qgraphicstransform.cpp index 06df788..513c41f 100644 --- a/src/gui/graphicsview/qgraphicstransform.cpp +++ b/src/gui/graphicsview/qgraphicstransform.cpp @@ -92,6 +92,7 @@ #include "qgraphicstransform_p.h" #include <QDebug> #include <QtCore/qmath.h> +#include <QtCore/qnumeric.h> #ifndef QT_NO_GRAPHICSVIEW QT_BEGIN_NAMESPACE @@ -467,6 +468,7 @@ void QGraphicsRotation::setOrigin(const QVector3D &point) item will be rotated counter-clockwise. Normally the rotation angle will be in the range (-360, 360), but you can also provide numbers outside of this range (e.g., a angle of 370 degrees gives the same result as 10 degrees). + Setting the angle to NaN results in no rotation. \sa origin */ @@ -570,7 +572,7 @@ void QGraphicsRotation::applyTo(QMatrix4x4 *matrix) const { Q_D(const QGraphicsRotation); - if (d->angle == 0. || d->axis.isNull()) + if (d->angle == 0. || d->axis.isNull() || qIsNaN(d->angle)) return; matrix->translate(d->origin); diff --git a/src/gui/graphicsview/qgraphicsview.cpp b/src/gui/graphicsview/qgraphicsview.cpp index 2b129d7..16268a8 100644 --- a/src/gui/graphicsview/qgraphicsview.cpp +++ b/src/gui/graphicsview/qgraphicsview.cpp @@ -2498,7 +2498,7 @@ QVariant QGraphicsView::inputMethodQuery(Qt::InputMethodQuery query) const else if (value.type() == QVariant::PointF) value = mapFromScene(value.toPointF()); else if (value.type() == QVariant::Rect) - value = mapFromScene(value.toRect()).boundingRect(); + value = d->mapRectFromScene(value.toRect()).toRect(); else if (value.type() == QVariant::Point) value = mapFromScene(value.toPoint()); return value; diff --git a/src/gui/gui.pro b/src/gui/gui.pro index 4d51fa8..cf492d6 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -55,11 +55,9 @@ DEFINES += Q_INTERNAL_QAPP_SRC symbian { TARGET.UID3=0x2001B2DD - symbian-abld|symbian-sbsv2 { - # ro-section in gui can exceed default allocated space, so move rw-section a little further - QMAKE_LFLAGS.ARMCC += --rw-base 0x800000 - QMAKE_LFLAGS.GCCE += -Tdata 0xC00000 - } + # ro-section in gui can exceed default allocated space, so move rw-section a little further + QMAKE_LFLAGS.ARMCC += --rw-base 0x800000 + QMAKE_LFLAGS.GCCE += -Tdata 0x800000 } neon:*-g++* { diff --git a/src/gui/image/qicon.cpp b/src/gui/image/qicon.cpp index d0cc937..59c384a 100644 --- a/src/gui/image/qicon.cpp +++ b/src/gui/image/qicon.cpp @@ -964,12 +964,15 @@ QString QIcon::themeName() Returns the QIcon corresponding to \a name in the current icon theme. If no such icon is found in the current theme - \a fallback is return instead. + \a fallback is returned instead. - The lastest version of the freedesktop icon specification and naming - spesification can be obtained here: - http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html - http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html + The latest version of the freedesktop icon specification and naming + specification can be obtained here: + + \list + \o \l{http://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html} + \o \l{http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html} + \endlist To fetch an icon from the current icon theme: diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp index 168c518..441bdb1 100644 --- a/src/gui/image/qimage.cpp +++ b/src/gui/image/qimage.cpp @@ -833,6 +833,8 @@ QImage::QImage() Constructs an image with the given \a width, \a height and \a format. + A \l{isNull()}{null} image will be returned if memory cannot be allocated. + \warning This will create a QImage with uninitialized data. Call fill() to fill the image with an appropriate pixel value before drawing onto it with QPainter. @@ -846,6 +848,8 @@ QImage::QImage(int width, int height, Format format) /*! Constructs an image with the given \a size and \a format. + A \l{isNull()}{null} image is returned if memory cannot be allocated. + \warning This will create a QImage with uninitialized data. Call fill() to fill the image with an appropriate pixel value before drawing onto it with QPainter. diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp index 1fa1058..e7b1000 100644 --- a/src/gui/image/qimagereader.cpp +++ b/src/gui/image/qimagereader.cpp @@ -1482,6 +1482,9 @@ QByteArray QImageReader::imageFormat(QIODevice *device) configure script or check the appropriate option in the graphical installer. + Note that the QApplication instance must be created before this function is + called. + \sa setFormat(), QImageWriter::supportedImageFormats(), QImageIOPlugin */ QList<QByteArray> QImageReader::supportedImageFormats() diff --git a/src/gui/image/qimagewriter.cpp b/src/gui/image/qimagewriter.cpp index 8a65ac0..504260a 100644 --- a/src/gui/image/qimagewriter.cpp +++ b/src/gui/image/qimagewriter.cpp @@ -679,6 +679,9 @@ bool QImageWriter::supportsOption(QImageIOHandler::ImageOption option) const Reading and writing SVG files is supported through Qt's \l{QtSvg Module}{SVG Module}. + Note that the QApplication instance must be created before this function is + called. + \sa setFormat(), QImageReader::supportedImageFormats(), QImageIOPlugin */ QList<QByteArray> QImageWriter::supportedImageFormats() diff --git a/src/gui/image/qpixmap_s60.cpp b/src/gui/image/qpixmap_s60.cpp index ca5f133..32d8dd7 100644 --- a/src/gui/image/qpixmap_s60.cpp +++ b/src/gui/image/qpixmap_s60.cpp @@ -374,6 +374,8 @@ CFbsBitmap *QPixmap::toSymbianCFbsBitmap() const To be sure that QPixmap does not modify your original instance, you should make a copy of your \c CFbsBitmap before calling this function. If the CFbsBitmap is not valid this function will return a null QPixmap. + For performance reasons it is recommended to use a \a bitmap with a display + mode of EColor16MAP or EColor16MU whenever possible. \warning This function is only available on Symbian OS. @@ -599,6 +601,9 @@ bool QS60PixmapData::scroll(int dx, int dy, const QRect &rect) return res; } +Q_GUI_EXPORT int qt_defaultDpiX(); +Q_GUI_EXPORT int qt_defaultDpiY(); + int QS60PixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const { if (!cfbsBitmap) @@ -609,28 +614,18 @@ int QS60PixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const return cfbsBitmap->SizeInPixels().iWidth; case QPaintDevice::PdmHeight: return cfbsBitmap->SizeInPixels().iHeight; - case QPaintDevice::PdmWidthMM: { - TInt twips = cfbsBitmap->SizeInTwips().iWidth; - return (int)(twips * (25.4/KTwipsPerInch)); - } - case QPaintDevice::PdmHeightMM: { - TInt twips = cfbsBitmap->SizeInTwips().iHeight; - return (int)(twips * (25.4/KTwipsPerInch)); - } + case QPaintDevice::PdmWidthMM: + return qRound(cfbsBitmap->SizeInPixels().iWidth * 25.4 / qt_defaultDpiX()); + case QPaintDevice::PdmHeightMM: + return qRound(cfbsBitmap->SizeInPixels().iHeight * 25.4 / qt_defaultDpiY()); case QPaintDevice::PdmNumColors: return TDisplayModeUtils::NumDisplayModeColors(cfbsBitmap->DisplayMode()); case QPaintDevice::PdmDpiX: - case QPaintDevice::PdmPhysicalDpiX: { - TReal inches = cfbsBitmap->SizeInTwips().iWidth / (TReal)KTwipsPerInch; - TInt pixels = cfbsBitmap->SizeInPixels().iWidth; - return pixels / inches; - } + case QPaintDevice::PdmPhysicalDpiX: + return qt_defaultDpiX(); case QPaintDevice::PdmDpiY: - case QPaintDevice::PdmPhysicalDpiY: { - TReal inches = cfbsBitmap->SizeInTwips().iHeight / (TReal)KTwipsPerInch; - TInt pixels = cfbsBitmap->SizeInPixels().iHeight; - return pixels / inches; - } + case QPaintDevice::PdmPhysicalDpiY: + return qt_defaultDpiY(); case QPaintDevice::PdmDepth: return TDisplayModeUtils::NumDisplayModeBitsPerPixel(cfbsBitmap->DisplayMode()); default: diff --git a/src/gui/image/qvolatileimagedata_symbian.cpp b/src/gui/image/qvolatileimagedata_symbian.cpp index 474d0ef..6e2909b 100644 --- a/src/gui/image/qvolatileimagedata_symbian.cpp +++ b/src/gui/image/qvolatileimagedata_symbian.cpp @@ -392,6 +392,9 @@ void QVolatileImageData::initWithBitmap(CFbsBitmap *source) } else if (needsCopy) { // Rasterize extended and compressed bitmaps. bitmap = rasterizeBitmap(source, EColor16MAP); + } else if (source->DisplayMode() == EGray2) { + // The pixels will be inverted, must make a copy. + bitmap = rasterizeBitmap(source, source->DisplayMode()); } else { // Efficient path: no pixel data copying. Just duplicate. This of course // means the original bitmap's data may get modified, but that's fine diff --git a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp index cd4e2fd..92f8384 100644 --- a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp +++ b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp @@ -77,6 +77,15 @@ QT_BEGIN_NAMESPACE Q_GUI_EXPORT void qt_s60_setPartialScreenInputMode(bool enable) { S60->partial_keyboard = enable; + + QInputContext *ic = 0; + if (QApplication::focusWidget()) { + ic = QApplication::focusWidget()->inputContext(); + } else if (qApp && qApp->inputContext()) { + ic = qApp->inputContext(); + } + if (ic) + ic->update(); } QCoeFepInputContext::QCoeFepInputContext(QObject *parent) @@ -108,7 +117,7 @@ QCoeFepInputContext::QCoeFepInputContext(QObject *parent) m_fepState->SetDefaultCase( EAknEditorTextCase ); m_fepState->SetPermittedCases( EAknEditorAllCaseModes ); m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_SPECIAL_CHARACTER_TABLE_DIALOG); - m_fepState->SetNumericKeymap( EAknEditorStandardNumberModeKeymap ); + m_fepState->SetNumericKeymap(EAknEditorAlphanumericNumberModeKeymap); } QCoeFepInputContext::~QCoeFepInputContext() @@ -231,7 +240,7 @@ bool QCoeFepInputContext::filterEvent(const QEvent *event) // It ignores the mouse event, so we need to commit and send a selection event (which will get triggered // after the commit) if (!m_preeditString.isEmpty()) { - commitCurrentString(false); + commitCurrentString(true); int pos = focusWidget()->inputMethodQuery(Qt::ImCursorPosition).toInt(); @@ -330,23 +339,20 @@ bool QCoeFepInputContext::symbianFilterEvent(QWidget *keyWidget, const QSymbianE // This should also happen for commands. reset(); - // We need to translate the window content when window becomes available. Changing the window while it is - // not yet ready with OpenVg graphicssystem results in operations silently failing. + if (event->type() == QSymbianEvent::WindowServerEvent + && event->windowServerEvent() + && event->windowServerEvent()->Type() == EEventWindowVisibilityChanged + && S60->splitViewLastWidget) { + + QGraphicsView *gv = qobject_cast<QGraphicsView*>(S60->splitViewLastWidget); + const bool alwaysResize = (gv && gv->verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff); - if (event->windowServerEvent() && event->windowServerEvent()->Type() == EEventWindowVisibilityChanged) { - if (S60->splitViewLastWidget) { - QGraphicsView *gv = qobject_cast<QGraphicsView*>(S60->splitViewLastWidget); - const bool alwaysResize = (gv && gv->verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff); + if (alwaysResize) { TUint visibleFlags = event->windowServerEvent()->VisibilityChanged()->iFlags; - if (!alwaysResize) { - if (visibleFlags & TWsVisibilityChangedEvent::EPartiallyVisible) { - if (!isWidgetVisible(S60->splitViewLastWidget)) { - ensureFocusWidgetVisible(S60->splitViewLastWidget); - } - } else if (visibleFlags & TWsVisibilityChangedEvent::ENotVisible) { - resetSplitViewWidget(true); - } - } + if (visibleFlags & TWsVisibilityChangedEvent::EPartiallyVisible) + ensureFocusWidgetVisible(S60->splitViewLastWidget); + if (visibleFlags & TWsVisibilityChangedEvent::ENotVisible) + resetSplitViewWidget(true); } } @@ -402,24 +408,27 @@ void QCoeFepInputContext::resetSplitViewWidget(bool keepInputWidget) return; } - QSymbianControl *symControl = static_cast<QSymbianControl*>(S60->splitViewLastWidget->effectiveWinId()); + QSymbianControl *symControl = static_cast<QSymbianControl*>(gv->effectiveWinId()); symControl->CancelLongTapTimer(); - const bool alwaysResize = (gv && gv->verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff); - QWidget *windowToMove = gv ? gv : symControl->widget(); - if (!S60->splitViewLastWidget->isWindow()) - windowToMove = S60->splitViewLastWidget->window(); + const bool alwaysResize = (gv->verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff); + QWidget *windowToMove = gv->window(); - bool userResize = S60->splitViewLastWidget->testAttribute(Qt::WA_Resized); - bool userMove = windowToMove->testAttribute(Qt::WA_Moved); + bool userResize = gv->testAttribute(Qt::WA_Resized); - if (gv) - windowToMove->setUpdatesEnabled(false); + windowToMove->setUpdatesEnabled(false); + + if (!alwaysResize) { + if (gv->scene()) { + if (gv->scene()->focusItem()) { + // Check if the widget contains cursorPositionChanged signal and disconnect from it. + QByteArray signal = QMetaObject::normalizedSignature(SIGNAL(cursorPositionChanged())); + int index = gv->scene()->focusItem()->toGraphicsObject()->metaObject()->indexOfSignal(signal.right(signal.length() - 1)); + if (index != -1) + disconnect(gv->scene()->focusItem()->toGraphicsObject(), SIGNAL(cursorPositionChanged()), this, SLOT(translateInputWidget())); + } - if (gv && !alwaysResize) { - disconnect(gv->scene()->focusItem()->toGraphicsObject(), SIGNAL(cursorPositionChanged()), this, SLOT(translateInputWidget())); - if (gv && gv->scene()) { - QGraphicsItem *rootItem; + QGraphicsItem *rootItem = 0; foreach (QGraphicsItem *item, gv->scene()->items()) { if (!item->parentItem()) { rootItem = item; @@ -429,21 +438,19 @@ void QCoeFepInputContext::resetSplitViewWidget(bool keepInputWidget) if (rootItem) rootItem->resetTransform(); } + } else { + if (m_splitViewResizeBy) + gv->resize(gv->rect().width(), m_splitViewResizeBy); } - // Resizing might have led to widget losing its original windowstate. // Restore previous window state. if (m_splitViewPreviousWindowStates != windowToMove->windowState()) windowToMove->setWindowState(m_splitViewPreviousWindowStates); - if (m_splitViewResizeBy) - S60->splitViewLastWidget->updateGeometry(); - if (gv) - windowToMove->setUpdatesEnabled(true); + windowToMove->setUpdatesEnabled(true); - S60->splitViewLastWidget->setAttribute(Qt::WA_Resized, userResize); //not a user resize - windowToMove->setAttribute(Qt::WA_Moved, userMove); //not a user move + gv->setAttribute(Qt::WA_Resized, userResize); //not a user resize m_splitViewResizeBy = 0; if (!keepInputWidget) { @@ -509,6 +516,13 @@ void QCoeFepInputContext::ensureFocusWidgetVisible(QWidget *widget) // states getting changed. if (!moveWithinVisibleArea) { + // Check if the widget contains cursorPositionChanged signal and connect to it. + QByteArray signal = QMetaObject::normalizedSignature(SIGNAL(cursorPositionChanged())); + if (gv->scene() && gv->scene()->focusItem()) { + int index = gv->scene()->focusItem()->toGraphicsObject()->metaObject()->indexOfSignal(signal.right(signal.length() - 1)); + if (index != -1) + connect(gv->scene()->focusItem()->toGraphicsObject(), SIGNAL(cursorPositionChanged()), this, SLOT(translateInputWidget())); + } S60->splitViewLastWidget = widget; m_splitViewPreviousWindowStates = windowToMove->windowState(); } @@ -516,50 +530,43 @@ void QCoeFepInputContext::ensureFocusWidgetVisible(QWidget *widget) int windowTop = widget->window()->pos().y(); const bool userResize = widget->testAttribute(Qt::WA_Resized); - const bool userMove = windowToMove->testAttribute(Qt::WA_Moved); QRect splitViewRect = qt_TRect2QRect(static_cast<CEikAppUi*>(S60->appUi())->ClientRect()); - if (gv) { - // When resizing a window widget, it will lose its maximized window state. - // Native applications hide statuspane in splitview state, so lets move to - // fullscreen mode. This makes available area slightly bigger, which helps usability - // and greatly reduces event passing in orientation switch cases, - // as the statuspane size is not changing. + // When resizing a window widget, it will lose its maximized window state. + // Native applications hide statuspane in splitview state, so lets move to + // fullscreen mode. This makes available area slightly bigger, which helps usability + // and greatly reduces event passing in orientation switch cases, + // as the statuspane size is not changing. - if (!(windowToMove->windowState() & Qt::WindowFullScreen)) { - widget->setWindowState( - (windowToMove->windowState() & ~(Qt::WindowMinimized | Qt::WindowFullScreen)) | Qt::WindowFullScreen); - } + if (alwaysResize) + windowToMove->setUpdatesEnabled(false); - if (alwaysResize) { - windowToMove->setUpdatesEnabled(false); - if (!moveWithinVisibleArea) - m_splitViewResizeBy = widget->height(); + if (!(windowToMove->windowState() & Qt::WindowFullScreen)) { + windowToMove->setWindowState( + (windowToMove->windowState() & ~(Qt::WindowMinimized | Qt::WindowFullScreen)) | Qt::WindowFullScreen); + } + if (alwaysResize) { + if (!moveWithinVisibleArea) { + m_splitViewResizeBy = widget->height(); windowTop = widget->geometry().top(); widget->resize(widget->width(), splitViewRect.height() - windowTop); + } - if (gv && gv->scene()) { - const QRectF microFocusRect = gv->scene()->inputMethodQuery(Qt::ImMicroFocus).toRectF(); - gv->ensureVisible(microFocusRect); - } - windowToMove->setUpdatesEnabled(true); - } else { - if (!moveWithinVisibleArea) { - // Check if the widget contains cursorPositionChanged signal and connect to it. - const char *signal = QMetaObject::normalizedSignature(SIGNAL(cursorPositionChanged())).constData(); - int index = gv->scene()->focusItem()->toGraphicsObject()->metaObject()->indexOfSignal(signal + 1); - if (index != -1) - connect(gv->scene()->focusItem()->toGraphicsObject(), SIGNAL(cursorPositionChanged()), this, SLOT(translateInputWidget())); - } - translateInputWidget(); + if (gv->scene()) { + const QRectF microFocusRect = gv->scene()->inputMethodQuery(Qt::ImMicroFocus).toRectF(); + gv->ensureVisible(microFocusRect); } + } else { + translateInputWidget(); } + if (alwaysResize) + windowToMove->setUpdatesEnabled(true); + widget->setAttribute(Qt::WA_Resized, userResize); //not a user resize - windowToMove->setAttribute(Qt::WA_Moved, userMove); //not a user move } static QTextCharFormat qt_TCharFormat2QTextCharFormat(const TCharFormat &cFormat, bool validStyleColor) @@ -582,6 +589,19 @@ void QCoeFepInputContext::updateHints(bool mustUpdateInputCapabilities) QWidget *w = focusWidget(); if (w) { Qt::InputMethodHints hints = w->inputMethodHints(); + + // Since splitview support works like an input method hint, yet it is private flag, + // we need to update its state separately. + if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0) { + TInt currentFlags = m_fepState->Flags(); + if (S60->partial_keyboard) + currentFlags |= QT_EAknEditorFlagEnablePartialScreen; + else + currentFlags &= ~QT_EAknEditorFlagEnablePartialScreen; + if (currentFlags != m_fepState->Flags()) + m_fepState->SetFlags(currentFlags); + } + if (hints != m_lastImHints) { m_lastImHints = hints; applyHints(hints); @@ -734,6 +754,8 @@ void QCoeFepInputContext::applyHints(Qt::InputMethodHints hints) m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_EMAIL_ADDR_SPECIAL_CHARACTER_TABLE_DIALOG); } else if (needsCharMap) { m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_SPECIAL_CHARACTER_TABLE_DIALOG); + } else if ((hints & ImhFormattedNumbersOnly) || (hints & ImhDialableCharactersOnly)) { + m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_SPECIAL_CHARACTER_TABLE_DIALOG); } else { m_fepState->SetSpecialCharacterTableResourceId(0); } @@ -837,7 +859,7 @@ void QCoeFepInputContext::translateInputWidget() return; // Fetch root item (i.e. graphicsitem with no parent) - QGraphicsItem *rootItem; + QGraphicsItem *rootItem = 0; foreach (QGraphicsItem *item, gv->scene()->items()) { if (!item->parentItem()) { rootItem = item; @@ -856,7 +878,7 @@ void QCoeFepInputContext::translateInputWidget() // New Y position should be ideally at the center of the splitview area. // If that would expose unpainted canvas, limit the tranformation to the visible scene bottom. - const qreal maxY = gv->sceneRect().bottom() - splitViewRect.bottom() + m_transformation.height(); + const qreal maxY = gv->sceneRect().bottom() - splitViewRect.bottom() + m_transformation.height(); qreal dy = -(qMin(maxY, (cursor.bottom() - vkbRect.top() / 2))); // Do not allow transform above screen top. diff --git a/src/gui/inputmethod/qinputcontext.cpp b/src/gui/inputmethod/qinputcontext.cpp index 063aefd..f083e51 100644 --- a/src/gui/inputmethod/qinputcontext.cpp +++ b/src/gui/inputmethod/qinputcontext.cpp @@ -355,9 +355,10 @@ void QInputContext::widgetDestroyed(QWidget *widget) in complex input method. In the case, call QInputContext::reset() to ensure proper termination of inputting. - You must not send any QInputMethodEvent except empty InputMethodEnd event using - QInputContext::reset() at reimplemented reset(). It will break - input state consistency. + In a reimplementation of reset(), you must not send any + QInputMethodEvent containing preedit text. You can only commit + string and attributes; otherwise, you risk breaking input state + consistency. */ diff --git a/src/gui/itemviews/qheaderview.cpp b/src/gui/itemviews/qheaderview.cpp index c857670..2ccf792 100644 --- a/src/gui/itemviews/qheaderview.cpp +++ b/src/gui/itemviews/qheaderview.cpp @@ -643,8 +643,12 @@ int QHeaderView::sectionSize(int logicalIndex) const } /*! - Returns the section position of the given \a logicalIndex, or -1 if the - section is hidden. + + Returns the section position of the given \a logicalIndex, or -1 + if the section is hidden. The position is measured in pixels from + the first visible item's top-left corner to the top-left corner of + the item with \a logicalIndex. The measurement is along the x-axis + for horizontal headers and along the y-axis for vertical headers. \sa sectionViewportPosition() */ diff --git a/src/gui/itemviews/qlistwidget.cpp b/src/gui/itemviews/qlistwidget.cpp index 94e3b76..61a935f 100644 --- a/src/gui/itemviews/qlistwidget.cpp +++ b/src/gui/itemviews/qlistwidget.cpp @@ -1500,7 +1500,9 @@ void QListWidget::setCurrentRow(int row, QItemSelectionModel::SelectionFlags com } /*! - Returns a pointer to the item at the coordinates \a p. + Returns a pointer to the item at the coordinates \a p. The coordinates + are relative to the list widget's \l{QAbstractScrollArea::}{viewport()}. + */ QListWidgetItem *QListWidget::itemAt(const QPoint &p) const { @@ -1514,6 +1516,9 @@ QListWidgetItem *QListWidget::itemAt(const QPoint &p) const \overload Returns a pointer to the item at the coordinates (\a x, \a y). + The coordinates are relative to the list widget's + \l{QAbstractScrollArea::}{viewport()}. + */ diff --git a/src/gui/itemviews/qstyleditemdelegate.cpp b/src/gui/itemviews/qstyleditemdelegate.cpp index 0d1473d..eb54bac 100644 --- a/src/gui/itemviews/qstyleditemdelegate.cpp +++ b/src/gui/itemviews/qstyleditemdelegate.cpp @@ -263,6 +263,11 @@ QStyledItemDelegate::~QStyledItemDelegate() The default implementation uses the QLocale::toString to convert \a value into a QString. + + This function is not called for empty model indices, i.e., indices for which + the model returns an invalid QVariant. + + \sa QAbstractItemModel::data() */ QString QStyledItemDelegate::displayText(const QVariant &value, const QLocale& locale) const { diff --git a/src/gui/itemviews/qtreewidget.cpp b/src/gui/itemviews/qtreewidget.cpp index 4db29d6..2ea9a43 100644 --- a/src/gui/itemviews/qtreewidget.cpp +++ b/src/gui/itemviews/qtreewidget.cpp @@ -2830,7 +2830,8 @@ void QTreeWidget::setCurrentItem(QTreeWidgetItem *item, int column, /*! - Returns a pointer to the item at the coordinates \a p. + Returns a pointer to the item at the coordinates \a p. The coordinates + are relative to the tree widget's \l{QAbstractScrollArea::}{viewport()}. \sa visualItemRect() */ @@ -2844,7 +2845,8 @@ QTreeWidgetItem *QTreeWidget::itemAt(const QPoint &p) const \fn QTreeWidgetItem *QTreeWidget::itemAt(int x, int y) const \overload - Returns a pointer to the item at the coordinates (\a x, \a y). + Returns a pointer to the item at the coordinates (\a x, \a y). The coordinates + are relative to the tree widget's \l{QAbstractScrollArea::}{viewport()}. */ /*! diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index f9c84c1..467eb9b 100644 --- a/src/gui/kernel/kernel.pri +++ b/src/gui/kernel/kernel.pri @@ -111,6 +111,8 @@ win32 { } symbian { + exists($${EPOCROOT}epoc32/include/platform/mw/akntranseffect.h): DEFINES += QT_SYMBIAN_HAVE_AKNTRANSEFFECT_H + SOURCES += \ kernel/qapplication_s60.cpp \ kernel/qeventdispatcher_s60.cpp \ diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 59aec91..f906bbf 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -128,6 +128,10 @@ extern bool qt_wince_is_pocket_pc(); //qguifunctions_wince.cpp //#define ALIEN_DEBUG +#if defined(Q_OS_SYMBIAN) +#include "qt_s60_p.h" +#endif + static void initResources() { #if defined(Q_WS_WINCE) @@ -2432,6 +2436,11 @@ bool QApplication::event(QEvent *e) { Q_D(QApplication); if(e->type() == QEvent::Close) { +#if defined(Q_OS_SYMBIAN) + // In order to have proper application-exit effects on Symbian, certain + // native APIs have to be called _before_ closing/destroying the widgets. + bool effectStarted = qt_beginFullScreenEffect(); +#endif QCloseEvent *ce = static_cast<QCloseEvent*>(e); ce->accept(); closeAllWindows(); @@ -2445,8 +2454,14 @@ bool QApplication::event(QEvent *e) break; } } - if(ce->isAccepted()) + if (ce->isAccepted()) { return true; + } else { +#if defined(Q_OS_SYMBIAN) + if (effectStarted) + qt_abortFullScreenEffect(); +#endif + } } else if(e->type() == QEvent::LanguageChange) { #ifndef QT_NO_TRANSLATION setLayoutDirection(qt_detectRTLLanguage()?Qt::RightToLeft:Qt::LeftToRight); diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h index 43634ef..3d2c9d6 100644 --- a/src/gui/kernel/qapplication_p.h +++ b/src/gui/kernel/qapplication_p.h @@ -599,6 +599,8 @@ public: int pressureSupported; int maxTouchPressure; QList<QTouchEvent::TouchPoint> appAllTouchPoints; + + bool useTranslucentEGLSurfaces; #endif private: diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index 6e43c8b..6620efd 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -100,7 +100,6 @@ static const int KGoomMemoryGoodEvent = 0x20026790; static const int KSplitViewOpenEvent = 0x2001E2C0; static const int KSplitViewCloseEvent = 0x2001E2C1; - #if defined(QT_DEBUG) static bool appNoGrab = false; // Grabbing enabled #endif @@ -143,6 +142,60 @@ void QS60Data::setStatusPaneAndButtonGroupVisibility(bool statusPaneVisible, boo // Ensure that control rectangle is updated static_cast<QSymbianControl *>(QApplication::activeWindow()->winId())->handleClientAreaChange(); } + +bool QS60Data::setRecursiveDecorationsVisibility(QWidget *window, Qt::WindowStates newState) +{ + // Show statusbar: + // Topmost parent: Show unless fullscreen/minimized. + // Child windows: Follow topmost parent, unless fullscreen, in which case do not show statusbar + // Show CBA: + // Topmost parent: Show unless fullscreen/minimized. + // Exception: Show if fullscreen with Qt::WindowSoftkeysVisibleHint. + // Child windows: + // Minimized: Unclear if there is an use case for having focused minimized window at all. + // Always follow topmost parent just to be safe. + // Maximized and normal: follow topmost parent. + // Exception: If topmost parent is not showing CBA, show CBA if any softkey actions are + // defined. + // Fullscreen: Show only if Qt::WindowSoftkeysVisibleHint set. + + Qt::WindowStates comparisonState = newState; + QWidget *parentWindow = window->parentWidget(); + if (parentWindow) { + while (parentWindow->parentWidget()) + parentWindow = parentWindow->parentWidget(); + comparisonState = parentWindow->windowState(); + } else { + parentWindow = window; + } + + bool decorationsVisible = !(comparisonState & (Qt::WindowFullScreen | Qt::WindowMinimized)); + const bool parentIsFullscreen = comparisonState & Qt::WindowFullScreen; + const bool parentCbaVisibilityHint = parentWindow->windowFlags() & Qt::WindowSoftkeysVisibleHint; + bool buttonGroupVisibility = (decorationsVisible || (parentIsFullscreen && parentCbaVisibilityHint)); + + // Do extra checking for child windows + if (window->parentWidget()) { + if (newState & Qt::WindowFullScreen) { + decorationsVisible = false; + if (window->windowFlags() & Qt::WindowSoftkeysVisibleHint) + buttonGroupVisibility = true; + else + buttonGroupVisibility = false; + } else if (!(newState & Qt::WindowMinimized) && !buttonGroupVisibility) { + for (int i = 0; i < window->actions().size(); ++i) { + if (window->actions().at(i)->softKeyRole() != QAction::NoSoftKey) { + buttonGroupVisibility = true; + break; + } + } + } + } + + S60->setStatusPaneAndButtonGroupVisibility(decorationsVisible, buttonGroupVisibility); + + return decorationsVisible; +} #endif void QS60Data::controlVisibilityChanged(CCoeControl *control, bool visible) @@ -162,6 +215,12 @@ void QS60Data::controlVisibilityChanged(CCoeControl *control, bool visible) widget->repaint(); } } else { + // In certain special scenarios we may get an ENotVisible event + // without a previous EPartiallyVisible. The backingstore must + // still be destroyed, hence the registerWidget() call below. + if (backingStore.data() && widget->internalWinId() + && qt_widget_private(widget)->maybeBackingStore() == backingStore.data()) + backingStore.registerWidget(widget); backingStore.unregisterWidget(widget); // In order to ensure that any resources used by the window surface // are immediately freed, we flush the WSERV command buffer. @@ -406,6 +465,7 @@ QSymbianControl::QSymbianControl(QWidget *w) , m_ignoreFocusChanged(0) , m_symbianPopupIsOpen(0) , m_inExternalScreenOverride(false) + , m_lastStatusPaneVisibility(0) { } @@ -492,11 +552,52 @@ void QSymbianControl::setWidget(QWidget *w) { qwidget = w; } + +QPoint QSymbianControl::translatePointForFixedNativeOrientation(const TPoint &pointerEventPos) const +{ + QPoint pos(pointerEventPos.iX, pointerEventPos.iY); + if (qwidget->d_func()->fixNativeOrientationCalled) { + QSize wsize = qwidget->size(); + TSize size = Size(); + if (size.iWidth == wsize.height() && size.iHeight == wsize.width()) { + qreal x = pos.x(); + qreal y = pos.y(); + pos.setX(size.iHeight - y); + pos.setY(x); + } + } + return pos; +} + +TRect QSymbianControl::translateRectForFixedNativeOrientation(const TRect &controlRect) const +{ + TRect rect = controlRect; + if (qwidget->d_func()->fixNativeOrientationCalled) { + QPoint a = translatePointForFixedNativeOrientation(rect.iTl); + QPoint b = translatePointForFixedNativeOrientation(rect.iBr); + if (a.x() < b.x()) { + rect.iTl.iX = a.x(); + rect.iBr.iX = b.x(); + } else { + rect.iTl.iX = b.x(); + rect.iBr.iX = a.x(); + } + if (a.y() < b.y()) { + rect.iTl.iY = a.y(); + rect.iBr.iY = b.y(); + } else { + rect.iTl.iY = b.y(); + rect.iBr.iY = a.y(); + } + } + return rect; +} + void QSymbianControl::HandleLongTapEventL( const TPoint& aPenEventLocation, const TPoint& aPenEventScreenLocation ) { QWidget *alienWidget; - QPoint widgetPos = QPoint(aPenEventLocation.iX, aPenEventLocation.iY); - QPoint globalPos = QPoint(aPenEventScreenLocation.iX,aPenEventScreenLocation.iY); + QPoint widgetPos = translatePointForFixedNativeOrientation(aPenEventLocation); + QPoint globalPos = translatePointForFixedNativeOrientation(aPenEventScreenLocation); alienWidget = qwidget->childAt(widgetPos); if (!alienWidget) alienWidget = qwidget; @@ -511,7 +612,7 @@ void QSymbianControl::HandleLongTapEventL( const TPoint& aPenEventLocation, cons void QSymbianControl::translateAdvancedPointerEvent(const TAdvancedPointerEvent *event) { QApplicationPrivate *d = QApplicationPrivate::instance(); - QPointF screenPos = qwidget->mapToGlobal(QPoint(event->iPosition.iX, event->iPosition.iY)); + QPointF screenPos = qwidget->mapToGlobal(translatePointForFixedNativeOrientation(event->iPosition)); qreal pressure; if(d->pressureSupported && event->Pressure() > 0) //workaround for misconfigured HAL @@ -612,7 +713,7 @@ void QSymbianControl::HandlePointerEvent(const TPointerEvent& pEvent) mapS60MouseEventTypeToQt(&type, &button, &pEvent); Qt::KeyboardModifiers modifiers = mapToQtModifiers(pEvent.iModifiers); - QPoint widgetPos = QPoint(pEvent.iPosition.iX, pEvent.iPosition.iY); + QPoint widgetPos = translatePointForFixedNativeOrientation(pEvent.iPosition); TPoint controlScreenPos = PositionRelativeToScreen(); QPoint globalPos = QPoint(controlScreenPos.iX, controlScreenPos.iY) + widgetPos; S60->lastCursorPos = globalPos; @@ -1078,6 +1179,9 @@ void QSymbianControl::Draw(const TRect& controlRect) const Q_ASSERT(window); QTLWExtra *topExtra = window->d_func()->maybeTopData(); Q_ASSERT(topExtra); + + TRect wcontrolRect = translateRectForFixedNativeOrientation(controlRect); + if (!topExtra->inExpose) { topExtra->inExpose = true; if (!qwidget->isWindow()) { @@ -1088,7 +1192,7 @@ void QSymbianControl::Draw(const TRect& controlRect) const gc.SetBrushColor(TRgb(0, 0, 0, 0)); gc.Clear(controlRect); } - QRect exposeRect = qt_TRect2QRect(controlRect); + QRect exposeRect = qt_TRect2QRect(wcontrolRect); qwidget->d_func()->syncBackingStore(exposeRect); topExtra->inExpose = false; } @@ -1101,7 +1205,7 @@ void QSymbianControl::Draw(const TRect& controlRect) const const bool sendNativePaintEvents = qwidget->d_func()->extraData()->receiveNativePaintEvents; if (sendNativePaintEvents) { - const QRect r = qt_TRect2QRect(controlRect); + const QRect r = qt_TRect2QRect(wcontrolRect); QMetaObject::invokeMethod(qwidget, "beginNativePaintEvent", Qt::DirectConnection, Q_ARG(QRect, r)); } @@ -1133,7 +1237,8 @@ void QSymbianControl::Draw(const TRect& controlRect) const // Do nothing break; case QWExtra::Blit: - if (qwidget->d_func()->isOpaque) + case QWExtra::BlitWriteAlpha: + if (qwidget->d_func()->isOpaque || nativePaintMode == QWExtra::BlitWriteAlpha) gc.SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha); gc.BitBlt(controlRect.iTl, bitmap, backingStoreRect); break; @@ -1155,7 +1260,7 @@ void QSymbianControl::Draw(const TRect& controlRect) const } if (sendNativePaintEvents) { - const QRect r = qt_TRect2QRect(controlRect); + const QRect r = qt_TRect2QRect(wcontrolRect); // The draw ops aren't actually sent to WSERV until the graphics // context is deactivated, which happens in the function calling // this one. We therefore delay the delivery of endNativePaintEvent, @@ -1168,14 +1273,45 @@ void QSymbianControl::Draw(const TRect& controlRect) const } } +void QSymbianControl::qwidgetResize_helper(const QSize &newSize) +{ + QRect cr = qwidget->geometry(); + QSize oldSize(cr.size()); + cr.setSize(newSize); + qwidget->data->crect = cr; + if (qwidget->isVisible()) { + QTLWExtra *tlwExtra = qwidget->d_func()->maybeTopData(); + bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt(); + if (!slowResize && tlwExtra) + tlwExtra->inTopLevelResize = true; + QResizeEvent e(newSize, oldSize); + qt_sendSpontaneousEvent(qwidget, &e); + if (!qwidget->testAttribute(Qt::WA_StaticContents)) + qwidget->d_func()->syncBackingStore(); + if (!slowResize && tlwExtra) + tlwExtra->inTopLevelResize = false; + } else { + if (!qwidget->testAttribute(Qt::WA_PendingResizeEvent)) { + QResizeEvent *e = new QResizeEvent(newSize, oldSize); + QApplication::postEvent(qwidget, e); + } + } +} + void QSymbianControl::SizeChanged() { CCoeControl::SizeChanged(); + // When FixNativeOrientation had been called, the RWindow/CCoeControl size + // and the surface/QWidget size have nothing to do with each other. + if (qwidget->d_func()->fixNativeOrientationCalled) + return; + QSize oldSize = qwidget->size(); QSize newSize(Size().iWidth, Size().iHeight); if (oldSize != newSize) { + // Enforce the proper size for fullscreen widgets on the secondary screen. const bool isFullscreen = qwidget->windowState() & Qt::WindowFullScreen; const int screenNumber = S60->screenNumberForWidget(qwidget); if (!m_inExternalScreenOverride && isFullscreen && screenNumber > 0) { @@ -1188,26 +1324,8 @@ void QSymbianControl::SizeChanged() return; } } - QRect cr = qwidget->geometry(); - cr.setSize(newSize); - qwidget->data->crect = cr; - if (qwidget->isVisible()) { - QTLWExtra *tlwExtra = qwidget->d_func()->maybeTopData(); - bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt(); - if (!slowResize && tlwExtra) - tlwExtra->inTopLevelResize = true; - QResizeEvent e(newSize, oldSize); - qt_sendSpontaneousEvent(qwidget, &e); - if (!qwidget->testAttribute(Qt::WA_StaticContents)) - qwidget->d_func()->syncBackingStore(); - if (!slowResize && tlwExtra) - tlwExtra->inTopLevelResize = false; - } else { - if (!qwidget->testAttribute(Qt::WA_PendingResizeEvent)) { - QResizeEvent *e = new QResizeEvent(newSize, oldSize); - QApplication::postEvent(qwidget, e); - } - } + + qwidgetResize_helper(newSize); } m_inExternalScreenOverride = false; @@ -1271,16 +1389,8 @@ void QSymbianControl::FocusChanged(TDrawNow /* aDrawNow */) qwidget->d_func()->setWindowIcon_sys(true); qwidget->d_func()->setWindowTitle_sys(qwidget->windowTitle()); #ifdef Q_WS_S60 - // If widget is fullscreen/minimized, hide status pane and button container otherwise show them. - QWidget *const window = qwidget->window(); - if (!window->parentWidget()) { // Only top level native windows have control over cba/status pane - const bool decorationsVisible = !(window->windowState() & (Qt::WindowFullScreen | Qt::WindowMinimized)); - const bool statusPaneVisibility = decorationsVisible; - const bool isFullscreen = window->windowState() & Qt::WindowFullScreen; - const bool cbaVisibilityHint = window->windowFlags() & Qt::WindowSoftkeysVisibleHint; - const bool buttonGroupVisibility = (decorationsVisible || (isFullscreen && cbaVisibilityHint)); - S60->setStatusPaneAndButtonGroupVisibility(statusPaneVisibility, buttonGroupVisibility); - } + if (qwidget->isWindow()) + S60->setRecursiveDecorationsVisibility(qwidget, qwidget->windowState()); #endif } else if (QApplication::activeWindow() == qwidget->window()) { bool focusedControlFound = false; @@ -1381,7 +1491,13 @@ void QSymbianControl::HandleResourceChange(int resourceType) } break; case KInternalStatusPaneChange: - handleClientAreaChange(); + // When status pane is not visible, only handle client area change if status pane was + // previously visible, as size changes to hidden status pane should not affect + // client area. + if (S60->statusPane() && (S60->statusPane()->IsVisible() || m_lastStatusPaneVisibility)) { + m_lastStatusPaneVisibility = S60->statusPane()->IsVisible(); + handleClientAreaChange(); + } if (IsFocused() && IsVisible()) { qwidget->d_func()->setWindowIcon_sys(true); qwidget->d_func()->setWindowTitle_sys(qwidget->windowTitle()); @@ -1395,8 +1511,10 @@ void QSymbianControl::HandleResourceChange(int resourceType) { handleClientAreaChange(); // Send resize event to trigger desktopwidget workAreaResized signal - QResizeEvent e(qt_desktopWidget->size(), qt_desktopWidget->size()); - QApplication::sendEvent(qt_desktopWidget, &e); + if (qt_desktopWidget) { + QResizeEvent e(qt_desktopWidget->size(), qt_desktopWidget->size()); + QApplication::sendEvent(qt_desktopWidget, &e); + } break; } #endif @@ -1455,6 +1573,55 @@ bool QSymbianControl::isControlActive() return IsActivated() ? true : false; } +void QSymbianControl::ensureFixNativeOrientation() +{ +#if defined(Q_SYMBIAN_SUPPORTS_FIXNATIVEORIENTATION) + if (!qwidget->isWindow() || qwidget->windowType() == Qt::Desktop) + return; + if (S60->screenNumberForWidget(qwidget) > 0) + return; + const bool isFixed = qwidget->d_func()->fixNativeOrientationCalled; + const bool isFixEnabled = qwidget->testAttribute(Qt::WA_SymbianNoSystemRotation); + const bool isFullScreen = qwidget->windowState().testFlag(Qt::WindowFullScreen); + if (isFullScreen && isFixEnabled) { + const bool surfaceBasedGs = + QApplicationPrivate::graphics_system_name == QLatin1String("openvg") + || QApplicationPrivate::graphics_system_name == QLatin1String("opengl"); + if (!surfaceBasedGs) + qwidget->setAttribute(Qt::WA_SymbianNoSystemRotation, false); + if (!isFixed && surfaceBasedGs) { + if (Window().FixNativeOrientation() == KErrNone) { + qwidget->d_func()->fixNativeOrientationCalled = true; + // The EGL window surface is now fixed to the native orientation + // of the device, no matter what size we pass when creating it. + // Enforce the same size for the QWidget too. For the underlying + // CCoeControl and RWindow it is up to the system to resize them + // when the standard auto-rotation mechanism is in use, we must not + // change that behavior by forcing any size for those. In practice + // this means that the QWidget and the underlying native control + // dimensions will be out of sync when FixNativeOrientation was + // called and the device is turned to the non-native (typically + // landscape) orientation. The pointer event handling and certain + // functions like Draw() will need to compensate for this. + QSize newSize(S60->nativeScreenWidthInPixels, S60->nativeScreenHeightInPixels); + if (qwidget->size() != newSize) + qwidgetResize_helper(newSize); + } else { + qwidget->setAttribute(Qt::WA_SymbianNoSystemRotation, false); + } + } + } else if (isFixed) { + qwidget->setAttribute(Qt::WA_SymbianNoSystemRotation, false); + qwidget->d_func()->fixNativeOrientationCalled = false; + qwidget->hide(); + qwidget->d_func()->create_sys(0, false, true); + qwidget->show(); + } +#else + qwidget->setAttribute(Qt::WA_SymbianNoSystemRotation, false); +#endif +} + /*! \typedef QApplication::QS60MainApplicationFactory \since 4.6 @@ -1661,10 +1828,36 @@ void qt_init(QApplicationPrivate * /* priv */, int) systemFont.setFamily(systemFont.defaultFamily()); QApplicationPrivate::setSystemFont(systemFont); -#ifdef Q_SYMBIAN_TRANSITION_EFFECTS QObject::connect(qApp, SIGNAL(aboutToQuit()), qApp, SLOT(_q_aboutToQuit())); -#endif +#ifdef Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE + QApplicationPrivate::instance()->useTranslucentEGLSurfaces = true; + + const TUid KIvePropertyCat = {0x2726beef}; + enum TIvePropertyChipType { + EVCBCM2727B1 = 0x00000000, + EVCBCM2763A0 = 0x04000100, + EVCBCM2763B0 = 0x04000102, + EVCBCM2763C0 = 0x04000103, + EVCBCM2763C1 = 0x04000104, + EVCBCMUnknown = 0x7fffffff + }; + + TInt chipType = EVCBCMUnknown; + if (RProperty::Get(KIvePropertyCat, 0 /*chip type*/, chipType) == KErrNone) { + if (chipType == EVCBCM2727B1) { + // We have only 32MB GPU memory. Use raster surfaces + // for transparent TLWs. + QApplicationPrivate::instance()->useTranslucentEGLSurfaces = false; + } + } else { + QApplicationPrivate::instance()->useTranslucentEGLSurfaces = false; + } + if (QApplicationPrivate::graphics_system_name == QLatin1String("raster")) + QApplicationPrivate::instance()->useTranslucentEGLSurfaces = false; +#else + QApplicationPrivate::instance()->useTranslucentEGLSurfaces = false; +#endif /* ### Commented out for now as parameter handling not needed in SOS(yet). Code below will break testlib with -o flag int argc = priv->argc; @@ -1726,6 +1919,9 @@ void qt_cleanup() S60->setButtonGroupContainer(0); #endif + // Call EndFullScreen() to prevent confusing the system effect state machine. + qt_endFullScreenEffect(); + if (S60->qtOwnsS60Environment) { // Restore the S60 framework trap handler. See qt_init(). User::SetTrapHandler(S60->s60InstalledTrapHandler); @@ -2097,7 +2293,8 @@ int QApplicationPrivate::symbianProcessWsEvent(const QSymbianEvent *symbianEvent } #endif #ifdef QT_SOFTKEYS_ENABLED - QSoftKeyManager::updateSoftKeys(); + if (!CEikonEnv::Static()->EikAppUi()->IsDisplayingMenuOrDialog()) + QSoftKeyManager::updateSoftKeys(); #endif break; case EEventFocusLost: @@ -2463,6 +2660,8 @@ void QApplication::restoreOverrideCursor() void QApplicationPrivate::_q_aboutToQuit() { + qt_beginFullScreenEffect(); + #ifdef Q_SYMBIAN_TRANSITION_EFFECTS // Send the shutdown tfx command S60->wsSession().SendEffectCommand(ETfxCmdAppShutDown); diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp index 6e89ceb..913bc7e 100644 --- a/src/gui/kernel/qapplication_win.cpp +++ b/src/gui/kernel/qapplication_win.cpp @@ -3779,16 +3779,32 @@ bool QETWidget::translateConfigEvent(const MSG &msg) QApplication::sendSpontaneousEvent(this, &e); hideChildren(true); } - } else if (msg.wParam != SIZE_MINIMIZED && isMinimized()) { + } else if (msg.wParam != SIZE_MINIMIZED) { + bool window_state_changed = false; + Qt::WindowStates oldstate = Qt::WindowStates(dataPtr()->window_state); + if (isMinimized()) { #ifndef Q_WS_WINCE - const QString title = windowTitle(); - if (!title.isEmpty()) - d_func()->setWindowTitle_helper(title); + const QString title = windowTitle(); + if (!title.isEmpty()) + d_func()->setWindowTitle_helper(title); #endif - data->window_state &= ~Qt::WindowMinimized; - showChildren(true); - QShowEvent e; - QApplication::sendSpontaneousEvent(this, &e); + data->window_state &= ~Qt::WindowMinimized; + showChildren(true); + QShowEvent e; + QApplication::sendSpontaneousEvent(this, &e); + // Capture SIZE_MAXIMIZED and SIZE_RESTORED without preceding WM_SYSCOMMAND + // (Aero Snap on Win7) + } else if (msg.wParam == SIZE_MAXIMIZED && !isMaximized()) { + data->window_state |= Qt::WindowMaximized; + window_state_changed = true; + } else if (msg.wParam == SIZE_RESTORED && isMaximized()) { + data->window_state &= ~(Qt::WindowMaximized); + window_state_changed = true; + } + if (window_state_changed) { + QWindowStateChangeEvent e(oldstate); + QApplication::sendSpontaneousEvent(this, &e); + } } } if (msg.wParam != SIZE_MINIMIZED && oldSize != newSize) { @@ -3820,7 +3836,7 @@ bool QETWidget::translateConfigEvent(const MSG &msg) QApplication::postEvent(this, e); } } -} else if (msg.message == WM_MOVE) { // move event + } else if (msg.message == WM_MOVE) { // move event int a = (int) (short) LOWORD(msg.lParam); int b = (int) (short) HIWORD(msg.lParam); QPoint oldPos = geometry().topLeft(); diff --git a/src/gui/kernel/qclipboard_win.cpp b/src/gui/kernel/qclipboard_win.cpp index 52b9663..ea41165 100644 --- a/src/gui/kernel/qclipboard_win.cpp +++ b/src/gui/kernel/qclipboard_win.cpp @@ -52,6 +52,7 @@ #include "qt_windows.h" #include "qdnd_p.h" #include <private/qwidget_p.h> +#include <private/qsystemlibrary_p.h> QT_BEGIN_NAMESPACE @@ -70,6 +71,9 @@ void QtCeFlushClipboard(); #endif +typedef BOOL (WINAPI *PtrIsHungAppWindow)(HWND); + +static PtrIsHungAppWindow ptrIsHungAppWindow = 0; class QClipboardWatcher : public QInternalMimeData { public: @@ -327,9 +331,16 @@ bool QClipboard::event(QEvent *e) d->releaseIData(); propagate = true; } - if (propagate && d->nextClipboardViewer) { - SendMessage(d->nextClipboardViewer, m->message, m->wParam, m->lParam); + if (ptrIsHungAppWindow == 0) { + QSystemLibrary library(QLatin1String("User32")); + ptrIsHungAppWindow = (PtrIsHungAppWindow)library.resolve("IsHungAppWindow"); + } + if (ptrIsHungAppWindow && ptrIsHungAppWindow(d->nextClipboardViewer)) { + qWarning("%s: Cowardly refusing to send clipboard message to hung application...", Q_FUNC_INFO); + } else { + SendMessage(d->nextClipboardViewer, m->message, m->wParam, m->lParam); + } } return true; diff --git a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h index 6254061..406e6d4 100644 --- a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h +++ b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h @@ -157,6 +157,20 @@ QT_END_NAMESPACE [NSApp terminate:sender]; } +- (void)setLevel:(NSInteger)windowLevel +{ + // Cocoa will upon activating/deactivating applications level modal + // windows up and down, regardsless of any explicit set window level. + // To ensure that modal stays-on-top dialogs actually stays on top after + // the application is activated (and therefore stacks in front of + // other stays-on-top windows), we need to add this little special-case override: + QWidget *widget = [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] qt_qwidgetForWindow:self]; + if (widget && widget->isModal() && (widget->windowFlags() & Qt::WindowStaysOnTopHint)) + [super setLevel:NSPopUpMenuWindowLevel]; + else + [super setLevel:windowLevel]; +} + - (void)sendEvent:(NSEvent *)event { if ([event type] == NSApplicationDefined) { diff --git a/src/gui/kernel/qdesktopwidget_s60.cpp b/src/gui/kernel/qdesktopwidget_s60.cpp index c3963f4..62a4d40 100644 --- a/src/gui/kernel/qdesktopwidget_s60.cpp +++ b/src/gui/kernel/qdesktopwidget_s60.cpp @@ -188,12 +188,14 @@ void QDesktopWidgetPrivate::cleanup() void QDesktopWidgetPrivate::init_sys() { #if defined(Q_SYMBIAN_SUPPORTS_MULTIPLE_SCREENS) - CWsScreenDevice *dev = S60->screenDevice(1); - if (dev) { - displayControl = static_cast<MDisplayControl *>( - dev->GetInterface(MDisplayControl::ETypeId)); - if (displayControl) { - displayControl->EnableDisplayChangeEvents(ETrue); + if (S60->screenCount() > 1) { + CWsScreenDevice *dev = S60->screenDevice(1); + if (dev) { + displayControl = static_cast<MDisplayControl *>( + dev->GetInterface(MDisplayControl::ETypeId)); + if (displayControl) { + displayControl->EnableDisplayChangeEvents(ETrue); + } } } #endif diff --git a/src/gui/kernel/qsoftkeymanager.cpp b/src/gui/kernel/qsoftkeymanager.cpp index 1b26933..204efe9 100644 --- a/src/gui/kernel/qsoftkeymanager.cpp +++ b/src/gui/kernel/qsoftkeymanager.cpp @@ -50,6 +50,10 @@ #include "private/qsoftkeymanager_s60_p.h" #endif +#ifdef SYMBIAN_VERSION_SYMBIAN3 +#include "private/qt_s60_p.h" +#endif + #ifndef QT_NO_SOFTKEYMANAGER QT_BEGIN_NAMESPACE @@ -101,6 +105,30 @@ QSoftKeyManager::QSoftKeyManager() : QAction *QSoftKeyManager::createAction(StandardSoftKey standardKey, QWidget *actionWidget) { QAction *action = new QAction(standardSoftKeyText(standardKey), actionWidget); +#ifdef SYMBIAN_VERSION_SYMBIAN3 + int key = 0; + switch (standardKey) { + case OkSoftKey: + key = EAknSoftkeyOk; + break; + case SelectSoftKey: + key = EAknSoftkeySelect; + break; + case DoneSoftKey: + key = EAknSoftkeyDone; + break; + case MenuSoftKey: + key = EAknSoftkeyOptions; + break; + case CancelSoftKey: + key = EAknSoftkeyCancel; + break; + default: + break; + }; + if (key != 0) + QSoftKeyManager::instance()->d_func()->softKeyCommandActions.insert(action, key); +#endif QAction::SoftKeyRole softKeyRole = QAction::NoSoftKey; switch (standardKey) { case MenuSoftKey: // FALL-THROUGH @@ -143,6 +171,9 @@ void QSoftKeyManager::cleanupHash(QObject *obj) Q_D(QSoftKeyManager); QAction *action = qobject_cast<QAction*>(obj); d->keyedActions.remove(action); +#ifdef SYMBIAN_VERSION_SYMBIAN3 + d->softKeyCommandActions.remove(action); +#endif } void QSoftKeyManager::sendKeyEvent() diff --git a/src/gui/kernel/qsoftkeymanager_common_p.h b/src/gui/kernel/qsoftkeymanager_common_p.h index 27d8ee9..02ae697 100644 --- a/src/gui/kernel/qsoftkeymanager_common_p.h +++ b/src/gui/kernel/qsoftkeymanager_common_p.h @@ -72,6 +72,9 @@ protected: QMultiHash<int, QAction*> requestedSoftKeyActions; QWidget *initialSoftKeySource; bool pendingUpdate; +#ifdef SYMBIAN_VERSION_SYMBIAN3 + QHash<QAction*, int> softKeyCommandActions; +#endif }; QT_END_NAMESPACE diff --git a/src/gui/kernel/qsoftkeymanager_s60.cpp b/src/gui/kernel/qsoftkeymanager_s60.cpp index 3496297..79ed91a 100644 --- a/src/gui/kernel/qsoftkeymanager_s60.cpp +++ b/src/gui/kernel/qsoftkeymanager_s60.cpp @@ -113,12 +113,20 @@ void QSoftKeyManagerPrivateS60::ensureCbaVisibilityAndResponsiviness(CEikButtonG void QSoftKeyManagerPrivateS60::clearSoftkeys(CEikButtonGroupContainer &cba) { +#ifdef SYMBIAN_VERSION_SYMBIAN3 + QT_TRAP_THROWING( + //EAknSoftkeyEmpty is used, because using -1 adds softkeys without actions on Symbian3 + cba.SetCommandL(0, EAknSoftkeyEmpty, KNullDesC); + cba.SetCommandL(2, EAknSoftkeyEmpty, KNullDesC); + ); +#else QT_TRAP_THROWING( //Using -1 instead of EAknSoftkeyEmpty to avoid flickering. cba.SetCommandL(0, -1, KNullDesC); // TODO: Should we clear also middle SK? cba.SetCommandL(2, -1, KNullDesC); ); +#endif realSoftKeyActions.clear(); } @@ -290,6 +298,10 @@ bool QSoftKeyManagerPrivateS60::setSoftkey(CEikButtonGroupContainer &cba, QString text = softkeyText(*action); TPtrC nativeText = qt_QString2TPtrC(text); int command = S60_COMMAND_START + position; +#ifdef SYMBIAN_VERSION_SYMBIAN3 + if (softKeyCommandActions.contains(action)) + command = softKeyCommandActions.value(action); +#endif setNativeSoftkey(cba, position, command, nativeText); const bool dimmed = !action->isEnabled() && !QSoftKeyManager::isForceEnabledInSofkeys(action); cba.DimCommand(command, dimmed); diff --git a/src/gui/kernel/qt_s60_p.h b/src/gui/kernel/qt_s60_p.h index 3bb27c3..8aba53a 100644 --- a/src/gui/kernel/qt_s60_p.h +++ b/src/gui/kernel/qt_s60_p.h @@ -77,6 +77,10 @@ #include <akncontext.h> // CAknContextPane #include <eikspane.h> // CEikStatusPane #include <AknPopupFader.h> // MAknFadedComponent and TAknPopupFader +#include <gfxtranseffect/gfxtranseffect.h> // BeginFullScreen +#ifdef QT_SYMBIAN_HAVE_AKNTRANSEFFECT_H +#include <akntranseffect.h> // BeginFullScreen +#endif #endif QT_BEGIN_NAMESPACE @@ -85,6 +89,9 @@ QT_BEGIN_NAMESPACE // system events seems to start with 0x10 const TInt KInternalStatusPaneChange = 0x50000000; +// For BeginFullScreen(). +const TUint KQtAppExitFlag = 0x400; + static const int qt_symbian_max_screens = 4; //this macro exists because EColor16MAP enum value doesn't exist in Symbian OS 9.2 @@ -178,6 +185,7 @@ public: static inline CEikButtonGroupContainer* buttonGroupContainer(); static inline void setButtonGroupContainer(CEikButtonGroupContainer* newCba); static void setStatusPaneAndButtonGroupVisibility(bool statusPaneVisible, bool buttonGroupVisible); + static bool setRecursiveDecorationsVisibility(QWidget *window, Qt::WindowStates newState); #endif static void controlVisibilityChanged(CCoeControl *control, bool visible); @@ -189,6 +197,12 @@ public: int screenHeightInPixelsForScreen[qt_symbian_max_screens]; int screenWidthInTwipsForScreen[qt_symbian_max_screens]; int screenHeightInTwipsForScreen[qt_symbian_max_screens]; + + int nativeScreenWidthInPixels; + int nativeScreenHeightInPixels; + + int beginFullScreenCalled : 1; + int endFullScreenCalled : 1; }; Q_AUTOTEST_EXPORT QS60Data* qGlobalS60Data(); @@ -233,6 +247,10 @@ public: bool isControlActive(); + void ensureFixNativeOrientation(); + QPoint translatePointForFixedNativeOrientation(const TPoint &pointerEventPos) const; + TRect translateRectForFixedNativeOrientation(const TRect &controlRect) const; + #ifdef Q_WS_S60 void FadeBehindPopup(bool fade){ popupFader.FadeBehindPopup( this, this, fade); } void HandleStatusPaneSizeChange(); @@ -251,6 +269,9 @@ protected: void PositionChanged(); void FocusChanged(TDrawNow aDrawNow); +protected: + void qwidgetResize_helper(const QSize &newSize); + private: void HandlePointerEvent(const TPointerEvent& aPointerEvent); TKeyResponse OfferKeyEvent(const TKeyEvent& aKeyEvent,TEventCode aType); @@ -290,6 +311,7 @@ private: #endif bool m_inExternalScreenOverride : 1; + bool m_lastStatusPaneVisibility : 1; }; inline QS60Data::QS60Data() @@ -322,14 +344,18 @@ inline QS60Data::QS60Data() #ifdef Q_OS_SYMBIAN ,s60InstalledTrapHandler(0) #endif + ,beginFullScreenCalled(0), + endFullScreenCalled(0) { } inline void QS60Data::updateScreenSize() { + CWsScreenDevice *dev = S60->screenDevice(); + int screenModeCount = dev->NumScreenModes(); + int mode = dev->CurrentScreenMode(); TPixelsTwipsAndRotation params; - int mode = S60->screenDevice()->CurrentScreenMode(); - S60->screenDevice()->GetScreenModeSizeAndRotation(mode, params); + dev->GetScreenModeSizeAndRotation(mode, params); S60->screenWidthInPixels = params.iPixelSize.iWidth; S60->screenHeightInPixels = params.iPixelSize.iHeight; S60->screenWidthInTwips = params.iTwipsSize.iWidth; @@ -352,6 +378,18 @@ inline void QS60Data::updateScreenSize() S60->screenWidthInTwipsForScreen[i] = params.iTwipsSize.iWidth; S60->screenHeightInTwipsForScreen[i] = params.iTwipsSize.iHeight; } + + // Look for a screen mode with rotation 0 + // in order to decide what the native orientation is. + for (mode = 0; mode < screenModeCount; ++mode) { + TPixelsAndRotation sizeAndRotation; + dev->GetScreenModeSizeAndRotation(mode, sizeAndRotation); + if (sizeAndRotation.iRotation == CFbsBitGc::EGraphicsOrientationNormal) { + S60->nativeScreenWidthInPixels = sizeAndRotation.iPixelSize.iWidth; + S60->nativeScreenHeightInPixels = sizeAndRotation.iPixelSize.iHeight; + break; + } + } } inline RWsSession& QS60Data::wsSession() @@ -539,6 +577,49 @@ void qt_symbian_set_cursor_visible(bool visible); bool qt_symbian_is_cursor_visible(); #endif +static inline bool qt_beginFullScreenEffect() +{ +#if defined(Q_WS_S60) && defined(QT_SYMBIAN_HAVE_AKNTRANSEFFECT_H) + // Only for post-S^3. On earlier versions the system transition effects + // may not be able to capture the non-Avkon content, leading to confusing + // looking effects, so just skip the whole thing. + if (S60->beginFullScreenCalled || QSysInfo::s60Version() <= QSysInfo::SV_S60_5_2) + return false; + S60->beginFullScreenCalled = true; + // For Avkon apps the app-exit effect is triggered from CAknAppUi::PrepareToExit(). + // That is good for Avkon apps, but in case of Qt the RWindows are destroyed earlier. + // Therefore we call BeginFullScreen() ourselves. + GfxTransEffect::BeginFullScreen(AknTransEffect::EApplicationExit, + TRect(0, 0, 0, 0), + AknTransEffect::EParameterType, + AknTransEffect::GfxTransParam(S60->uid, + AknTransEffect::TParameter::EAvkonCheck | KQtAppExitFlag)); + return true; +#else + return false; +#endif +} + +static inline void qt_abortFullScreenEffect() +{ +#if defined(Q_WS_S60) && defined(QT_SYMBIAN_HAVE_AKNTRANSEFFECT_H) + if (!S60->beginFullScreenCalled || QSysInfo::s60Version() <= QSysInfo::SV_S60_5_2) + return; + GfxTransEffect::AbortFullScreen(); + S60->beginFullScreenCalled = S60->endFullScreenCalled = false; +#endif +} + +static inline void qt_endFullScreenEffect() +{ +#if defined(Q_WS_S60) && defined(QT_SYMBIAN_HAVE_AKNTRANSEFFECT_H) + if (S60->endFullScreenCalled || QSysInfo::s60Version() <= QSysInfo::SV_S60_5_2) + return; + S60->endFullScreenCalled = true; + GfxTransEffect::EndFullScreen(); +#endif +} + QT_END_NAMESPACE #endif // QT_S60_P_H diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index 1786e65..ac35d42 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -306,6 +306,7 @@ QWidgetPrivate::QWidgetPrivate(int version) , qd_hd(0) #elif defined(Q_OS_SYMBIAN) , symbianScreenNumber(0) + , fixNativeOrientationCalled(false) #endif { if (!qApp) { @@ -597,8 +598,7 @@ void QWidget::setAutoFillBackground(bool enabled) \brief The QWidget class is the base class of all user interface objects. \ingroup basicwidgets - - + The widget is the atom of the user interface: it receives mouse, keyboard and other events from the window system, and paints a representation of itself on the screen. Every widget is rectangular, and they are sorted in a @@ -1326,8 +1326,8 @@ void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f) //give potential windows a bigger "pre-initial" size; create_sys() will give them a new size later #ifdef Q_OS_SYMBIAN if (isGLWidget) { - // Don't waste GPU mem for unnecessary large egl surface - data.crect = QRect(0,0,2,2); + // Don't waste GPU mem for unnecessary large egl surface until resized by application + data.crect = QRect(0,0,1,1); } else { data.crect = parentWidget ? QRect(0,0,100,30) : QRect(0,0,360,640); } @@ -10866,6 +10866,9 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on) } QT_TRAP_THROWING(appUi->SetOrientationL(s60orientation)); S60->orientationSet = true; + QSymbianControl *window = static_cast<QSymbianControl *>(internalWinId()); + if (window) + window->ensureFixNativeOrientation(); #endif break; } diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm index 7e5173f..8784ffd 100644 --- a/src/gui/kernel/qwidget_mac.mm +++ b/src/gui/kernel/qwidget_mac.mm @@ -2794,6 +2794,11 @@ void QWidgetPrivate::transferChildren() #ifdef QT_MAC_USE_COCOA void QWidgetPrivate::setSubWindowStacking(bool set) { + // After hitting too many unforeseen bugs trying to put Qt on top of the cocoa child + // window API, we have decided to revert this behaviour as much as we can. We + // therefore now only allow child windows to exist for children of modal dialogs. + static bool use_behaviour_qt473 = !qgetenv("QT_MAC_USE_CHILDWINDOWS").isEmpty(); + // This will set/remove a visual relationship between parent and child on screen. // The reason for doing this is to ensure that a child always stacks infront of // its parent. Unfortunatly is turns out that [NSWindow addChildWindow] has @@ -2822,7 +2827,10 @@ void QWidgetPrivate::setSubWindowStacking(bool set) if (NSWindow *pwin = [qt_mac_nativeview_for(parent) window]) { if (set) { Qt::WindowType ptype = parent->window()->windowType(); - if ([pwin isVisible] && (ptype == Qt::Window || ptype == Qt::Dialog) && ![qwin parentWindow]) { + if ([pwin isVisible] + && (ptype == Qt::Window || ptype == Qt::Dialog) + && ![qwin parentWindow] + && (use_behaviour_qt473 || parent->windowModality() == Qt::ApplicationModal)) { NSInteger level = [qwin level]; [pwin addChildWindow:qwin ordered:NSWindowAbove]; if ([qwin level] < level) @@ -2834,6 +2842,10 @@ void QWidgetPrivate::setSubWindowStacking(bool set) } } + // Only set-up child windows for q if q is modal: + if (set && !use_behaviour_qt473 && q->windowModality() != Qt::ApplicationModal) + return; + QObjectList widgets = q->children(); for (int i=0; i<widgets.size(); ++i) { QWidget *child = qobject_cast<QWidget *>(widgets.at(i)); diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h index 5235dc4..377e3a7 100644 --- a/src/gui/kernel/qwidget_p.h +++ b/src/gui/kernel/qwidget_p.h @@ -315,6 +315,11 @@ struct QWExtra { */ ZeroFill, + /** + * Blit backing store, propagating alpha channel into the framebuffer. + */ + BlitWriteAlpha, + Default = Blit }; @@ -878,6 +883,7 @@ public: static QWidget *mouseGrabber; static QWidget *keyboardGrabber; int symbianScreenNumber; // only valid for desktop widget and top-levels + bool fixNativeOrientationCalled; void s60UpdateIsOpaque(); void reparentChildren(); void registerTouchWindow(); diff --git a/src/gui/kernel/qwidget_s60.cpp b/src/gui/kernel/qwidget_s60.cpp index be212fb..d55e1ad 100644 --- a/src/gui/kernel/qwidget_s60.cpp +++ b/src/gui/kernel/qwidget_s60.cpp @@ -278,6 +278,8 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove) q->internalWinId()->SetRect(TRect(TPoint(x, y), TSize(w, h))); topData()->normalGeometry = data.crect; } + QSymbianControl *window = static_cast<QSymbianControl *>(q->internalWinId()); + window->ensureFixNativeOrientation(); } else { data.crect.setRect(x, y, w, h); @@ -805,36 +807,45 @@ void QWidgetPrivate::s60UpdateIsOpaque() { Q_Q(QWidget); - if (!q->testAttribute(Qt::WA_WState_Created) || !q->testAttribute(Qt::WA_TranslucentBackground)) + if (!q->testAttribute(Qt::WA_WState_Created)) return; + const bool writeAlpha = extraData()->nativePaintMode == QWExtra::BlitWriteAlpha; + if (!q->testAttribute(Qt::WA_TranslucentBackground) && !writeAlpha) + return; + const bool requireAlphaChannel = !isOpaque || writeAlpha; + createTLExtra(); RWindow *const window = static_cast<RWindow *>(q->effectiveWinId()->DrawableWindow()); #ifdef Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE - window->SetSurfaceTransparency(!isOpaque); - extra->topextra->nativeWindowTransparencyEnabled = !isOpaque; -#else - if (!isOpaque) { + if (QApplicationPrivate::instance()->useTranslucentEGLSurfaces) { + window->SetSurfaceTransparency(!isOpaque); + extra->topextra->nativeWindowTransparencyEnabled = !isOpaque; + return; + } +#endif + if (requireAlphaChannel) { const TDisplayMode displayMode = static_cast<TDisplayMode>(window->SetRequiredDisplayMode(EColor16MA)); if (window->SetTransparencyAlphaChannel() == KErrNone) { window->SetBackgroundColor(TRgb(255, 255, 255, 0)); extra->topextra->nativeWindowTransparencyEnabled = 1; - - if (extra->topextra->backingStore.data() && - QApplicationPrivate::graphics_system_name == QLatin1String("openvg")) { + if (extra->topextra->backingStore.data() && ( + QApplicationPrivate::graphics_system_name == QLatin1String("openvg") + || QApplicationPrivate::graphics_system_name == QLatin1String("opengl"))) { // Semi-transparent EGL surfaces aren't supported. We need to // recreate backing store to get translucent surface (raster surface). extra->topextra->backingStore.create(q); extra->topextra->backingStore.registerWidget(q); + // FixNativeOrientation() will not work without an EGL surface. + q->setAttribute(Qt::WA_SymbianNoSystemRotation, false); } } } else if (extra->topextra->nativeWindowTransparencyEnabled) { window->SetTransparentRegion(TRegionFix<1>()); extra->topextra->nativeWindowTransparencyEnabled = 0; } -#endif } void QWidgetPrivate::setWindowIcon_sys(bool forceReset) @@ -1197,17 +1208,10 @@ void QWidget::setWindowState(Qt::WindowStates newstate) } #ifdef Q_WS_S60 - bool decorationsVisible(false); - if (!parentWidget()) { // Only top level native windows have control over cba/status pane - // Hide window decoration when switching to fullscreen / minimized otherwise show decoration. - // The window decoration visibility has to be changed before doing actual window state - // change since in that order the availableGeometry will return directly the right size and - // we will avoid unnecessary redraws - decorationsVisible = !(newstate & (Qt::WindowFullScreen | Qt::WindowMinimized)); - const bool statusPaneVisibility = decorationsVisible; - const bool buttonGroupVisibility = (decorationsVisible || (isFullscreen && cbaRequested)); - S60->setStatusPaneAndButtonGroupVisibility(statusPaneVisibility, buttonGroupVisibility); - } + // The window decoration visibility has to be changed before doing actual window state + // change since in that order the availableGeometry will return directly the right size and + // we will avoid unnecessary redraws + bool decorationsVisible = S60->setRecursiveDecorationsVisibility(this, newstate); #endif // Q_WS_S60 // Ensure the initial size is valid, since we store it as normalGeometry below. @@ -1266,6 +1270,12 @@ void QWidget::setWindowState(Qt::WindowStates newstate) if (newstate & Qt::WindowActive) activateWindow(); + if (isWindow()) { + // Now that the new state is set, fix the display memory layout, if needed. + QSymbianControl *window = static_cast<QSymbianControl *>(effectiveWinId()); + window->ensureFixNativeOrientation(); + } + QWindowStateChangeEvent e(oldstate); QApplication::sendEvent(this, &e); } @@ -1412,7 +1422,8 @@ void QWidget::activateWindow() if (tlw->isVisible()) { window()->createWinId(); QSymbianControl *id = static_cast<QSymbianControl *>(tlw->internalWinId()); - id->setFocusSafely(true); + if (!id->IsFocused()) + id->setFocusSafely(true); } } diff --git a/src/gui/math3d/qvector2d.cpp b/src/gui/math3d/qvector2d.cpp index 7f5a937..1fccfc9 100644 --- a/src/gui/math3d/qvector2d.cpp +++ b/src/gui/math3d/qvector2d.cpp @@ -60,6 +60,11 @@ QT_BEGIN_NAMESPACE The QVector2D class can also be used to represent vertices in 2D space. We therefore do not need to provide a separate vertex class. + \bold{Note:} By design values in the QVector2D instance are stored as \c float. + This means that on platforms where the \c qreal arguments to QVector2D + functions are represented by \c double values, it is possible to + lose precision. + \sa QVector3D, QVector4D, QQuaternion */ diff --git a/src/gui/math3d/qvector3d.cpp b/src/gui/math3d/qvector3d.cpp index 2414b5f..7bf0400 100644 --- a/src/gui/math3d/qvector3d.cpp +++ b/src/gui/math3d/qvector3d.cpp @@ -63,6 +63,11 @@ QT_BEGIN_NAMESPACE The QVector3D class can also be used to represent vertices in 3D space. We therefore do not need to provide a separate vertex class. + \bold{Note:} By design values in the QVector3D instance are stored as \c float. + This means that on platforms where the \c qreal arguments to QVector3D + functions are represented by \c double values, it is possible to + lose precision. + \sa QVector2D, QVector4D, QQuaternion */ diff --git a/src/gui/math3d/qvector4d.cpp b/src/gui/math3d/qvector4d.cpp index 74dedc4..23befc0 100644 --- a/src/gui/math3d/qvector4d.cpp +++ b/src/gui/math3d/qvector4d.cpp @@ -59,6 +59,11 @@ QT_BEGIN_NAMESPACE The QVector4D class can also be used to represent vertices in 4D space. We therefore do not need to provide a separate vertex class. + \bold{Note:} By design values in the QVector4D instance are stored as \c float. + This means that on platforms where the \c qreal arguments to QVector4D + functions are represented by \c double values, it is possible to + lose precision. + \sa QQuaternion, QVector2D, QVector3D */ diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp index dc61e34..8f965c2 100644 --- a/src/gui/painting/qbrush.cpp +++ b/src/gui/painting/qbrush.cpp @@ -49,6 +49,7 @@ #include "qdebug.h" #include <QtCore/qcoreapplication.h> #include "private/qstylehelper_p.h" +#include <QtCore/qnumeric.h> QT_BEGIN_NAMESPACE @@ -1360,13 +1361,14 @@ QGradient::QGradient() void QGradient::setColorAt(qreal pos, const QColor &color) { - if (pos > 1 || pos < 0) { + if ((pos > 1 || pos < 0) && !qIsNaN(pos)) { qWarning("QGradient::setColorAt: Color position must be specified in the range 0 to 1"); return; } int index = 0; - while (index < m_stops.size() && m_stops.at(index).first < pos) ++index; + if (!qIsNaN(pos)) + while (index < m_stops.size() && m_stops.at(index).first < pos) ++index; if (index < m_stops.size() && m_stops.at(index).first == pos) m_stops[index].second = color; diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp index 00b103d..debca37 100644 --- a/src/gui/painting/qdrawhelper_neon.cpp +++ b/src/gui/painting/qdrawhelper_neon.cpp @@ -327,10 +327,8 @@ void qt_blend_argb32_on_rgb16_neon(uchar *destPixels, int dbpl, blend_8_pixels_argb32_on_rgb16_neon(dstBuffer, srcBuffer, const_alpha); - for (int j = 0; j < tail; ++j) { + for (int j = 0; j < tail; ++j) dst[i + j] = dstBuffer[j]; - src[i + j] = srcBuffer[j]; - } } dst = (quint16 *)(((uchar *) dst) + dbpl); diff --git a/src/gui/painting/qgraphicssystem_runtime.cpp b/src/gui/painting/qgraphicssystem_runtime.cpp index 5841d40..33652ee 100644 --- a/src/gui/painting/qgraphicssystem_runtime.cpp +++ b/src/gui/painting/qgraphicssystem_runtime.cpp @@ -394,7 +394,10 @@ void QRuntimeGraphicsSystem::setGraphicsSystem(const QString &name) if(m_windowSurfaceDestroyPolicy == DestroyAfterFirstFlush) proxy->m_pendingWindowSurface.reset(proxy->m_windowSurface.take()); - proxy->m_windowSurface.reset(m_graphicsSystem->createWindowSurface(widget)); + QWindowSurface *newWindowSurface = m_graphicsSystem->createWindowSurface(widget); + newWindowSurface->setGeometry(proxy->geometry()); + + proxy->m_windowSurface.reset(newWindowSurface); qt_widget_private(widget)->invalidateBuffer(widget->rect()); } diff --git a/src/gui/painting/qpaintengine_mac.cpp b/src/gui/painting/qpaintengine_mac.cpp index c3aac1b..b07053e 100644 --- a/src/gui/painting/qpaintengine_mac.cpp +++ b/src/gui/painting/qpaintengine_mac.cpp @@ -969,7 +969,7 @@ void QCoreGraphicsPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, co return; bool differentSize = (QRectF(0, 0, pm.width(), pm.height()) != sr), doRestore = false; - CGRect rect = CGRectMake(qRound(r.x()), qRound(r.y()), qRound(r.width()), qRound(r.height())); + CGRect rect = CGRectMake(r.x(), r.y(), r.width(), r.height()); QCFType<CGImageRef> image; bool isBitmap = (pm.depth() == 1); if (isBitmap) { diff --git a/src/gui/painting/qpainterpath.cpp b/src/gui/painting/qpainterpath.cpp index 9ef6955..0bb2901 100644 --- a/src/gui/painting/qpainterpath.cpp +++ b/src/gui/painting/qpainterpath.cpp @@ -1690,7 +1690,7 @@ static void qt_painterpath_isect_line(const QPointF &p1, } static void qt_painterpath_isect_curve(const QBezier &bezier, const QPointF &pt, - int *winding) + int *winding, int depth = 0) { qreal y = pt.y(); qreal x = pt.x(); @@ -1705,7 +1705,7 @@ static void qt_painterpath_isect_curve(const QBezier &bezier, const QPointF &pt, // hit lower limit... This is a rough threshold, but its a // tradeoff between speed and precision. const qreal lower_bound = qreal(.001); - if (bounds.width() < lower_bound && bounds.height() < lower_bound) { + if (depth == 32 || (bounds.width() < lower_bound && bounds.height() < lower_bound)) { // We make the assumption here that the curve starts to // approximate a line after while (i.e. that it doesn't // change direction drastically during its slope) @@ -1718,8 +1718,8 @@ static void qt_painterpath_isect_curve(const QBezier &bezier, const QPointF &pt, // split curve and try again... QBezier first_half, second_half; bezier.split(&first_half, &second_half); - qt_painterpath_isect_curve(first_half, pt, winding); - qt_painterpath_isect_curve(second_half, pt, winding); + qt_painterpath_isect_curve(first_half, pt, winding, depth + 1); + qt_painterpath_isect_curve(second_half, pt, winding, depth + 1); } } @@ -1863,39 +1863,39 @@ static bool qt_painterpath_isect_line_rect(qreal x1, qreal y1, qreal x2, qreal y return false; } -static bool qt_isect_curve_horizontal(const QBezier &bezier, qreal y, qreal x1, qreal x2) +static bool qt_isect_curve_horizontal(const QBezier &bezier, qreal y, qreal x1, qreal x2, int depth = 0) { QRectF bounds = bezier.bounds(); if (y >= bounds.top() && y < bounds.bottom() && bounds.right() >= x1 && bounds.left() < x2) { const qreal lower_bound = qreal(.01); - if (bounds.width() < lower_bound && bounds.height() < lower_bound) + if (depth == 32 || bounds.width() < lower_bound && bounds.height() < lower_bound) return true; QBezier first_half, second_half; bezier.split(&first_half, &second_half); - if (qt_isect_curve_horizontal(first_half, y, x1, x2) - || qt_isect_curve_horizontal(second_half, y, x1, x2)) + if (qt_isect_curve_horizontal(first_half, y, x1, x2, depth + 1) + || qt_isect_curve_horizontal(second_half, y, x1, x2, depth + 1)) return true; } return false; } -static bool qt_isect_curve_vertical(const QBezier &bezier, qreal x, qreal y1, qreal y2) +static bool qt_isect_curve_vertical(const QBezier &bezier, qreal x, qreal y1, qreal y2, int depth = 0) { QRectF bounds = bezier.bounds(); if (x >= bounds.left() && x < bounds.right() && bounds.bottom() >= y1 && bounds.top() < y2) { const qreal lower_bound = qreal(.01); - if (bounds.width() < lower_bound && bounds.height() < lower_bound) + if (depth == 32 || bounds.width() < lower_bound && bounds.height() < lower_bound) return true; QBezier first_half, second_half; bezier.split(&first_half, &second_half); - if (qt_isect_curve_vertical(first_half, x, y1, y2) - || qt_isect_curve_vertical(second_half, x, y1, y2)) + if (qt_isect_curve_vertical(first_half, x, y1, y2, depth + 1) + || qt_isect_curve_vertical(second_half, x, y1, y2, depth + 1)) return true; } return false; diff --git a/src/gui/painting/qwindowsurface_s60.cpp b/src/gui/painting/qwindowsurface_s60.cpp index 9f371a8..cb53ea0 100644 --- a/src/gui/painting/qwindowsurface_s60.cpp +++ b/src/gui/painting/qwindowsurface_s60.cpp @@ -63,7 +63,6 @@ struct QS60WindowSurfacePrivate TDisplayMode displayMode(bool opaque) { - TDisplayMode mode = S60->screenDevice()->DisplayMode(); if (opaque) { mode = EColor16MU; @@ -76,10 +75,18 @@ TDisplayMode displayMode(bool opaque) return mode; } +bool blitWriteAlpha(QWidgetPrivate *widgetPrivate) +{ + QWExtra *extra = widgetPrivate->extraData(); + return extra ? extra->nativePaintMode == QWExtra::BlitWriteAlpha : false; +} + QS60WindowSurface::QS60WindowSurface(QWidget* widget) : QWindowSurface(widget), d_ptr(new QS60WindowSurfacePrivate) { - TDisplayMode mode = displayMode(qt_widget_private(widget)->isOpaque); + QWidgetPrivate *widgetPrivate = qt_widget_private(widget); + const bool opaque = widgetPrivate->isOpaque && !blitWriteAlpha(widgetPrivate); + TDisplayMode mode = displayMode(opaque); // We create empty CFbsBitmap here -> it will be resized in setGeometry CFbsBitmap *bitmap = q_check_ptr(new CFbsBitmap); // CBase derived object needs check on new qt_symbian_throwIfError( bitmap->Create( TSize(0, 0), mode ) ); @@ -123,7 +130,8 @@ void QS60WindowSurface::beginPaint(const QRegion &rgn) S60->wsSession().Finish(); #endif - if (!qt_widget_private(window())->isOpaque) { + QWidgetPrivate *windowPrivate = qt_widget_private(window()); + if (!windowPrivate->isOpaque || blitWriteAlpha(windowPrivate)) { QS60PixmapData *pixmapData = static_cast<QS60PixmapData *>(d_ptr->device.data_ptr().data()); TDisplayMode mode = displayMode(false); @@ -132,12 +140,14 @@ void QS60WindowSurface::beginPaint(const QRegion &rgn) pixmapData->beginDataAccess(); - QPainter p(&pixmapData->image); - p.setCompositionMode(QPainter::CompositionMode_Source); - const QVector<QRect> rects = rgn.rects(); - const QColor blank = Qt::transparent; - for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it) { - p.fillRect(*it, blank); + if (!windowPrivate->isOpaque) { + QPainter p(&pixmapData->image); + p.setCompositionMode(QPainter::CompositionMode_Source); + const QVector<QRect> rects = rgn.rects(); + const QColor blank = Qt::transparent; + for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it) { + p.fillRect(*it, blank); + } } pixmapData->endDataAccess(); diff --git a/src/gui/s60framework/qs60mainappui.cpp b/src/gui/s60framework/qs60mainappui.cpp index b5b8b81..4842bc5 100644 --- a/src/gui/s60framework/qs60mainappui.cpp +++ b/src/gui/s60framework/qs60mainappui.cpp @@ -61,6 +61,7 @@ //Animated wallpapers in Qt applications are not supported. const TInt KAknDisableAnimationBackground = 0x02000000; +const TInt KAknSingleClickCompatible = 0x01000000; QT_BEGIN_NAMESPACE @@ -117,8 +118,12 @@ void QS60MainAppUi::ConstructL() // After 5th Edition S60, native side supports animated wallpapers. // However, there is no support for that feature on Qt side, so indicate to // native UI framework that this application will not support background animations. - if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0) - flags |= KAknDisableAnimationBackground; + + // Also, add support for single touch for post 5th edition platforms. + // This has only impact when launching native dialogs/menus from inside QApplication. + if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0) { + flags |= (KAknDisableAnimationBackground | KAknSingleClickCompatible); + } #endif BaseConstructL(flags); } diff --git a/src/gui/styles/qs60style.cpp b/src/gui/styles/qs60style.cpp index 38a4b7c..f146075 100644 --- a/src/gui/styles/qs60style.cpp +++ b/src/gui/styles/qs60style.cpp @@ -72,6 +72,7 @@ #include "qcheckbox.h" #include "qdesktopwidget.h" #include "qprogressbar.h" +#include "qlabel.h" #include "private/qtoolbarextension_p.h" #include "private/qcombobox_p.h" @@ -107,8 +108,8 @@ const short QS60StylePrivate::data[][MAX_PIXELMETRICS] = { // *** generated pixel metrics *** {5,0,-909,0,0,2,0,2,-1,7,12,22,15,15,7,198,-909,-909,-909,20,13,2,0,0,21,7,18,30,3,3,1,-909,-909,0,1,0,0,12,20,15,15,18,18,1,115,18,0,-909,-909,-909,-909,0,0,16,2,-909,0,0,-909,16,-909,-909,-909,-909,32,18,55,24,55,4,4,4,9,13,-909,5,51,11,5,0,3,3,6,8,3,3,-909,2,-909,-909,-909,-909,5,5,3,1,106}, {5,0,-909,0,0,1,0,2,-1,8,14,22,15,15,7,164,-909,-909,-909,19,15,2,0,0,21,8,27,28,4,4,1,-909,-909,0,7,6,0,13,23,17,17,21,21,7,115,21,0,-909,-909,-909,-909,0,0,15,1,-909,0,0,-909,15,-909,-909,-909,-909,32,21,65,27,65,3,3,5,10,15,-909,5,58,13,5,0,4,4,7,9,4,4,-909,2,-909,-909,-909,-909,6,6,3,1,106}, -{7,0,-909,0,0,2,0,5,-1,25,69,46,37,37,9,258,-909,-909,-909,23,19,26,0,0,32,25,72,44,5,5,2,-909,-909,0,7,21,0,17,29,22,22,27,27,7,173,29,0,-909,-909,-909,-909,0,0,25,2,-909,0,0,-909,25,-909,-909,-909,-909,87,27,77,35,77,13,3,6,8,19,-909,7,74,19,7,0,5,5,8,12,5,5,-909,3,-909,-909,-909,-909,7,7,3,1,135}, -{7,0,-909,0,0,2,0,5,-1,25,68,46,37,37,9,258,-909,-909,-909,31,19,6,0,0,32,25,60,52,5,5,2,-909,-909,0,7,32,0,17,29,22,22,27,27,7,173,29,0,-909,-909,-909,-909,0,0,26,2,-909,0,0,-909,26,-909,-909,-909,-909,87,27,96,35,96,12,3,6,8,19,-909,7,74,22,7,0,5,5,8,12,5,5,-909,3,-909,-909,-909,-909,7,7,3,1,135}, +{7,0,-909,0,0,2,0,5,-1,25,69,46,37,37,9,258,-909,-909,-909,23,19,11,0,0,32,25,72,44,5,5,2,-909,-909,0,7,21,0,17,29,22,22,27,27,7,173,29,0,-909,-909,-909,-909,0,0,25,2,-909,0,0,-909,25,-909,-909,-909,-909,87,27,77,35,77,13,3,6,8,19,-909,7,74,19,7,0,5,5,8,12,5,5,-909,3,-909,-909,-909,-909,7,7,3,1,135}, +{7,0,-909,0,0,2,0,5,-1,25,68,46,37,37,9,258,-909,-909,-909,31,19,13,0,0,32,25,60,52,5,5,2,-909,-909,0,7,32,0,17,29,22,22,27,27,7,173,29,0,-909,-909,-909,-909,0,0,26,2,-909,0,0,-909,26,-909,-909,-909,-909,87,27,96,35,96,12,3,6,8,19,-909,7,74,22,7,0,5,5,8,12,5,5,-909,3,-909,-909,-909,-909,7,7,3,1,135}, {7,0,-909,0,0,2,0,2,-1,10,20,27,18,18,9,301,-909,-909,-909,29,18,5,0,0,35,7,32,30,5,5,2,-909,-909,0,2,8,0,16,28,21,21,26,26,2,170,26,0,-909,-909,-909,-909,0,0,21,6,-909,0,0,-909,-909,-909,-909,-909,-909,54,26,265,34,265,5,5,6,3,18,-909,7,72,19,7,0,5,6,8,11,6,5,-909,2,-909,-909,-909,-909,5,5,3,1,106}, {9,0,-909,0,0,2,0,5,-1,34,99,76,51,51,25,352,-909,-909,-909,29,25,7,0,0,43,34,42,76,7,7,2,-909,-909,0,9,14,0,23,39,30,30,37,37,9,391,40,0,-909,-909,-909,-909,0,0,29,2,-909,0,0,-909,29,-909,-909,-909,-909,115,37,96,48,96,19,19,9,1,25,-909,9,101,24,9,0,7,7,7,16,7,7,-909,3,-909,-909,-909,-909,9,9,3,1,184} // *** End of generated data *** @@ -118,6 +119,7 @@ const short *QS60StylePrivate::m_pmPointer = QS60StylePrivate::data[0]; // theme background texture QPixmap *QS60StylePrivate::m_background = 0; +QPixmap *QS60StylePrivate::m_placeHolderTexture = 0; // theme palette QPalette *QS60StylePrivate::m_themePalette = 0; @@ -155,6 +157,10 @@ const double KTabFontMul = 0.72; QS60StylePrivate::~QS60StylePrivate() { clearCaches(); //deletes also background image + if (m_placeHolderTexture) { + delete m_placeHolderTexture; + m_placeHolderTexture = 0; + } deleteThemePalette(); #ifdef Q_WS_S60 removeAnimations(); @@ -505,7 +511,10 @@ void QS60StylePrivate::setBackgroundTexture(QApplication *app) const { Q_UNUSED(app) QPalette applicationPalette = QApplication::palette(); - applicationPalette.setBrush(QPalette::Window, backgroundTexture()); + // The initial QPalette::Window is just a placeHolder QPixmap to save RAM + // if the actual texture is not needed. The real texture is created just before + // painting it in qt_s60_fill_background(). + applicationPalette.setBrush(QPalette::Window, placeHolderTexture()); setThemePalette(&applicationPalette); } @@ -630,25 +639,6 @@ QPixmap QS60StylePrivate::cachedFrame(SkinFrameElements frame, const QSize &size return result; } -void QS60StylePrivate::refreshUI() -{ - QList<QWidget *> widgets = QApplication::allWidgets(); - - for (int i = 0; i < widgets.size(); ++i) { - QWidget *widget = widgets.at(i); - if (widget == 0) - continue; - - if (widget->style()) { - widget->style()->polish(widget); - QEvent event(QEvent::StyleChange); - qApp->sendEvent(widget, &event); - } - widget->update(); - widget->updateGeometry(); - } -} - void QS60StylePrivate::setFont(QWidget *widget) const { QS60StyleEnums::FontCategories fontCategory = QS60StyleEnums::FC_Undefined; @@ -678,7 +668,7 @@ void QS60StylePrivate::setFont(QWidget *widget) const } } -void QS60StylePrivate::setThemePalette(QWidget *widget) const +void QS60StylePrivate::setThemePalette(QWidget *widget) { if(!widget) return; @@ -694,6 +684,13 @@ void QS60StylePrivate::setThemePalette(QWidget *widget) const if (header->viewport()) header->viewport()->setPalette(widgetPalette); QApplication::setPalette(widgetPalette, "QHeaderView"); + } else if (qobject_cast<QLabel *>(widget)) { + if (widget->window() && widget->window()->windowType() == Qt::Dialog) { + QPalette widgetPalette = widget->palette(); + widgetPalette.setColor(QPalette::WindowText, + s60Color(QS60StyleEnums::CL_QsnTextColors, 19, 0)); + widget->setPalette(widgetPalette); + } } } @@ -719,8 +716,10 @@ void QS60StylePrivate::setThemePalette(QPalette *palette) const palette->setColor(QPalette::LinkVisited, palette->color(QPalette::Link).darker()); palette->setColor(QPalette::Highlight, s60Color(QS60StyleEnums::CL_QsnHighlightColors, 2, 0)); - // set background image as a texture brush - palette->setBrush(QPalette::Window, backgroundTexture()); + // The initial QPalette::Window is just a placeHolder QPixmap to save RAM + // if the actual texture is not needed. The real texture is created just before + // painting it in qt_s60_fill_background(). + palette->setBrush(QPalette::Window, placeHolderTexture()); // set as transparent so that styled full screen theme background is visible palette->setBrush(QPalette::Base, Qt::transparent); // set button color based on pixel colors @@ -761,7 +760,7 @@ void QS60StylePrivate::storeThemePalette(QPalette *palette) } // set widget specific palettes -void QS60StylePrivate::setThemePaletteHash(QPalette *palette) const +void QS60StylePrivate::setThemePaletteHash(QPalette *palette) { if (!palette) return; @@ -1551,8 +1550,10 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, skinElement==QS60StylePrivate::SE_TabBarTabWestActive) { const int borderThickness = QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); - const int tabOverlap = - QS60StylePrivate::pixelMetric(PM_TabBarTabOverlap) - borderThickness; + int tabOverlap = pixelMetric(PM_TabBarTabOverlap); + if (tabOverlap > borderThickness) + tabOverlap -= borderThickness; + const bool usesScrollButtons = (widget) ? (qobject_cast<const QTabBar*>(widget))->usesScrollButtons() : false; const int roomForScrollButton = @@ -1591,9 +1592,11 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, QStyleOptionTabV3 optionTab = *tab; QRect tr = optionTab.rect; const bool directionMirrored = (optionTab.direction == Qt::RightToLeft); - const int borderThickness = QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); - const int tabOverlap = - QS60StylePrivate::pixelMetric(PM_TabBarTabOverlap) - borderThickness; + const int borderThickness = + QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); + int tabOverlap = pixelMetric(PM_TabBarTabOverlap); + if (tabOverlap > borderThickness) + tabOverlap -= borderThickness; const bool usesScrollButtons = (widget) ? (qobject_cast<const QTabBar*>(widget))->usesScrollButtons() : false; const int roomForScrollButton = @@ -1752,16 +1755,26 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, QStyleOptionMenuItem optionMenuItem = *menuItem; bool drawSubMenuIndicator = false; + bool drawSeparator = false; switch(menuItem->menuItemType) { - case QStyleOptionMenuItem::Scroller: case QStyleOptionMenuItem::Separator: - return; // no separators or scrollers in S60 menus + drawSeparator = true; + break; + case QStyleOptionMenuItem::Scroller: + return; // no scrollers in S60 menus case QStyleOptionMenuItem::SubMenu: drawSubMenuIndicator = true; break; default: break; } + if (drawSeparator) { + painter->save(); + painter->setPen(QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnLineColors, 10, 0)); + painter->drawLine(optionMenuItem.rect.topLeft(), optionMenuItem.rect.bottomRight()); + painter->restore(); + return; + } const bool enabled = optionMenuItem.state & State_Enabled; const bool checkable = optionMenuItem.checkType != QStyleOptionMenuItem::NotCheckable; bool ignoreCheckMark = false; @@ -1865,20 +1878,26 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, //In Sym^3, native menu items have "lines" between them if (QS60StylePrivate::isSingleClickUi()) { - const QColor lineColorAlpha = QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnLineColors, 15, 0); - const int spacing = QS60StylePrivate::pixelMetric(PM_FrameCornerWidth); - //native platform sets each color byte to same value for "line 16" which just defines alpha for - //menuitem lines; lets use first byte "red". - QColor lineColor = optionMenuItem.palette.text().color(); - if (lineColorAlpha.isValid()) - lineColor.setAlpha(lineColorAlpha.red()); - painter->save(); - painter->setPen(lineColor); - - const int lineStartX = optionMenuItem.rect.left() + (QS60StylePrivate::pixelMetric(PM_FrameCornerWidth) - 2) + spacing; - const int lineEndX = optionMenuItem.rect.right() - (QS60StylePrivate::pixelMetric(PM_FrameCornerWidth) - 2) - spacing; - painter->drawLine(QPoint(lineStartX, optionMenuItem.rect.bottom()), QPoint(lineEndX, optionMenuItem.rect.bottom())); - painter->restore(); + int diff = widget->geometry().bottom() - optionMenuItem.rect.bottom(); + if (const QComboBox *cb = qobject_cast<const QComboBox*>(widget)) + diff = cb->view()->geometry().bottom() - optionMenuItem.rect.bottom(); + + // Skip drawing the horizontal line for the last menu item. + if (diff > optionMenuItem.rect.height()) { + const QColor lineColorAlpha = QS60StylePrivate::s60Color(QS60StyleEnums::CL_QsnLineColors, 15, 0); + //native platform sets each color byte to same value for "line 16" which just defines alpha for + //menuitem lines; lets use first byte "red". + QColor lineColor = optionMenuItem.palette.text().color(); + if (lineColorAlpha.isValid()) + lineColor.setAlpha(lineColorAlpha.red()); + painter->save(); + painter->setPen(lineColor); + const int horizontalMargin = 2 * QS60StylePrivate::pixelMetric(PM_FrameCornerWidth) - QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); + const int lineStartX = optionMenuItem.rect.left() + horizontalMargin; + const int lineEndX = optionMenuItem.rect.right() - horizontalMargin; + painter->drawLine(QPoint(lineStartX, optionMenuItem.rect.bottom()), QPoint(lineEndX, optionMenuItem.rect.bottom())); + painter->restore(); + } } if (!enabled) painter->restore(); @@ -2273,13 +2292,16 @@ void QS60Style::drawPrimitive(PrimitiveElement element, const QStyleOption *opti #endif //QT_NO_MENU ) { //Need extra check since dialogs have their own theme background - if (QS60StylePrivate::canDrawThemeBackground(option->palette.base(), widget) && - QS60StylePrivate::equalToThemePalette(option->palette.window().texture().cacheKey(), QPalette::Window)) - //todo: for combobox listviews, the background should include area for menu scrollers, - //but this produces drawing issues as we need to turn clipping off. - QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_PopupBackground, painter, option->rect, flags); - else + if (QS60StylePrivate::canDrawThemeBackground(option->palette.base(), widget) + && QS60StylePrivate::equalToThemePalette(option->palette.window().texture().cacheKey(), QPalette::Window)) { + const bool comboMenu = qobject_cast<const QComboBoxListView *>(widget); + // Add margin area to the background, to avoid background being cut for first and last item. + const int verticalMenuAdjustment = comboMenu ? QS60StylePrivate::pixelMetric(PM_MenuVMargin) : 0; + const QRect adjustedMenuRect = option->rect.adjusted(0, -verticalMenuAdjustment, 0, verticalMenuAdjustment); + QS60StylePrivate::drawSkinElement(QS60StylePrivate::SE_PopupBackground, painter, adjustedMenuRect, flags); + } else { commonStyleDraws = true; + } } break; case PE_FrameWindow: @@ -2523,6 +2545,11 @@ int QS60Style::pixelMetric(PixelMetric metric, const QStyleOption *option, const //without having to define custom pixel metric metricValue *= 2; +#if defined(Q_WS_S60) + if (metric == PM_TabBarTabOverlap && (QSysInfo::s60Version() > QSysInfo::SV_S60_5_2)) + metricValue = 0; +#endif + return metricValue; } @@ -2547,17 +2574,16 @@ QSize QS60Style::sizeFromContents(ContentsType ct, const QStyleOption *opt, tb->sizePolicy().horizontalPolicy() == QSizePolicy::Maximum) && tb->orientation() == Qt::Horizontal; if (parentCanGrowHorizontally) { - int visibleButtons = 0; + int buttons = 0; //Make the auto-stretch to happen only for horizontal orientation if (tb && tb->orientation() == Qt::Horizontal) { QList<QAction*> actionList = tb->actions(); for (int i = 0; i < actionList.count(); i++) { - if (actionList.at(i)->isVisible()) - visibleButtons++; + buttons++; } } - if (widget->parentWidget() && visibleButtons > 0) { + if (widget->parentWidget() && buttons > 0) { QWidget *w = const_cast<QWidget *>(widget); int toolBarMaxWidth = 0; int totalMargin = 0; @@ -2580,7 +2606,7 @@ QSize QS60Style::sizeFromContents(ContentsType ct, const QStyleOption *opt, toolBarMaxWidth -= totalMargin; //ensure that buttons are side-by-side and not on top of each other - const int toolButtonWidth = (toolBarMaxWidth / visibleButtons) + const int toolButtonWidth = (toolBarMaxWidth / buttons) - pixelMetric(QStyle::PM_ToolBarItemSpacing) - pixelMetric(QStyle::PM_ToolBarItemMargin) //toolbar frame needs to be reduced again, since QToolBarLayout adds it for each toolbar action @@ -2613,10 +2639,7 @@ QSize QS60Style::sizeFromContents(ContentsType ct, const QStyleOption *opt, sz += QSize(2 * f->lineWidth, 4 * f->lineWidth); break; case CT_TabBarTab: { - const QSize naviPaneSize = QS60StylePrivate::naviPaneSize(); sz = QCommonStyle::sizeFromContents(ct, opt, csz, widget); - if (naviPaneSize.height() > sz.height()) - sz.setHeight(naviPaneSize.height()); // Adjust beginning tabbar item size, if scrollbuttons are used. This is to ensure that the // tabbar item content fits, since scrollbuttons are making beginning tabbar item smaller. int scrollButtonSize = 0; @@ -2636,17 +2659,18 @@ QSize QS60Style::sizeFromContents(ContentsType ct, const QStyleOption *opt, case CT_ItemViewItem: if (const QStyleOptionMenuItem *menuItem = qstyleoption_cast<const QStyleOptionMenuItem *>(opt)) { if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) { - sz = QSize(); + sz = QSize(menuItem->rect.width() - 2 * pixelMetric(PM_MenuHMargin) - 2 * QS60StylePrivate::pixelMetric(PM_FrameCornerWidth), 1); break; } } sz = QCommonStyle::sizeFromContents( ct, opt, csz, widget); - //native items have small empty areas at the beginning and end of menu item - sz.setWidth(sz.width() + 2 * pixelMetric(PM_MenuHMargin) + 2 * QS60StylePrivate::pixelMetric(PM_FrameCornerWidth)); - if (QS60StylePrivate::isTouchSupported()) + if (QS60StylePrivate::isTouchSupported()) { //Make itemview easier to use in touch devices + sz.setHeight(sz.height() + 2 * pixelMetric(PM_FocusFrameVMargin)); //QCommonStyle does not adjust height with horizontal margin, it only adjusts width - sz.setHeight(sz.height() + 2 * pixelMetric(PM_FocusFrameVMargin) - 8); //QCommonstyle adds 8 to height that this style handles through PM values + if (ct == CT_MenuItem) + sz.setHeight(sz.height() - 8); //QCommonstyle adds 8 to height that this style handles through PM values + } break; #ifndef QT_NO_COMBOBOX case CT_ComboBox: { @@ -2998,10 +3022,11 @@ QRect QS60Style::subElementRect(SubElement element, const QStyleOption *opt, con ret = QCommonStyle::subElementRect(element, opt, widget); if (const QStyleOptionTabWidgetFrame *twf = qstyleoption_cast<const QStyleOptionTabWidgetFrame *>(opt)) { - const int tabOverlapNoBorder = - QS60StylePrivate::pixelMetric(PM_TabBarTabOverlap); - const int tabOverlap = - tabOverlapNoBorder - QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); + const int borderThickness = + QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); + int tabOverlap = pixelMetric(PM_TabBarTabOverlap); + if (tabOverlap > borderThickness) + tabOverlap -= borderThickness; const QTabWidget *tab = qobject_cast<const QTabWidget *>(widget); int gain = (tab) ? tabOverlap * tab->count() : 0; switch (twf->shape) { @@ -3019,7 +3044,7 @@ QRect QS60Style::subElementRect(SubElement element, const QStyleOption *opt, con if ((ret.right() + gain) > widget->rect().right()) gain = widget->rect().right() - ret.right(); ret.adjust(0, 0, gain, 0); - } + } } break; } @@ -3107,7 +3132,7 @@ QRect QS60Style::subElementRect(SubElement element, const QStyleOption *opt, con } break; case SE_ItemViewItemCheckIndicator: - if (const QStyleOptionViewItemV2 *vopt = qstyleoption_cast<const QStyleOptionViewItemV2 *>(opt)) { + if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast<const QStyleOptionViewItemV4 *>(opt)) { const QAbstractItemView *listItem = qobject_cast<const QAbstractItemView *>(widget); const bool singleSelection = listItem && @@ -3115,7 +3140,7 @@ QRect QS60Style::subElementRect(SubElement element, const QStyleOption *opt, con listItem->selectionMode() == QAbstractItemView::NoSelection); const bool checkBoxOnly = (vopt->features & QStyleOptionViewItemV2::HasCheckIndicator) && listItem && - singleSelection; + singleSelection && vopt->text.isEmpty() && vopt->icon.isNull(); // Selection check mark rect. const int indicatorWidth = QS60StylePrivate::pixelMetric(PM_IndicatorWidth); @@ -3359,9 +3384,9 @@ bool QS60Style::event(QEvent *e) QIcon QS60Style::standardIconImplementation(StandardPixmap standardIcon, const QStyleOption *option, const QWidget *widget) const { - const int iconDimension = QS60StylePrivate::pixelMetric(PM_ToolBarIconSize); - const QRect iconSize = (!option) ? QRect(0, 0, iconDimension, iconDimension) : option->rect; QS60StyleEnums::SkinParts part; + qreal iconHeightMultiplier = 1.0; + qreal iconWidthMultiplier = 1.0; QS60StylePrivate::SkinElementFlags adjustedFlags; if (option) adjustedFlags = (option->state & State_Enabled || option->state == 0) ? @@ -3370,15 +3395,20 @@ QIcon QS60Style::standardIconImplementation(StandardPixmap standardIcon, switch(standardIcon) { case SP_MessageBoxWarning: + // By default, S60 messagebox icons have 4:3 ratio. Value is from S60 LAF documentation. + iconHeightMultiplier = 1.33; part = QS60StyleEnums::SP_QgnNoteWarning; break; case SP_MessageBoxInformation: + iconHeightMultiplier = 1.33; part = QS60StyleEnums::SP_QgnNoteInfo; break; case SP_MessageBoxCritical: + iconHeightMultiplier = 1.33; part = QS60StyleEnums::SP_QgnNoteError; break; case SP_MessageBoxQuestion: + iconHeightMultiplier = 1.33; part = QS60StyleEnums::SP_QgnNoteQuery; break; case SP_ArrowRight: @@ -3433,11 +3463,13 @@ QIcon QS60Style::standardIconImplementation(StandardPixmap standardIcon, adjustedFlags |= QS60StylePrivate::SF_PointEast; part = QS60StyleEnums::SP_QgnIndiSubmenu; break; - default: return QCommonStyle::standardIconImplementation(standardIcon, option, widget); } const QS60StylePrivate::SkinElementFlags flags = adjustedFlags; + const int iconDimension = QS60StylePrivate::pixelMetric(PM_ToolBarIconSize); + const QRect iconSize = (!option) ? + QRect(0, 0, iconDimension * iconWidthMultiplier, iconDimension * iconHeightMultiplier) : option->rect; const QPixmap cachedPixMap(QS60StylePrivate::cachedPart(part, iconSize.size(), 0, flags)); return cachedPixMap.isNull() ? QCommonStyle::standardIconImplementation(standardIcon, option, widget) : QIcon(cachedPixMap); @@ -3545,10 +3577,18 @@ extern QPoint qt_s60_fill_background_offset(const QWidget *targetWidget); bool qt_s60_fill_background(QPainter *painter, const QRegion &rgn, const QBrush &brush) { - const QPixmap backgroundTexture(QS60StylePrivate::backgroundTexture()); - if (backgroundTexture.cacheKey() != brush.texture().cacheKey()) + // Check if the widget's palette matches placeholder or actual background texture. + // When accessing backgroundTexture, use parameter value 'true' to avoid creating + // the texture, if it is not already created. + + const QPixmap placeHolder(QS60StylePrivate::placeHolderTexture()); + const QPixmap bg(QS60StylePrivate::backgroundTexture(true)); + if (placeHolder.cacheKey() != brush.texture().cacheKey() + && bg.cacheKey() != brush.texture().cacheKey()) return false; + const QPixmap backgroundTexture(QS60StylePrivate::backgroundTexture()); + const QPaintDevice *target = painter->device(); if (target->devType() == QInternal::Widget) { const QWidget *widget = static_cast<const QWidget *>(target); diff --git a/src/gui/styles/qs60style_p.h b/src/gui/styles/qs60style_p.h index 242c451..e146a4e 100644 --- a/src/gui/styles/qs60style_p.h +++ b/src/gui/styles/qs60style_p.h @@ -554,15 +554,14 @@ public: static QPixmap frame(SkinFrameElements frame, const QSize &size, SkinElementFlags flags = KDefaultSkinElementFlags); - static QPixmap backgroundTexture(); + static QPixmap backgroundTexture(bool skipCreation = false); + static QPixmap placeHolderTexture(); #ifdef Q_WS_S60 void handleDynamicLayoutVariantSwitch(); void handleSkinChange(); #endif // Q_WS_S60 - static QSize naviPaneSize(); - //Checks that the current brush is transparent or has BrushStyle NoBrush, //so that theme graphic background can be drawn. static bool canDrawThemeBackground(const QBrush &backgroundBrush, const QWidget *widget); @@ -592,13 +591,11 @@ private: static QPixmap cachedFrame(SkinFrameElements frame, const QSize &size, SkinElementFlags flags = KDefaultSkinElementFlags); - static void refreshUI(); - // set S60 font for widget void setFont(QWidget *widget) const; - void setThemePalette(QWidget *widget) const; + static void setThemePalette(QWidget *widget); void setThemePalette(QPalette *palette) const; - void setThemePaletteHash(QPalette *palette) const; + static void setThemePaletteHash(QPalette *palette); static void storeThemePalette(QPalette *palette); static void deleteThemePalette(); static bool equalToThemePalette(QColor color, QPalette::ColorRole role); @@ -616,6 +613,9 @@ private: // Contains background texture. static QPixmap *m_background; + // Placeholder pixmap for the real background texture. + static QPixmap *m_placeHolderTexture; + const static SkinElementFlags KDefaultSkinElementFlags; // defined theme palette static QPalette *m_themePalette; diff --git a/src/gui/styles/qs60style_s60.cpp b/src/gui/styles/qs60style_s60.cpp index 600c631..dc64872 100644 --- a/src/gui/styles/qs60style_s60.cpp +++ b/src/gui/styles/qs60style_s60.cpp @@ -66,7 +66,6 @@ #include <aknnavi.h> #include <gulicon.h> #include <AknBitmapAnimation.h> - #include <centralrepository.h> #if !defined(QT_NO_STYLE_S60) || defined(QT_PLUGIN) @@ -90,17 +89,25 @@ enum TSupportRelease { ES60_5_0 = 0x0004, ES60_5_1 = 0x0008, ES60_5_2 = 0x0010, + ES60_5_3 = 0x0020, ES60_3_X = ES60_3_1 | ES60_3_2, // Releases before Symbian Foundation ES60_PreSF = ES60_3_1 | ES60_3_2 | ES60_5_0, + // Releases before the S60 5.2 + 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, // Add all new releases here - ES60_All = ES60_3_1 | ES60_3_2 | ES60_5_0 | ES60_5_1 | ES60_5_2 + ES60_All = ES60_3_1 | ES60_3_2 | ES60_5_0 | ES60_5_1 | ES60_5_2 | ES60_5_3 }; typedef struct { - const TAknsItemID &skinID; - TDrawType drawType; - int supportInfo; + const TAknsItemID &skinID; // Determines default theme graphics ID. + TDrawType drawType; // Determines which native drawing routine is used to draw this item. + int supportInfo; // Defines the S60 versions that use the default graphics. + // These two, define new graphics that are used in releases other than partMapEntry.supportInfo defined releases. + // In general, these are given in numeric form to allow style compilation in earlier + // native releases that do not contain the new graphics. int newMajorSkinId; int newMinorSkinId; } partMapEntry; @@ -159,7 +166,6 @@ public: static bool disabledPartGraphic(QS60StyleEnums::SkinParts &part); static bool disabledFrameGraphic(QS60StylePrivate::SkinFrameElements &frame); static QPixmap generateMissingThemeGraphic(QS60StyleEnums::SkinParts &part, const QSize &size, QS60StylePrivate::SkinElementFlags flags); - static QSize naviPaneSize(); static TAknsItemID partSpecificThemeId(int part); static QVariant themeDefinition(QS60StyleEnums::ThemeDefinitions definition, QS60StyleEnums::SkinParts part); @@ -190,12 +196,14 @@ const partMapEntry QS60StyleModeSpecifics::m_partMap[] = { /* SP_QgnGrafScrollArrowLeft */ {KAknsIIDQgnGrafScrollArrowLeft, EDrawGulIcon, ES60_All, -1,-1}, /* SP_QgnGrafScrollArrowRight */ {KAknsIIDQgnGrafScrollArrowRight, EDrawGulIcon, ES60_All, -1,-1}, /* SP_QgnGrafScrollArrowUp */ {KAknsIIDQgnGrafScrollArrowUp, EDrawGulIcon, ES60_All, -1,-1}, - /* SP_QgnGrafTabActiveL */ {KAknsIIDQgnGrafTabActiveL, EDrawIcon, ES60_All, -1,-1}, - /* SP_QgnGrafTabActiveM */ {KAknsIIDQgnGrafTabActiveM, EDrawIcon, ES60_All, -1,-1}, - /* SP_QgnGrafTabActiveR */ {KAknsIIDQgnGrafTabActiveR, EDrawIcon, ES60_All, -1,-1}, - /* SP_QgnGrafTabPassiveL */ {KAknsIIDQgnGrafTabPassiveL, EDrawIcon, ES60_All, -1,-1}, - /* SP_QgnGrafTabPassiveM */ {KAknsIIDQgnGrafTabPassiveM, EDrawIcon, ES60_All, -1,-1}, - /* SP_QgnGrafTabPassiveR */ {KAknsIIDQgnGrafTabPassiveR, EDrawIcon, ES60_All, -1,-1}, + + // In S60 5.3 there is a new tab graphic + /* SP_QgnGrafTabActiveL */ {KAknsIIDQgnGrafTabActiveL, EDrawIcon, ES60_Pre53, EAknsMajorSkin, 0x2219}, //KAknsIIDQtgFrTabActiveNormalL + /* SP_QgnGrafTabActiveM */ {KAknsIIDQgnGrafTabActiveM, EDrawIcon, ES60_Pre53, EAknsMajorSkin, 0x221b}, //KAknsIIDQtgFrTabActiveNormalC + /* SP_QgnGrafTabActiveR */ {KAknsIIDQgnGrafTabActiveR, EDrawIcon, ES60_Pre53, EAknsMajorSkin, 0x221a}, //KAknsIIDQtgFrTabActiveNormalR + /* SP_QgnGrafTabPassiveL */ {KAknsIIDQgnGrafTabPassiveL, EDrawIcon, ES60_Pre53, EAknsMajorSkin, 0x2221}, //KAknsIIDQtgFrTabPassiveNormalL + /* SP_QgnGrafTabPassiveM */ {KAknsIIDQgnGrafTabPassiveM, EDrawIcon, ES60_Pre53, EAknsMajorSkin, 0x2223}, //KAknsIIDQtgFrTabPassiveNormalC + /* SP_QgnGrafTabPassiveR */ {KAknsIIDQgnGrafTabPassiveR, EDrawIcon, ES60_Pre53, EAknsMajorSkin, 0x2222}, //KAknsIIDQtgFrTabPassiveNormalR // In 3.1 there is no slider groove. /* SP_QgnGrafNsliderEndLeft */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x19cf /* KAknsIIDQgnGrafNsliderEndLeft */}, @@ -640,13 +648,14 @@ QPixmap QS60StyleModeSpecifics::fromFbsBitmap(CFbsBitmap *icon, CFbsBitmap *mask QPixmap pixmap; QScopedPointer<QPixmapData> pd(QPixmapData::create(0, 0, QPixmapData::PixmapType)); - bool nativeMaskSupported = (pd->toNativeType(QPixmapData::VolatileImage) != 0); - if (mask && nativeMaskSupported) { - // Efficient path, less copying and conversion. + if (mask) { + // Try the efficient path with less copying and conversion. QVolatileImage img(icon, mask); pd->fromNativeType(&img, QPixmapData::VolatileImage); - pixmap = QPixmap(pd.take()); - } else { + if (!pd->isNull()) + pixmap = QPixmap(pd.take()); + } + if (pixmap.isNull()) { // Potentially more expensive path. pd->fromNativeType(icon, QPixmapData::FbsBitmap); pixmap = QPixmap(pd.take()); @@ -1141,7 +1150,8 @@ bool QS60StyleModeSpecifics::checkSupport(const int supportedRelease) (currentRelease == QSysInfo::SV_S60_3_2 && supportedRelease & ES60_3_2) || (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_2 && supportedRelease & ES60_5_2) || + (currentRelease == QSysInfo::SV_S60_5_3 && supportedRelease & ES60_5_3) ); } TAknsItemID QS60StyleModeSpecifics::partSpecificThemeId(int part) @@ -1391,7 +1401,7 @@ QPixmap QS60StylePrivate::frame(SkinFrameElements frame, const QSize &size, Skin return result; } -QPixmap QS60StylePrivate::backgroundTexture() +QPixmap QS60StylePrivate::backgroundTexture(bool skipCreation) { bool createNewBackground = false; TRect applicationRect = (static_cast<CEikAppUi*>(S60->appUi())->ApplicationRect()); @@ -1402,18 +1412,45 @@ QPixmap QS60StylePrivate::backgroundTexture() if (m_background->width() != applicationRect.Width() || m_background->height() != applicationRect.Height()) { delete m_background; + m_background = 0; createNewBackground = true; } } - if (createNewBackground) { + if (createNewBackground && !skipCreation) { QPixmap background = part(QS60StyleEnums::SP_QsnBgScreen, - QSize(applicationRect.Width(), applicationRect.Height()), 0, SkinElementFlags()); + QSize(applicationRect.Width(), applicationRect.Height()), 0, SkinElementFlags()); m_background = new QPixmap(background); + + // Notify all widgets that palette is updated with the actual background texture. + QPalette pal = QApplication::palette(); + pal.setBrush(QPalette::Window, *m_background); + QApplication::setPalette(pal); + setThemePaletteHash(&pal); + storeThemePalette(&pal); + foreach (QWidget *widget, QApplication::allWidgets()){ + QEvent e(QEvent::PaletteChange); + QApplication::sendEvent(widget, &e); + setThemePalette(widget); + widget->ensurePolished(); + } } + if (!m_background) + return QPixmap(); return *m_background; } +// Generates 1*1 white pixmap as a placeholder for real texture. +// The actual theme texture is drawn in qt_s60_fill_background(). +QPixmap QS60StylePrivate::placeHolderTexture() +{ + if (!m_placeHolderTexture) { + m_placeHolderTexture = new QPixmap(1,1); + m_placeHolderTexture->fill(Qt::white); + } + return *m_placeHolderTexture; +} + QSize QS60StylePrivate::screenSize() { return QSize(S60->screenWidthInPixels, S60->screenHeightInPixels); @@ -1428,8 +1465,8 @@ QS60Style::QS60Style() void QS60StylePrivate::handleDynamicLayoutVariantSwitch() { clearCaches(QS60StylePrivate::CC_LayoutChange); + setBackgroundTexture(qApp); setActiveLayout(); - refreshUI(); foreach (QWidget *widget, QApplication::allWidgets()) widget->ensurePolished(); } @@ -1451,23 +1488,6 @@ void QS60StylePrivate::handleSkinChange() #endif } -QSize QS60StylePrivate::naviPaneSize() -{ - return QS60StyleModeSpecifics::naviPaneSize(); -} - -QSize QS60StyleModeSpecifics::naviPaneSize() -{ - CAknNavigationControlContainer* naviContainer; - if (S60->statusPane()) { - TRAPD(err, naviContainer = static_cast<CAknNavigationControlContainer*> - (S60->statusPane()->ControlL(TUid::Uid(EEikStatusPaneUidNavi)))); - if (err==KErrNone) - return QSize(naviContainer->Size().iWidth, naviContainer->Size().iHeight); - } - return QSize(0,0); -} - int QS60StylePrivate::currentAnimationFrame(QS60StyleEnums::SkinParts part) { QS60StyleAnimation *animation = animationDefinition(part); diff --git a/src/gui/styles/qs60style_simulated.cpp b/src/gui/styles/qs60style_simulated.cpp index 77e0d0e..a5aeac3 100644 --- a/src/gui/styles/qs60style_simulated.cpp +++ b/src/gui/styles/qs60style_simulated.cpp @@ -308,7 +308,7 @@ QPixmap QS60StylePrivate::frame(SkinFrameElements frame, const QSize &size, return result; } -QPixmap QS60StylePrivate::backgroundTexture() +QPixmap QS60StylePrivate::backgroundTexture(bool /*skipCreation*/) { if (!m_background) { const QSize size = QApplication::desktop()->screen()->size(); @@ -318,11 +318,6 @@ QPixmap QS60StylePrivate::backgroundTexture() return *m_background; } -QSize QS60StylePrivate::naviPaneSize() -{ - return QSize(0, 0); -} - bool QS60StylePrivate::isTouchSupported() { #ifdef QT_KEYPAD_NAVIGATION diff --git a/src/gui/styles/qstylesheetstyle.cpp b/src/gui/styles/qstylesheetstyle.cpp index a4e7c38..369a0f0 100644 --- a/src/gui/styles/qstylesheetstyle.cpp +++ b/src/gui/styles/qstylesheetstyle.cpp @@ -3339,6 +3339,13 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q } break; + case CE_FocusFrame: + if (!rule.hasNativeBorder()) { + rule.drawBorder(p, opt->rect); + return; + } + break; + case CE_PushButton: if (const QStyleOptionButton *btn = qstyleoption_cast<const QStyleOptionButton *>(opt)) { if (rule.hasDrawable() || rule.hasBox() || rule.hasPosition() || rule.hasPalette() || diff --git a/src/gui/text/qfontengine_mac.mm b/src/gui/text/qfontengine_mac.mm index 42b9402..05e3d3c 100644 --- a/src/gui/text/qfontengine_mac.mm +++ b/src/gui/text/qfontengine_mac.mm @@ -144,7 +144,7 @@ void qmacfontengine_gamma_correct(QImage *image) #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 -QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const ATSFontFamilyRef &, const ATSFontRef &atsFontRef, const QFontDef &fontDef, bool kerning) +QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const ATSFontFamilyRef &atsFamilyRef, const ATSFontRef &atsFontRef, const QFontDef &fontDef, bool kerning) : QFontEngineMulti(0) { this->fontDef = fontDef; @@ -162,6 +162,8 @@ QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const ATSFontFamilyRef &, con QCFString name; ATSFontGetName(atsFontRef, kATSOptionFlagsDefault, &name); + if (QString(name).isEmpty()) + ATSFontFamilyGetName(atsFamilyRef, kATSOptionFlagsDefault, &name); transform = CGAffineTransformIdentity; if (fontDef.stretch != 100) { diff --git a/src/gui/text/qfragmentmap_p.h b/src/gui/text/qfragmentmap_p.h index 501bfff..4057142 100644 --- a/src/gui/text/qfragmentmap_p.h +++ b/src/gui/text/qfragmentmap_p.h @@ -195,6 +195,10 @@ public: head->root = new_root; } + inline bool isValid(uint n) const { + return n > 0 && n != head->freelist; + } + union { Header *head; Fragment *fragments; @@ -854,6 +858,7 @@ public: return data.fragment(index); } inline uint position(uint node, uint field = 0) const { return data.position(node, field); } + inline bool isValid(uint n) const { return data.isValid(n); } inline uint next(uint n) const { return data.next(n); } inline uint previous(uint n) const { return data.previous(n); } inline uint size(uint node, uint field = 0) const { return data.size(node, field); } diff --git a/src/gui/text/qtextcontrol.cpp b/src/gui/text/qtextcontrol.cpp index f5da079..bee4d95 100644 --- a/src/gui/text/qtextcontrol.cpp +++ b/src/gui/text/qtextcontrol.cpp @@ -1551,7 +1551,7 @@ void QTextControlPrivate::mousePressEvent(QEvent *e, Qt::MouseButton button, con extendBlockwiseSelection(cursorPos); else if (selectedWordOnDoubleClick.hasSelection()) extendWordwiseSelection(cursorPos, pos.x()); - else if (wordSelectionEnabled) + else if (!wordSelectionEnabled) setCursorPosition(cursorPos, QTextCursor::KeepAnchor); } else { @@ -1607,7 +1607,10 @@ void QTextControlPrivate::mouseMoveEvent(QEvent *e, Qt::MouseButton button, cons if (!(buttons & Qt::LeftButton)) return; - if (!((interactionFlags & Qt::TextSelectableByMouse) || (interactionFlags & Qt::TextEditable))) + const bool selectable = interactionFlags & Qt::TextSelectableByMouse; + const bool editable = interactionFlags & Qt::TextEditable; + + if (!selectable && !editable) return; if (!(mousePressed @@ -1623,6 +1626,10 @@ void QTextControlPrivate::mouseMoveEvent(QEvent *e, Qt::MouseButton button, cons startDrag(); return; } + + if (!selectable) + return; + const qreal mouseX = qreal(mousePos.x()); int newCursorPos = q->hitTest(mousePos, Qt::FuzzyHit); @@ -1638,7 +1645,7 @@ void QTextControlPrivate::mouseMoveEvent(QEvent *e, Qt::MouseButton button, cons extendBlockwiseSelection(newCursorPos); else if (selectedWordOnDoubleClick.hasSelection()) extendWordwiseSelection(newCursorPos, mouseX); - else if (interactionFlags & Qt::TextSelectableByMouse) + else setCursorPosition(newCursorPos, QTextCursor::KeepAnchor); if (interactionFlags & Qt::TextEditable) { @@ -1943,6 +1950,7 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) if (isGettingInput) layout->setPreeditArea(cursor.position() - block.position(), e->preeditString()); QList<QTextLayout::FormatRange> overrides; + const int oldPreeditCursor = preeditCursor; preeditCursor = e->preeditString().length(); hideCursor = false; for (int i = 0; i < e->attributes().size(); ++i) { @@ -1963,6 +1971,8 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) } layout->setAdditionalFormats(overrides); cursor.endEditBlock(); + if (oldPreeditCursor != preeditCursor) + emit q->microFocusChanged(); } QVariant QTextControl::inputMethodQuery(Qt::InputMethodQuery property) const diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp index a1dcb63..5e59341 100644 --- a/src/gui/text/qtextdocumentlayout.cpp +++ b/src/gui/text/qtextdocumentlayout.cpp @@ -3148,7 +3148,7 @@ QRectF QTextDocumentLayoutPrivate::frameBoundingRectInternal(QTextFrame *frame) QRectF QTextDocumentLayout::blockBoundingRect(const QTextBlock &block) const { Q_D(const QTextDocumentLayout); - if (d->docPrivate->pageSize.isNull()) + if (d->docPrivate->pageSize.isNull() || !block.isValid()) return QRectF(); d->ensureLayoutedByPosition(block.position() + block.length()); QTextFrame *frame = d->document->frameAt(block.position()); diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index b511b5a..4378c62 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -1233,6 +1233,8 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const shaper_item.num_glyphs -= itemBoundaries[k + 1]; } shaper_item.initialGlyphCount = shaper_item.num_glyphs; + if (shaper_item.num_glyphs < shaper_item.item.length) + shaper_item.num_glyphs = shaper_item.item.length; QFontEngine *actualFontEngine = font; uint engineIdx = 0; @@ -1257,7 +1259,8 @@ void QTextEngine::shapeTextWithHarfbuzz(int item) const } const QGlyphLayout g = availableGlyphs(&si).mid(glyph_pos); - moveGlyphData(g.mid(shaper_item.num_glyphs), g.mid(shaper_item.initialGlyphCount), remaining_glyphs); + if (shaper_item.num_glyphs > shaper_item.item.length) + moveGlyphData(g.mid(shaper_item.num_glyphs), g.mid(shaper_item.initialGlyphCount), remaining_glyphs); shaper_item.glyphs = g.glyphs; shaper_item.attributes = g.attributes; diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index a996f59..905f81b 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -1682,6 +1682,7 @@ namespace { int glyphCount; int maxGlyphs; int currentPosition; + glyph_t previousGlyph; QFixed minw; QFixed softHyphenWidth; @@ -1709,6 +1710,15 @@ namespace { return glyphs.glyphs[logClusters[currentPosition - 1]]; } + inline void saveCurrentGlyph() + { + previousGlyph = 0; + if (currentPosition > 0 && + logClusters[currentPosition - 1] < glyphs.numGlyphs) { + previousGlyph = currentGlyph(); // needed to calculate right bearing later + } + } + inline void adjustRightBearing(glyph_t glyph) { qreal rb; @@ -1723,6 +1733,12 @@ namespace { adjustRightBearing(currentGlyph()); } + inline void adjustPreviousRightBearing() + { + if (previousGlyph > 0) + adjustRightBearing(previousGlyph); + } + inline void resetRightBearing() { rightBearing = QFixed(1); // Any positive number is defined as invalid since only @@ -1798,22 +1814,7 @@ void QTextLine::layout_helper(int maxGlyphs) lbh.manualWrap = (wrapMode == QTextOption::ManualWrap || wrapMode == QTextOption::NoWrap); int item = -1; - int newItem = -1; - int left = 0; - int right = eng->layoutData->items.size()-1; - while(left <= right) { - int middle = ((right-left)/2)+left; - if (line.from > eng->layoutData->items[middle].position) - left = middle+1; - else if(line.from < eng->layoutData->items[middle].position) - right = middle-1; - else { - newItem = middle; - break; - } - } - if (newItem == -1) - newItem = right; + int newItem = eng->findItem(line.from); LB_DEBUG("from: %d: item=%d, total %d, width available %f", line.from, newItem, eng->layoutData->items.size(), line.width.toReal()); @@ -1825,6 +1826,7 @@ void QTextLine::layout_helper(int maxGlyphs) lbh.currentPosition = line.from; int end = 0; lbh.logClusters = eng->layoutData->logClustersPtr; + lbh.previousGlyph = 0; while (newItem < eng->layoutData->items.size()) { lbh.resetRightBearing(); @@ -1885,6 +1887,7 @@ void QTextLine::layout_helper(int maxGlyphs) current, lbh.logClusters, lbh.glyphs); } else { lbh.tmpData.length++; + lbh.adjustPreviousRightBearing(); } line += lbh.tmpData; goto found; @@ -1915,9 +1918,7 @@ void QTextLine::layout_helper(int maxGlyphs) } else { lbh.whiteSpaceOrObject = false; bool sb_or_ws = false; - glyph_t previousGlyph = 0; - if (lbh.currentPosition > 0 && lbh.logClusters[lbh.currentPosition - 1] <lbh.glyphs.numGlyphs) - previousGlyph = lbh.currentGlyph(); // needed to calculate right bearing later + lbh.saveCurrentGlyph(); do { addNextCluster(lbh.currentPosition, end, lbh.tmpData, lbh.glyphCount, current, lbh.logClusters, lbh.glyphs); @@ -1942,7 +1943,7 @@ void QTextLine::layout_helper(int maxGlyphs) // b) if we are so short of available width that the // soft hyphen is the first breakable position, then // we don't want to show it. However we initially - // have to take the width for it into accoun so that + // have to take the width for it into account so that // the text document layout sees the overflow and // switch to break-anywhere mode, in which we // want the soft-hyphen to slip into the next line @@ -1970,8 +1971,9 @@ void QTextLine::layout_helper(int maxGlyphs) // we are too wide, fix right bearing if (rightBearing <= 0) lbh.rightBearing = rightBearing; // take from cache - else if (previousGlyph > 0) - lbh.adjustRightBearing(previousGlyph); + else + lbh.adjustPreviousRightBearing(); + if (!breakany) { line.textWidth += lbh.softHyphenWidth; } @@ -1979,6 +1981,7 @@ void QTextLine::layout_helper(int maxGlyphs) goto found; } } + lbh.saveCurrentGlyph(); } if (lbh.currentPosition == end) newItem = item + 1; diff --git a/src/gui/text/qtextobject.cpp b/src/gui/text/qtextobject.cpp index e323fd0..a403cc5 100644 --- a/src/gui/text/qtextobject.cpp +++ b/src/gui/text/qtextobject.cpp @@ -891,6 +891,11 @@ QTextBlockUserData::~QTextBlockUserData() Returns true if this text block is valid; otherwise returns false. */ +bool QTextBlock::isValid() const +{ + return p != 0 && p->blockMap().isValid(n); +} + /*! \fn QTextBlock &QTextBlock::operator=(const QTextBlock &other) @@ -1504,7 +1509,7 @@ QTextBlock QTextBlock::next() const */ QTextBlock QTextBlock::previous() const { - if (!isValid()) + if (!p) return QTextBlock(); return QTextBlock(p, p->blockMap().previous(n)); diff --git a/src/gui/text/qtextobject.h b/src/gui/text/qtextobject.h index d5c1e8d..73aed79 100644 --- a/src/gui/text/qtextobject.h +++ b/src/gui/text/qtextobject.h @@ -204,7 +204,7 @@ public: inline QTextBlock(const QTextBlock &o) : p(o.p), n(o.n) {} inline QTextBlock &operator=(const QTextBlock &o) { p = o.p; n = o.n; return *this; } - inline bool isValid() const { return p != 0 && n != 0; } + bool isValid() const; inline bool operator==(const QTextBlock &o) const { return p == o.p && n == o.n; } inline bool operator!=(const QTextBlock &o) const { return p != o.p || n != o.n; } diff --git a/src/gui/util/qdesktopservices_s60.cpp b/src/gui/util/qdesktopservices_s60.cpp index 96860df..8caeb74 100644 --- a/src/gui/util/qdesktopservices_s60.cpp +++ b/src/gui/util/qdesktopservices_s60.cpp @@ -314,7 +314,7 @@ static bool handleUrl(const QUrl &url) if (!url.isValid()) return false; - QString urlString(url.toString()); + QString urlString(url.toEncoded()); TPtrC urlPtr(qt_QString2TPtrC(urlString)); TRAPD( err, handleUrlL(urlPtr)); return err ? false : true; diff --git a/src/gui/widgets/qabstractscrollarea.cpp b/src/gui/widgets/qabstractscrollarea.cpp index 5104116..2503b99 100644 --- a/src/gui/widgets/qabstractscrollarea.cpp +++ b/src/gui/widgets/qabstractscrollarea.cpp @@ -500,7 +500,7 @@ QAbstractScrollArea::QAbstractScrollArea(QAbstractScrollAreaPrivate &dd, QWidget /*! Constructs a viewport. - The \a parent arguments is sent to the QWidget constructor. + The \a parent argument is sent to the QWidget constructor. */ QAbstractScrollArea::QAbstractScrollArea(QWidget *parent) :QFrame(*new QAbstractScrollAreaPrivate, parent) diff --git a/src/gui/widgets/qabstractslider.cpp b/src/gui/widgets/qabstractslider.cpp index cb36398..2570496 100644 --- a/src/gui/widgets/qabstractslider.cpp +++ b/src/gui/widgets/qabstractslider.cpp @@ -265,7 +265,7 @@ void QAbstractSliderPrivate::setSteps(int single, int page) /*! Constructs an abstract slider. - The \a parent arguments is sent to the QWidget constructor. + The \a parent argument is sent to the QWidget constructor. The \l minimum defaults to 0, the \l maximum to 99, with a \l singleStep size of 1 and a \l pageStep size of 10, and an initial diff --git a/src/gui/widgets/qcombobox.cpp b/src/gui/widgets/qcombobox.cpp index dbbf49a..04ab801 100644 --- a/src/gui/widgets/qcombobox.cpp +++ b/src/gui/widgets/qcombobox.cpp @@ -398,7 +398,7 @@ void QComboBoxPrivateContainer::leaveEvent(QEvent *) #ifdef Q_WS_MAC QStyleOptionComboBox opt = comboStyleOption(); if (combo->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, combo)) - view->setCurrentIndex(QModelIndex()); + view->clearSelection(); #endif } @@ -671,8 +671,8 @@ bool QComboBoxPrivateContainer::eventFilter(QObject *o, QEvent *e) if (vector.manhattanLength() > 9 && blockMouseReleaseTimer.isActive()) blockMouseReleaseTimer.stop(); QModelIndex indexUnderMouse = view->indexAt(m->pos()); - if (indexUnderMouse.isValid() && indexUnderMouse != view->currentIndex() - && !QComboBoxDelegate::isSeparator(indexUnderMouse)) { + if (indexUnderMouse.isValid() + && !QComboBoxDelegate::isSeparator(indexUnderMouse)) { view->setCurrentIndex(indexUnderMouse); } } @@ -704,11 +704,13 @@ void QComboBoxPrivateContainer::hideEvent(QHideEvent *) { emit resetButton(); combo->update(); +#ifndef QT_NO_GRAPHICSVIEW // QGraphicsScenePrivate::removePopup closes the combo box popup, it hides it non-explicitly. // Hiding/showing the QComboBox after this will unexpectedly show the popup as well. // Re-hiding the popup container makes sure it is explicitly hidden. if (QGraphicsProxyWidget *proxy = graphicsProxyWidget()) proxy->hide(); +#endif } void QComboBoxPrivateContainer::mousePressEvent(QMouseEvent *e) @@ -944,7 +946,10 @@ QComboBox::QComboBox(bool rw, QWidget *parent, const char *name) to set and get item data (e.g., setItemData() and itemText()). You can also set a new model and view (with setModel() and setView()). For the text and icon in the combobox label, the data in the model - that has the Qt::DisplayRole and Qt::DecorationRole is used. + that has the Qt::DisplayRole and Qt::DecorationRole is used. Note + that you cannot alter the \l{QAbstractItemView::}{SelectionMode} + of the view(), e.g., by using + \l{QAbstractItemView::}{setSelectionMode()}. \image qstyle-comboboxes.png Comboboxes in the different built-in styles. @@ -2453,12 +2458,7 @@ void QComboBox::showPopup() // available screen geometry.This may override the vertical position, but it is more // important to show as much as possible of the popup. const int height = !boundToScreen ? listRect.height() : qMin(listRect.height(), screen.height()); -#ifdef Q_WS_S60 - //popup needs to be stretched with screen minimum dimension - listRect.setHeight(qMin(screen.height(), screen.width())); -#else listRect.setHeight(height); -#endif if (boundToScreen) { if (listRect.top() < screen.top()) diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index bffc2b5..5a281ad 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -414,10 +414,14 @@ void QLineControl::processInputMethodEvent(QInputMethodEvent *event) if (isGettingInput) { // If any text is being input, remove selected text. priorState = m_undoState; + if (echoMode() == QLineEdit::PasswordEchoOnEdit && !passwordEchoEditing()) { + updatePasswordEchoEditing(true); + m_selstart = 0; + m_selend = m_text.length(); + } removeSelectedText(); } - int c = m_cursor; // cursor position after insertion of commit string if (event->replacementStart() <= 0) c += event->commitString().length() - qMin(-event->replacementStart(), event->replacementLength()); diff --git a/src/gui/widgets/qmenu.cpp b/src/gui/widgets/qmenu.cpp index 9a6d24c..2f4bb4b 100644 --- a/src/gui/widgets/qmenu.cpp +++ b/src/gui/widgets/qmenu.cpp @@ -1247,37 +1247,15 @@ void QMenu::initStyleOption(QStyleOptionMenuItem *option, const QAction *action) response to button presses; these are just like context menus except for how they are invoked. - \raw HTML - <table align="center" cellpadding="0"> - <tr> - <td> - \endraw - \inlineimage plastique-menu.png - \raw HTML - </td> - <td> - \endraw - \inlineimage windowsxp-menu.png - \raw HTML - </td> - <td> - \endraw - \inlineimage macintosh-menu.png - \raw HTML - </td> - - </tr> - <tr> - <td colspan="3"> - \endraw - A menu shown in \l{Plastique Style Widget Gallery}{Plastique widget style}, + \table 100% + \row + \o \inlineimage plastique-menu.png + \o \inlineimage windowsxp-menu.png + \o \inlineimage macintosh-menu.png + \endtable + \caption Fig. A menu shown in \l{Plastique Style Widget Gallery}{Plastique widget style}, \l{Windows XP Style Widget Gallery}{Windows XP widget style}, and \l{Macintosh Style Widget Gallery}{Macintosh widget style}. - \raw HTML - </td> - </tr> - </table> - \endraw \section1 Actions diff --git a/src/gui/widgets/qscrollbar.cpp b/src/gui/widgets/qscrollbar.cpp index c895b1b..87738a0 100644 --- a/src/gui/widgets/qscrollbar.cpp +++ b/src/gui/widgets/qscrollbar.cpp @@ -330,7 +330,7 @@ void QScrollBar::initStyleOption(QStyleOptionSlider *option) const /*! Constructs a vertical scroll bar. - The \a parent arguments is sent to the QWidget constructor. + The \a parent argument is sent to the QWidget constructor. The \l {QAbstractSlider::minimum} {minimum} defaults to 0, the \l {QAbstractSlider::maximum} {maximum} to 99, with a diff --git a/src/gui/widgets/qsplitter.cpp b/src/gui/widgets/qsplitter.cpp index 964a6e1..ca8fc37 100644 --- a/src/gui/widgets/qsplitter.cpp +++ b/src/gui/widgets/qsplitter.cpp @@ -1016,7 +1016,7 @@ QSplitterLayoutStruct *QSplitterPrivate::insertWidget(int index, QWidget *w) /*! Constructs a horizontal splitter with the \a parent - arguments is passed on to the QFrame constructor. + argument passed on to the QFrame constructor. \sa setOrientation() */ diff --git a/src/imports/gestures/qdeclarativegesturearea.cpp b/src/imports/gestures/qdeclarativegesturearea.cpp index c2a2e98..aae6a01 100644 --- a/src/imports/gestures/qdeclarativegesturearea.cpp +++ b/src/imports/gestures/qdeclarativegesturearea.cpp @@ -136,7 +136,7 @@ public: GestureArea is an invisible item: it is never painted. - \sa MouseArea, {declarative/touchinteraction/gestures}{Gestures example} + \sa MouseArea */ /*! diff --git a/src/multimedia/audio/qaudioinput.cpp b/src/multimedia/audio/qaudioinput.cpp index 3767b95..77ecf70 100644 --- a/src/multimedia/audio/qaudioinput.cpp +++ b/src/multimedia/audio/qaudioinput.cpp @@ -202,7 +202,13 @@ QAudioInput::~QAudioInput() /*! Uses the \a device as the QIODevice to transfer data. Passing a QIODevice allows the data to be transferred without any extra code. - All that is required is to open the QIODevice. + All that is required is to open the QIODevice. QAudioInput does not take + ownership of \a device. + + The QAudioInput will write to the device when new data is available. You can + subclass QIODevice and reimplement \l{QIODevice::}{writeData()} if you wish to + access the data. If you simply want to save data to a file, you can pass a + QFile to this function. If able to successfully get audio data from the systems audio device the state() is set to either QAudio::ActiveState or QAudio::IdleState, @@ -222,9 +228,12 @@ void QAudioInput::start(QIODevice* device) } /*! - Returns a pointer to the QIODevice being used to handle the data - transfer. This QIODevice can be used to read() audio data - directly. + + Returns a pointer to a new QIODevice that will be used to handle the data transfer. + This QIODevice can be used to \l{QIODevice::}{read()} audio data directly. + You will typically connect to the \l{QIODevice::}{readyRead()} signal, and + read from the device in the slot you connect to. QAudioInput keeps ownership + of the device. If able to access the systems audio device the state() is set to QAudio::IdleState, error() is set to QAudio::NoError diff --git a/src/network/access/qftp.cpp b/src/network/access/qftp.cpp index ccc20e6..69e59d1 100644 --- a/src/network/access/qftp.cpp +++ b/src/network/access/qftp.cpp @@ -363,9 +363,9 @@ qint64 QFtpDTP::read(char *data, qint64 maxlen) if (socket && socket->state() == QTcpSocket::ConnectedState) { read = socket->read(data, maxlen); } else { - read = bytesFromSocket.size(); + read = qMin(maxlen, qint64(bytesFromSocket.size())); memcpy(data, bytesFromSocket.data(), read); - bytesFromSocket.clear(); + bytesFromSocket.remove(0, read); } bytesDone += read; diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 82b5ce3..700b455 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -963,8 +963,20 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket } else { errorCode = QNetworkReply::RemoteHostClosedError; } + } else if (state == QHttpNetworkConnectionChannel::ReadingState) { + if (!reply->d_func()->expectContent()) { + // No content expected, this is a valid way to have the connection closed by the server + return; + } + if (reply->contentLength() == -1 && !reply->d_func()->isChunked()) { + // There was no content-length header and it's not chunked encoding, + // so this is a valid way to have the connection closed by the server + return; + } + // ok, we got a disconnect even though we did not expect it + errorCode = QNetworkReply::RemoteHostClosedError; } else { - return; + errorCode = QNetworkReply::RemoteHostClosedError; } break; case QAbstractSocket::SocketTimeoutError: @@ -992,6 +1004,7 @@ void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socket if (reply) { reply->d_func()->errorString = errorString; emit reply->finishedWithError(errorCode, errorString); + reply = 0; } // send the next request QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection); diff --git a/src/network/access/qnetworkaccesshttpbackend.cpp b/src/network/access/qnetworkaccesshttpbackend.cpp index 4189743..7c90f68 100644 --- a/src/network/access/qnetworkaccesshttpbackend.cpp +++ b/src/network/access/qnetworkaccesshttpbackend.cpp @@ -360,6 +360,11 @@ void QNetworkAccessHttpBackend::validateCache(QHttpNetworkRequest &httpRequest, return; } + // The disk cache API does not currently support partial content retrieval. + // That is why we don't use the disk cache for any such requests. + if (request().hasRawHeader("Range")) + return; + QAbstractNetworkCache *nc = networkCache(); if (!nc) return; // no local cache @@ -996,14 +1001,11 @@ QNetworkCacheMetaData QNetworkAccessHttpBackend::fetchCacheMetaData(const QNetwo if (hop_by_hop) continue; - // for 4.6.0, we were planning to not store the date header in the - // cached resource; through that we planned to reduce the number - // of writes to disk when using a QNetworkDiskCache (i.e. don't - // write to disk when only the date changes). - // However, without the date we cannot calculate the age of the page - // anymore. - //if (header == "date") - //continue; + // we are currently not using the date header to determine the expiration time of a page, + // but only the "Expires", "max-age" and "s-maxage" headers, see + // QNetworkAccessHttpBackend::validateCache() and below ("metaData.setExpirationDate()"). + if (header == "date") + continue; // Don't store Warning 1xx headers if (header == "warning") { diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index 343f344..894df79 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -505,6 +505,13 @@ void QNetworkReplyImplPrivate::initCacheSaveDevice() { Q_Q(QNetworkReplyImpl); + // The disk cache does not support partial content, so don't even try to + // save any such content into the cache. + if (q->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 206) { + cacheEnabled = false; + return; + } + // save the meta data QNetworkCacheMetaData metaData; metaData.setUrl(url); diff --git a/src/network/bearer/qnetworkconfigmanager.cpp b/src/network/bearer/qnetworkconfigmanager.cpp index dc4e4f7..8634b6b 100644 --- a/src/network/bearer/qnetworkconfigmanager.cpp +++ b/src/network/bearer/qnetworkconfigmanager.cpp @@ -196,6 +196,9 @@ QNetworkConfigurationManagerPrivate *qNetworkConfigurationManagerPrivate() /*! Constructs a QNetworkConfigurationManager with the given \a parent. + + Note that to ensure a valid list of current configurations immediately available, updating + is done during construction which causes some delay. */ QNetworkConfigurationManager::QNetworkConfigurationManager( QObject* parent ) : QObject(parent) diff --git a/src/network/bearer/qsharednetworksession.cpp b/src/network/bearer/qsharednetworksession.cpp index 28ca173..fcb0128 100644 --- a/src/network/bearer/qsharednetworksession.cpp +++ b/src/network/bearer/qsharednetworksession.cpp @@ -59,6 +59,11 @@ inline QSharedNetworkSessionManager* sharedNetworkSessionManager() return rv; } +static void doDeleteLater(QObject* obj) +{ + obj->deleteLater(); +} + QSharedPointer<QNetworkSession> QSharedNetworkSessionManager::getSession(QNetworkConfiguration config) { QSharedNetworkSessionManager *m(sharedNetworkSessionManager()); @@ -69,7 +74,7 @@ QSharedPointer<QNetworkSession> QSharedNetworkSessionManager::getSession(QNetwor return p; } //otherwise make one - QSharedPointer<QNetworkSession> session(new QNetworkSession(config)); + QSharedPointer<QNetworkSession> session(new QNetworkSession(config), doDeleteLater); m->sessions[config] = session; return session; } diff --git a/src/network/kernel/qnetworkinterface_symbian.cpp b/src/network/kernel/qnetworkinterface_symbian.cpp index 03133d0..8e5db3c 100644 --- a/src/network/kernel/qnetworkinterface_symbian.cpp +++ b/src/network/kernel/qnetworkinterface_symbian.cpp @@ -43,7 +43,7 @@ #include "qnetworkinterface.h" #include "qnetworkinterface_p.h" -#include "../corelib/kernel/qcore_symbian_p.h" +#include <private/qcore_symbian_p.h> #ifndef QT_NO_NETWORKINTERFACE diff --git a/src/network/ssl/qsslcertificate.cpp b/src/network/ssl/qsslcertificate.cpp index 618ac79..a5cdf01 100644 --- a/src/network/ssl/qsslcertificate.cpp +++ b/src/network/ssl/qsslcertificate.cpp @@ -219,17 +219,19 @@ bool QSslCertificate::isNull() const Returns true if this certificate is valid; otherwise returns false. - Note: Currently, this function only checks that the current + Note: Currently, this function checks that the current data-time is within the date-time range during which the - certificate is considered valid. No other checks are - currently performed. + certificate is considered valid, and checks that the + certificate is not in a blacklist of fraudulent certificates. \sa isNull() */ bool QSslCertificate::isValid() const { const QDateTime currentTime = QDateTime::currentDateTime(); - return currentTime >= d->notValidBefore && currentTime <= d->notValidAfter; + return currentTime >= d->notValidBefore && + currentTime <= d->notValidAfter && + ! QSslCertificatePrivate::isBlacklisted(*this); } /*! @@ -798,6 +800,30 @@ QList<QSslCertificate> QSslCertificatePrivate::certificatesFromDer(const QByteAr return certificates; } +// These certificates are known to be fraudulent and were created during the comodo +// compromise. See http://www.comodo.com/Comodo-Fraud-Incident-2011-03-23.html +static const char *certificate_blacklist[] = { + "04:7e:cb:e9:fc:a5:5f:7b:d0:9e:ae:36:e1:0c:ae:1e", + "f5:c8:6a:f3:61:62:f1:3a:64:f5:4f:6d:c9:58:7c:06", + "d7:55:8f:da:f5:f1:10:5b:b2:13:28:2b:70:77:29:a3", + "39:2a:43:4f:0e:07:df:1f:8a:a3:05:de:34:e0:c2:29", + "3e:75:ce:d4:6b:69:30:21:21:88:30:ae:86:a8:2a:71", + "e9:02:8b:95:78:e4:15:dc:1a:71:0a:2b:88:15:44:47", + "92:39:d5:34:8f:40:d1:69:5a:74:54:70:e1:f2:3f:43", + "b0:b7:13:3e:d0:96:f9:b5:6f:ae:91:c8:74:bd:3a:c0", + "d8:f3:5f:4e:b7:87:2b:2d:ab:06:92:e3:15:38:2f:b0", + 0 +}; + +bool QSslCertificatePrivate::isBlacklisted(const QSslCertificate &certificate) +{ + for (int a = 0; certificate_blacklist[a] != 0; a++) { + if (certificate.serialNumber() == certificate_blacklist[a]) + return true; + } + return false; +} + #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug debug, const QSslCertificate &certificate) { diff --git a/src/network/ssl/qsslcertificate_p.h b/src/network/ssl/qsslcertificate_p.h index cdceb0f..1ce33d3 100644 --- a/src/network/ssl/qsslcertificate_p.h +++ b/src/network/ssl/qsslcertificate_p.h @@ -96,6 +96,7 @@ public: static QSslCertificate QSslCertificate_from_X509(X509 *x509); static QList<QSslCertificate> certificatesFromPem(const QByteArray &pem, int count = -1); static QList<QSslCertificate> certificatesFromDer(const QByteArray &der, int count = -1); + static bool isBlacklisted(const QSslCertificate &certificate); friend class QSslSocketBackendPrivate; diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index 84e14ff..2427193 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -312,9 +312,18 @@ init_context: q_X509_STORE_add_cert(ctx->cert_store, (X509 *)caCertificate.handle()); } } + + bool addExpiredCerts = true; +#if defined(Q_OS_MAC) && (MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_5) + //On Leopard SSL does not work if we add the expired certificates. + if (QSysInfo::MacintoshVersion == QSysInfo::MV_10_5) + addExpiredCerts = false; +#endif // now add the expired certs - foreach (const QSslCertificate &caCertificate, expiredCerts) { - q_X509_STORE_add_cert(ctx->cert_store, (X509 *)caCertificate.handle()); + if (addExpiredCerts) { + foreach (const QSslCertificate &caCertificate, expiredCerts) { + q_X509_STORE_add_cert(ctx->cert_store, (X509 *)caCertificate.handle()); + } } // Register a custom callback to get all verification errors. @@ -1184,6 +1193,13 @@ bool QSslSocketBackendPrivate::startHandshake() X509 *x509 = q_SSL_get_peer_certificate(ssl); configuration.peerCertificate = QSslCertificatePrivate::QSslCertificate_from_X509(x509); q_X509_free(x509); + if (QSslCertificatePrivate::isBlacklisted(configuration.peerCertificate)) { + q->setErrorString(QSslSocket::tr("The peer certificate is blacklisted")); + q->setSocketError(QAbstractSocket::SslHandshakeFailedError); + emit q->error(QAbstractSocket::SslHandshakeFailedError); + plainSocket->disconnectFromHost(); + return false; + } // Start translating errors. QList<QSslError> errors; diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index cda31e5..5c8d2b6 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -90,10 +90,6 @@ QT_BEGIN_NAMESPACE -#if defined(Q_OS_SYMBIAN) -#define QT_GL_NO_SCISSOR_TEST -#endif - #if defined(Q_WS_WIN) extern Q_GUI_EXPORT bool qt_cleartype_enabled; #endif @@ -1335,11 +1331,14 @@ void QGL2PaintEngineEx::drawPixmap(const QRectF& dest, const QPixmap & pixmap, c ensureActive(); d->transferMode(ImageDrawingMode); + QGLContext::BindOptions bindOptions = QGLContext::InternalBindOption|QGLContext::CanFlipNativePixmapBindOption; +#ifdef QGL_USE_TEXTURE_POOL + bindOptions |= QGLContext::TemporarilyCachedBindOption; +#endif + glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); QGLTexture *texture = - ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, - QGLContext::InternalBindOption - | QGLContext::CanFlipNativePixmapBindOption); + ctx->d_func()->bindTexture(pixmap, GL_TEXTURE_2D, GL_RGBA, bindOptions); GLfloat top = texture->options & QGLContext::InvertedYBindOption ? (pixmap.height() - src.top()) : src.top(); GLfloat bottom = texture->options & QGLContext::InvertedYBindOption ? (pixmap.height() - src.bottom()) : src.bottom(); @@ -1351,6 +1350,12 @@ void QGL2PaintEngineEx::drawPixmap(const QRectF& dest, const QPixmap & pixmap, c d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, state()->renderHints & QPainter::SmoothPixmapTransform, texture->id); d->drawTexture(dest, srcRect, pixmap.size(), isOpaque, isBitmap); + + if (texture->options&QGLContext::TemporarilyCachedBindOption) { + // pixmap was temporarily cached as a QImage texture by pooling system + // and should be destroyed immediately + QGLTextureCache::instance()->remove(ctx, texture->id); + } } void QGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const QRectF& src, @@ -1375,12 +1380,23 @@ void QGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); - QGLTexture *texture = ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption); + QGLContext::BindOptions bindOptions = QGLContext::InternalBindOption; +#ifdef QGL_USE_TEXTURE_POOL + bindOptions |= QGLContext::TemporarilyCachedBindOption; +#endif + + QGLTexture *texture = ctx->d_func()->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, bindOptions); GLuint id = texture->id; d->updateTextureFilter(GL_TEXTURE_2D, GL_CLAMP_TO_EDGE, state()->renderHints & QPainter::SmoothPixmapTransform, id); d->drawTexture(dest, src, image.size(), !image.hasAlphaChannel()); + + if (texture->options&QGLContext::TemporarilyCachedBindOption) { + // image was temporarily cached by texture pooling system + // and should be destroyed immediately + QGLTextureCache::instance()->remove(ctx, texture->id); + } } void QGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem) diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro index 0e82467..6d79584 100644 --- a/src/opengl/opengl.pro +++ b/src/opengl/opengl.pro @@ -148,11 +148,16 @@ embedded { } symbian { + DEFINES += QGL_USE_TEXTURE_POOL QGL_NO_PRESERVED_SWAP + SOURCES -= qpixmapdata_gl.cpp SOURCES += qgl_symbian.cpp \ + qpixmapdata_poolgl.cpp \ qglpixelbuffer_egl.cpp \ - qgl_egl.cpp + qgl_egl.cpp \ + qgltexturepool.cpp - HEADERS += qgl_egl_p.h + HEADERS += qgl_egl_p.h \ + qgltexturepool_p.h symbian:TARGET.UID3 = 0x2002131A } diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 062218c..b755153 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -69,6 +69,7 @@ #if !defined(QT_OPENGL_ES_1) #include "gl2paintengineex/qpaintengineex_opengl2_p.h" +#include <private/qwindowsurface_gl_p.h> #endif #ifndef QT_OPENGL_ES_2 @@ -86,13 +87,16 @@ #include <private/qpixmapdata_p.h> #include <private/qpixmapdata_gl_p.h> #include <private/qglpixelbuffer_p.h> -#include <private/qwindowsurface_gl_p.h> #include <private/qimagepixmapcleanuphooks_p.h> #include "qcolormap.h" #include "qfile.h" #include "qlibrary.h" #include <qmutex.h> +#ifdef QGL_USE_TEXTURE_POOL +#include <private/qgltexturepool_p.h> +#endif + QT_BEGIN_NAMESPACE @@ -2022,6 +2026,10 @@ struct DDSFormat { the pixmap/image that it stems from, e.g. installing destruction hooks in them. + \omitvalue TemporarilyCachedBindOption Used by paint engines on some + platforms to indicate that the pixmap or image texture is possibly + cached only temporarily and must be destroyed immediately after the use. + \omitvalue InternalBindOption */ @@ -2529,8 +2537,18 @@ QGLTexture* QGLContextPrivate::bindTexture(const QImage &image, GLenum target, G #endif const QImage &constRef = img; // to avoid detach in bits()... +#ifdef QGL_USE_TEXTURE_POOL + QGLTexturePool::instance()->createPermanentTexture(tx_id, + target, + 0, internalFormat, + img.width(), img.height(), + externalFormat, + pixel_type, + constRef.bits()); +#else glTexImage2D(target, 0, internalFormat, img.width(), img.height(), 0, externalFormat, pixel_type, constRef.bits()); +#endif #if defined(QT_OPENGL_ES_2) if (genMipmap) glGenerateMipmap(target); @@ -2569,7 +2587,6 @@ QGLTexture *QGLContextPrivate::textureCacheLookup(const qint64 key, GLenum targe return 0; } - /*! \internal */ QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target, GLint format, QGLContext::BindOptions options) { diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h index 9443c74..7d72c8a 100644 --- a/src/opengl/qgl.h +++ b/src/opengl/qgl.h @@ -329,6 +329,7 @@ public: MemoryManagedBindOption = 0x0010, // internal flag CanFlipNativePixmapBindOption = 0x0020, // internal flag + TemporarilyCachedBindOption = 0x0040, // internal flag DefaultBindOption = LinearFilteringBindOption | InvertedYBindOption diff --git a/src/opengl/qgl_egl.cpp b/src/opengl/qgl_egl.cpp index 674d80d..d6b2d3b 100644 --- a/src/opengl/qgl_egl.cpp +++ b/src/opengl/qgl_egl.cpp @@ -39,6 +39,7 @@ ** ****************************************************************************/ +#include <QtCore/qdebug.h> #include <QtOpenGL/qgl.h> #include <QtOpenGL/qglpixelbuffer.h> #include "qgl_p.h" @@ -195,6 +196,7 @@ void QGLContext::makeCurrent() // PowerVR MBX/SGX chips needs to clear all buffers when starting to render // a new frame, otherwise there will be a performance penalty to pay for // each frame. + qDebug() << "Found SGX/MBX driver, enabling FullClearOnEveryFrame"; d->workaround_needsFullClearOnEveryFrame = true; // Older PowerVR SGX drivers (like the one in the N900) have a @@ -202,10 +204,31 @@ void QGLContext::makeCurrent() // or GL_ALPHA texture bound to an FBO. The only way to // identify that driver is to check the EGL version number for it. const char *egl_version = eglQueryString(d->eglContext->display(), EGL_VERSION); - if (egl_version && strstr(egl_version, "1.3")) + + if (egl_version && strstr(egl_version, "1.3")) { + qDebug() << "Found v1.3 driver, enabling brokenFBOReadBack"; d->workaround_brokenFBOReadBack = true; - else if (egl_version && strstr(egl_version, "1.4")) + } else if (egl_version && strstr(egl_version, "1.4")) { + qDebug() << "Found v1.4 driver, enabling brokenTexSubImage"; d->workaround_brokenTexSubImage = true; + + // this is a bit complicated; 1.4 version SGX drivers from + // Nokia have fixed the brokenFBOReadBack problem, but + // official drivers from TI haven't, meaning that things + // like the beagleboard are broken unless we hack around it + // - but at the same time, we want to not reduce performance + // by not enabling this elsewhere. + // + // so, let's check for a Nokia-specific addon, and only + // enable if it isn't present. + // (see MeeGo bug #5616) + if (!QEgl::hasExtension("EGL_NOK_image_shared")) { + // no Nokia extension, this is probably a standard SGX + // driver, so enable the workaround + qDebug() << "Found non-Nokia v1.4 driver, enabling brokenFBOReadBack"; + d->workaround_brokenFBOReadBack = true; + } + } } } } diff --git a/src/opengl/qgl_symbian.cpp b/src/opengl/qgl_symbian.cpp index a9e2248..1b41db4 100644 --- a/src/opengl/qgl_symbian.cpp +++ b/src/opengl/qgl_symbian.cpp @@ -41,17 +41,17 @@ #include "qgl.h" -#include <coemain.h> -#include <coecntrl.h> -#include <w32std.h> +#include <fbs.h> #include <private/qt_s60_p.h> #include <private/qpixmap_s60_p.h> #include <private/qimagepixmapcleanuphooks_p.h> #include <private/qgl_p.h> #include <private/qpaintengine_opengl_p.h> #include <private/qwidget_p.h> // to access QWExtra +#include <private/qnativeimagehandleprovider_p.h> #include "qgl_egl_p.h" #include "qpixmapdata_gl_p.h" +#include "qgltexturepool_p.h" #include "qcolormap.h" #include <QDebug> @@ -71,6 +71,8 @@ QT_BEGIN_NAMESPACE #endif #endif +extern int qt_gl_pixmap_serial; + /* QGLTemporaryContext implementation */ @@ -227,13 +229,20 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) // almost same as d->eglSurface = QEgl::createSurface(device(), d->eglContext->config()); -#if !defined(QGL_NO_PRESERVED_SWAP) - eglGetError(); // Clear error state first. - eglSurfaceAttrib(QEgl::display(), d->eglSurface, - EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); - if (eglGetError() != EGL_SUCCESS) { - qWarning("QGLContext: could not enable preserved swap"); - } + eglGetError(); // Clear error state first. + +#ifdef QGL_NO_PRESERVED_SWAP + eglSurfaceAttrib(QEgl::display(), d->eglSurface, + EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED); + + if (eglGetError() != EGL_SUCCESS) + qWarning("QGLContext: could not enable destroyed swap behaviour"); +#else + eglSurfaceAttrib(QEgl::display(), d->eglSurface, + EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); + + if (eglGetError() != EGL_SUCCESS) + qWarning("QGLContext: could not enable preserved swap behaviour"); #endif setWindowCreated(true); @@ -360,117 +369,104 @@ void QGLWidgetPrivate::recreateEglSurface() eglSurfaceWindowId = currentId; } -/* - * Symbian specific QGLPixmapData functions - */ - -static CFbsBitmap* createBlitCopy(CFbsBitmap* bitmap) +static inline bool knownGoodFormat(QImage::Format format) { - CFbsBitmap *copy = q_check_ptr(new CFbsBitmap); - if (!copy) - return 0; - - if (copy->Create(bitmap->SizeInPixels(), bitmap->DisplayMode()) != KErrNone) { - delete copy; - copy = 0; - - return 0; + switch (format) { + case QImage::Format_RGB16: // EColor64K + case QImage::Format_RGB32: // EColor16MU + case QImage::Format_ARGB32_Premultiplied: // EColor16MAP + return true; + default: + return false; } - - CFbsBitmapDevice* bitmapDevice = 0; - CFbsBitGc *bitmapGc = 0; - QT_TRAP_THROWING(bitmapDevice = CFbsBitmapDevice::NewL(copy)); - QT_TRAP_THROWING(bitmapGc = CFbsBitGc::NewL()); - bitmapGc->Activate(bitmapDevice); - - bitmapGc->BitBlt(TPoint(), bitmap); - - delete bitmapGc; - delete bitmapDevice; - - return copy; } void QGLPixmapData::fromNativeType(void* pixmap, NativeType type) { if (type == QPixmapData::FbsBitmap) { - CFbsBitmap *bitmap = reinterpret_cast<CFbsBitmap*>(pixmap); - - bool deleteSourceBitmap = false; -#ifdef Q_SYMBIAN_HAS_EXTENDED_BITMAP_TYPE - - // Rasterize extended bitmaps - - TUid extendedBitmapType = bitmap->ExtendedBitmapType(); - if (extendedBitmapType != KNullUid) { - bitmap = createBlitCopy(bitmap); - deleteSourceBitmap = true; - } -#endif - - if (bitmap->IsCompressedInRAM()) { - bitmap = createBlitCopy(bitmap); - deleteSourceBitmap = true; + CFbsBitmap *bitmap = reinterpret_cast<CFbsBitmap *>(pixmap); + QSize size(bitmap->SizeInPixels().iWidth, bitmap->SizeInPixels().iHeight); + if (size.width() == w && size.height() == h) + setSerialNumber(++qt_gl_pixmap_serial); + resize(size.width(), size.height()); + m_source = QVolatileImage(bitmap); + if (pixelType() == BitmapType) { + m_source.ensureFormat(QImage::Format_MonoLSB); + } else if (!knownGoodFormat(m_source.format())) { + m_source.beginDataAccess(); + QImage::Format format = idealFormat(m_source.imageRef(), Qt::AutoColor); + m_source.endDataAccess(true); + m_source.ensureFormat(format); } - - TDisplayMode displayMode = bitmap->DisplayMode(); - QImage::Format format = qt_TDisplayMode2Format(displayMode); - - TSize size = bitmap->SizeInPixels(); - int bytesPerLine = bitmap->ScanLineLength(size.iWidth, displayMode); - - bitmap->BeginDataAccess(); - uchar *bytes = (uchar*)bitmap->DataAddress(); - QImage img = QImage(bytes, size.iWidth, size.iHeight, bytesPerLine, format); - img = img.copy(); - bitmap->EndDataAccess(); - - if (displayMode == EGray2) { - //Symbian thinks set pixels are white/transparent, Qt thinks they are foreground/solid - //So invert mono bitmaps so that masks work correctly. - img.invertPixels(); - } else if (displayMode == EColor16M) { - img = img.rgbSwapped(); // EColor16M is BGR - } - - fromImage(img, Qt::AutoColor); - - if (deleteSourceBitmap) - delete bitmap; + m_hasAlpha = m_source.hasAlphaChannel(); + m_hasFillColor = false; + m_dirty = true; + + } else if (type == QPixmapData::VolatileImage && pixmap) { + // Support QS60Style in more efficient skin graphics retrieval. + QVolatileImage *img = static_cast<QVolatileImage *>(pixmap); + if (img->width() == w && img->height() == h) + setSerialNumber(++qt_gl_pixmap_serial); + resize(img->width(), img->height()); + m_source = *img; + m_hasAlpha = m_source.hasAlphaChannel(); + m_hasFillColor = false; + m_dirty = true; + } else if (type == QPixmapData::NativeImageHandleProvider && pixmap) { + destroyTexture(); + nativeImageHandleProvider = static_cast<QNativeImageHandleProvider *>(pixmap); + // Cannot defer the retrieval, we need at least the size right away. + createFromNativeImageHandleProvider(); } } void* QGLPixmapData::toNativeType(NativeType type) { if (type == QPixmapData::FbsBitmap) { - CFbsBitmap *bitmap = q_check_ptr(new CFbsBitmap); - - if (bitmap) { - QImage image = toImage(); - - TDisplayMode displayMode(EColor16MU); - if (image.format()==QImage::Format_ARGB32_Premultiplied) - displayMode = EColor16MAP; + if (m_source.isNull()) + m_source = QVolatileImage(w, h, QImage::Format_ARGB32_Premultiplied); + return m_source.duplicateNativeImage(); + } - if (bitmap->Create(TSize(image.width(), image.height()), - displayMode) == KErrNone) { - const uchar *sptr = const_cast<const QImage&>(image).bits(); - bitmap->BeginDataAccess(); + return 0; +} - uchar *dptr = (uchar*)bitmap->DataAddress(); - Mem::Copy(dptr, sptr, image.byteCount()); +bool QGLPixmapData::initFromNativeImageHandle(void *handle, const QString &type) +{ + if (type == QLatin1String("RSgImage")) { + fromNativeType(handle, QPixmapData::SgImage); + return true; + } else if (type == QLatin1String("CFbsBitmap")) { + fromNativeType(handle, QPixmapData::FbsBitmap); + return true; + } + return false; +} - bitmap->EndDataAccess(); - } else { - delete bitmap; - bitmap = 0; - } +void QGLPixmapData::createFromNativeImageHandleProvider() +{ + void *handle = 0; + QString type; + nativeImageHandleProvider->get(&handle, &type); + if (handle) { + if (initFromNativeImageHandle(handle, type)) { + nativeImageHandle = handle; + nativeImageType = type; + } else { + qWarning("QGLPixmapData: Unknown native image type '%s'", qPrintable(type)); } + } else { + qWarning("QGLPixmapData: Native handle is null"); + } +} - return reinterpret_cast<void*>(bitmap); +void QGLPixmapData::releaseNativeImageHandle() +{ + if (nativeImageHandleProvider && nativeImageHandle) { + nativeImageHandleProvider->release(nativeImageHandle, nativeImageType); + nativeImageHandle = 0; + nativeImageType = QString(); } - return 0; } QT_END_NAMESPACE - diff --git a/src/opengl/qglpaintdevice.cpp b/src/opengl/qglpaintdevice.cpp index ae61ca1..0e879df 100644 --- a/src/opengl/qglpaintdevice.cpp +++ b/src/opengl/qglpaintdevice.cpp @@ -43,13 +43,13 @@ #include <private/qgl_p.h> #include <private/qglpixelbuffer_p.h> #include <private/qglframebufferobject_p.h> -#include <private/qwindowsurface_gl_p.h> #ifdef Q_WS_X11 #include <private/qpixmapdata_x11gl_p.h> #endif #if !defined(QT_OPENGL_ES_1) #include <private/qpixmapdata_gl_p.h> +#include <private/qwindowsurface_gl_p.h> #endif QT_BEGIN_NAMESPACE diff --git a/src/opengl/qgltexturepool.cpp b/src/opengl/qgltexturepool.cpp new file mode 100644 index 0000000..a5472ec --- /dev/null +++ b/src/opengl/qgltexturepool.cpp @@ -0,0 +1,244 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgltexturepool_p.h" +#include "qpixmapdata_gl_p.h" + +QT_BEGIN_NAMESPACE + +Q_OPENGL_EXPORT extern QGLWidget* qt_gl_share_widget(); + +static QGLTexturePool *qt_gl_texture_pool = 0; + +class QGLTexturePoolPrivate +{ +public: + QGLTexturePoolPrivate() : lruFirst(0), lruLast(0) {} + + QGLPixmapData *lruFirst; + QGLPixmapData *lruLast; +}; + +QGLTexturePool::QGLTexturePool() + : d_ptr(new QGLTexturePoolPrivate()) +{ +} + +QGLTexturePool::~QGLTexturePool() +{ +} + +QGLTexturePool *QGLTexturePool::instance() +{ + if (!qt_gl_texture_pool) + qt_gl_texture_pool = new QGLTexturePool(); + return qt_gl_texture_pool; +} + +GLuint QGLTexturePool::createTextureForPixmap(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + QGLPixmapData *data) +{ + GLuint texture; + glGenTextures(1, &texture); + glBindTexture(target, texture); + do { + glTexImage2D(target, level, internalformat, width, height, 0, format, type, 0); + GLenum error = glGetError(); + if (error == GL_NO_ERROR) { + if (data) + moveToHeadOfLRU(data); + return texture; + } else if (error != GL_OUT_OF_MEMORY) { + qWarning("QGLTexturePool: cannot create temporary texture because of invalid params"); + return 0; + } + } while (reclaimSpace(internalformat, width, height, format, type, data)); + qWarning("QGLTexturePool: cannot reclaim sufficient space for a %dx%d pixmap", + width, height); + return 0; +} + +bool QGLTexturePool::createPermanentTexture(GLuint texture, + GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + const GLvoid *data) +{ + glBindTexture(target, texture); + do { + glTexImage2D(target, level, internalformat, width, height, 0, format, type, data); + + GLenum error = glGetError(); + if (error == GL_NO_ERROR) { + return true; + } else if (error != GL_OUT_OF_MEMORY) { + qWarning("QGLTexturePool: cannot create permanent texture because of invalid params"); + return false; + } + } while (reclaimSpace(internalformat, width, height, format, type, 0)); + qWarning("QGLTexturePool: cannot reclaim sufficient space for a %dx%d pixmap", + width, height); + return 0; +} + +void QGLTexturePool::releaseTexture(QGLPixmapData *data, GLuint texture) +{ + // Very simple strategy at the moment: just destroy the texture. + if (data) + removeFromLRU(data); + + QGLWidget *shareWidget = qt_gl_share_widget(); + if (shareWidget) { + QGLShareContextScope ctx(shareWidget->context()); + glDeleteTextures(1, &texture); + } +} + +void QGLTexturePool::useTexture(QGLPixmapData *data) +{ + moveToHeadOfLRU(data); +} + +void QGLTexturePool::detachTexture(QGLPixmapData *data) +{ + removeFromLRU(data); +} + +bool QGLTexturePool::reclaimSpace(GLint internalformat, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + QGLPixmapData *data) +{ + Q_UNUSED(internalformat); // For future use in picking the best texture to eject. + Q_UNUSED(width); + Q_UNUSED(height); + Q_UNUSED(format); + Q_UNUSED(type); + + bool succeeded = false; + bool wasInLRU = false; + if (data) { + wasInLRU = data->inLRU; + moveToHeadOfLRU(data); + } + + QGLPixmapData *lrudata = pixmapLRU(); + if (lrudata && lrudata != data) { + lrudata->reclaimTexture(); + succeeded = true; + } + + if (data && !wasInLRU) + removeFromLRU(data); + + return succeeded; +} + +void QGLTexturePool::hibernate() +{ + Q_D(QGLTexturePool); + QGLPixmapData *pd = d->lruLast; + while (pd) { + QGLPixmapData *prevLRU = pd->prevLRU; + pd->inTexturePool = false; + pd->inLRU = false; + pd->nextLRU = 0; + pd->prevLRU = 0; + pd->hibernate(); + pd = prevLRU; + } + d->lruFirst = 0; + d->lruLast = 0; +} + +void QGLTexturePool::moveToHeadOfLRU(QGLPixmapData *data) +{ + Q_D(QGLTexturePool); + if (data->inLRU) { + if (!data->prevLRU) + return; // Already at the head of the list. + removeFromLRU(data); + } + data->inLRU = true; + data->nextLRU = d->lruFirst; + data->prevLRU = 0; + if (d->lruFirst) + d->lruFirst->prevLRU = data; + else + d->lruLast = data; + d->lruFirst = data; +} + +void QGLTexturePool::removeFromLRU(QGLPixmapData *data) +{ + Q_D(QGLTexturePool); + if (!data->inLRU) + return; + if (data->nextLRU) + data->nextLRU->prevLRU = data->prevLRU; + else + d->lruLast = data->prevLRU; + if (data->prevLRU) + data->prevLRU->nextLRU = data->nextLRU; + else + d->lruFirst = data->nextLRU; + data->inLRU = false; +} + +QGLPixmapData *QGLTexturePool::pixmapLRU() +{ + Q_D(QGLTexturePool); + return d->lruLast; +} + +QT_END_NAMESPACE diff --git a/src/opengl/qgltexturepool_p.h b/src/opengl/qgltexturepool_p.h new file mode 100644 index 0000000..8b6f726 --- /dev/null +++ b/src/opengl/qgltexturepool_p.h @@ -0,0 +1,147 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGLTEXTUREPOOL_P_H +#define QGLTEXTUREPOOL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qgl.h" +#include <QtCore/qscopedpointer.h> + +QT_BEGIN_NAMESPACE + +class QGLPixmapData; +class QGLTexturePoolPrivate; + +class QGLTexturePool +{ +public: + QGLTexturePool(); + virtual ~QGLTexturePool(); + + static QGLTexturePool *instance(); + + // Create a new texture with the specified parameters and associate + // it with "data". The QGLPixmapData will be notified when the + // texture needs to be reclaimed by the pool. + // + // This function will call reclaimSpace() when texture creation fails. + GLuint createTextureForPixmap(GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + QGLPixmapData *data); + + // Create a permanent texture with the specified parameters. + // If there is insufficient space for the texture, + // then this function will call reclaimSpace() and try again. + // + // The caller is responsible for calling glDeleteTextures() + // when it no longer needs the texture, as the texture is not + // recorded in the texture pool. + bool createPermanentTexture(GLuint texture, + GLenum target, + GLint level, + GLint internalformat, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + const GLvoid *data); + + // Release a texture that is no longer required. + void releaseTexture(QGLPixmapData *data, GLuint texture); + + // Notify the pool that a QGLPixmapData object is using + // an texture again. This allows the pool to move the texture + // within a least-recently-used list of QGLPixmapData objects. + void useTexture(QGLPixmapData *data); + + // Notify the pool that the texture associated with a + // QGLPixmapData is being detached from the pool. The caller + // will become responsible for calling glDeleteTextures(). + void detachTexture(QGLPixmapData *data); + + // Reclaim space for an image allocation with the specified parameters. + // Returns true if space was reclaimed, or false if there is no + // further space that can be reclaimed. The "data" parameter + // indicates the pixmap that is trying to obtain space which should + // not itself be reclaimed. + bool reclaimSpace(GLint internalformat, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + QGLPixmapData *data); + + // Hibernate the image pool because the context is about to be + // destroyed. All textures left in the pool should be released. + void hibernate(); + +protected: + // Helper functions for managing the LRU list of QGLPixmapData objects. + void moveToHeadOfLRU(QGLPixmapData *data); + void removeFromLRU(QGLPixmapData *data); + QGLPixmapData *pixmapLRU(); + +private: + QScopedPointer<QGLTexturePoolPrivate> d_ptr; + + Q_DECLARE_PRIVATE(QGLTexturePool) + Q_DISABLE_COPY(QGLTexturePool) +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/opengl/qgraphicssystem_gl.cpp b/src/opengl/qgraphicssystem_gl.cpp index 79911fb..0aa3c2e 100644 --- a/src/opengl/qgraphicssystem_gl.cpp +++ b/src/opengl/qgraphicssystem_gl.cpp @@ -53,6 +53,14 @@ #include "private/qwindowsurface_x11gl_p.h" #endif +#if defined(Q_OS_SYMBIAN) +#include <QtGui/private/qapplication_p.h> +#endif + +#ifdef QGL_USE_TEXTURE_POOL +#include "private/qgltexturepool_p.h" +#endif + QT_BEGIN_NAMESPACE extern QGLWidget *qt_gl_getShareWidget(); @@ -86,8 +94,21 @@ QWindowSurface *QGLGraphicsSystem::createWindowSurface(QWidget *widget) const } #endif +#if defined(Q_OS_SYMBIAN) + if (!QApplicationPrivate::instance()->useTranslucentEGLSurfaces) { + QWidgetPrivate *d = qt_widget_private(widget); + if (!d->isOpaque && widget->testAttribute(Qt::WA_TranslucentBackground)) + return d->createDefaultWindowSurface_sys(); + } +#endif + return new QGLWindowSurface(widget); } - +#ifdef QGL_USE_TEXTURE_POOL +void QGLGraphicsSystem::releaseCachedResources() +{ + QGLTexturePool::instance()->hibernate(); +} +#endif QT_END_NAMESPACE diff --git a/src/opengl/qgraphicssystem_gl_p.h b/src/opengl/qgraphicssystem_gl_p.h index 4630da1..5829dcc 100644 --- a/src/opengl/qgraphicssystem_gl_p.h +++ b/src/opengl/qgraphicssystem_gl_p.h @@ -66,6 +66,10 @@ public: QPixmapData *createPixmapData(QPixmapData::PixelType type) const; QWindowSurface *createWindowSurface(QWidget *widget) const; + +#ifdef QGL_USE_TEXTURE_POOL + void releaseCachedResources(); +#endif private: bool m_useX11GL; }; diff --git a/src/opengl/qpixmapdata_gl_p.h b/src/opengl/qpixmapdata_gl_p.h index a4066fd..8855c20 100644 --- a/src/opengl/qpixmapdata_gl_p.h +++ b/src/opengl/qpixmapdata_gl_p.h @@ -59,6 +59,10 @@ #include "private/qpixmapdata_p.h" #include "private/qglpaintdevice_p.h" +#ifdef Q_OS_SYMBIAN +#include "private/qvolatileimage_p.h" +#endif + QT_BEGIN_NAMESPACE class QPaintEngine; @@ -66,6 +70,16 @@ class QGLFramebufferObject; class QGLFramebufferObjectFormat; class QGLPixmapData; +#ifdef QGL_USE_TEXTURE_POOL +void qt_gl_register_pixmap(QGLPixmapData *pd); +void qt_gl_unregister_pixmap(QGLPixmapData *pd); +void qt_gl_hibernate_pixmaps(); +#endif + +#ifdef Q_OS_SYMBIAN +class QNativeImageHandleProvider; +#endif + class QGLFramebufferObjectPool { public: @@ -129,9 +143,30 @@ public: GLuint bind(bool copyBack = true) const; QGLTexture *texture() const; -#if defined(Q_OS_SYMBIAN) +#ifdef QGL_USE_TEXTURE_POOL + void destroyTexture(); + // Detach this image from the image pool. + void detachTextureFromPool(); + // Release the GL resources associated with this pixmap and copy + // the pixmap's contents out of the GPU back into main memory. + // The GL resource will be automatically recreated the next time + // ensureCreated() is called. Does nothing if the pixmap cannot be + // hibernated for some reason (e.g. texture is shared with another + // process via a SgImage). + void hibernate(); + // Called when the QGLTexturePool wants to reclaim this pixmap's + // texture objects to reuse storage. + void reclaimTexture(); + void forceToImage(); +#endif + +#ifdef Q_OS_SYMBIAN + QImage::Format idealFormat(QImage &image, Qt::ImageConversionFlags flags); void* toNativeType(NativeType type); void fromNativeType(void* pixmap, NativeType type); + bool initFromNativeImageHandle(void *handle, const QString &type); + void createFromNativeImageHandleProvider(); + void releaseNativeImageHandle(); #endif private: @@ -161,7 +196,14 @@ private: mutable QGLFramebufferObject *m_renderFbo; mutable QPaintEngine *m_engine; mutable QGLContext *m_ctx; +#ifdef Q_OS_SYMBIAN + mutable QVolatileImage m_source; + mutable QNativeImageHandleProvider *nativeImageHandleProvider; + void *nativeImageHandle; + QString nativeImageType; +#else mutable QImage m_source; +#endif mutable QGLTexture m_texture; // the texture is not in sync with the source image @@ -176,6 +218,23 @@ private: mutable QGLPixmapGLPaintDevice m_glDevice; +#ifdef QGL_USE_TEXTURE_POOL + QGLPixmapData *nextLRU; + QGLPixmapData *prevLRU; + mutable bool inLRU; + mutable bool failedToAlloc; + mutable bool inTexturePool; + + QGLPixmapData *next; + QGLPixmapData *prev; + + friend class QGLTexturePool; + + friend void qt_gl_register_pixmap(QGLPixmapData *pd); + friend void qt_gl_unregister_pixmap(QGLPixmapData *pd); + friend void qt_gl_hibernate_pixmaps(); +#endif + friend class QGLPixmapGLPaintDevice; friend class QMeeGoPixmapData; friend class QMeeGoLivePixmapData; diff --git a/src/opengl/qpixmapdata_poolgl.cpp b/src/opengl/qpixmapdata_poolgl.cpp new file mode 100644 index 0000000..95152dd --- /dev/null +++ b/src/opengl/qpixmapdata_poolgl.cpp @@ -0,0 +1,936 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qpixmap.h" +#include "qglframebufferobject.h" + +#include <private/qpaintengine_raster_p.h> + +#include "qpixmapdata_gl_p.h" + +#include <private/qgl_p.h> +#include <private/qdrawhelper_p.h> +#include <private/qimage_p.h> +#include <private/qnativeimagehandleprovider_p.h> + +#include <private/qpaintengineex_opengl2_p.h> + +#include <qdesktopwidget.h> +#include <qfile.h> +#include <qimagereader.h> +#include <qbuffer.h> + +#include "qgltexturepool_p.h" + +QT_BEGIN_NAMESPACE + +Q_OPENGL_EXPORT extern QGLWidget* qt_gl_share_widget(); + +static inline int areaDiff(const QSize &size, const QGLFramebufferObject *fbo) +{ + return qAbs(size.width() * size.height() - fbo->width() * fbo->height()); +} + +extern int qt_next_power_of_two(int v); + +static inline QSize maybeRoundToNextPowerOfTwo(const QSize &sz) +{ +#ifdef QT_OPENGL_ES_2 + QSize rounded(qt_next_power_of_two(sz.width()), qt_next_power_of_two(sz.height())); + if (rounded.width() * rounded.height() < 1.20 * sz.width() * sz.height()) + return rounded; +#endif + return sz; +} + + +QGLFramebufferObject *QGLFramebufferObjectPool::acquire(const QSize &requestSize, const QGLFramebufferObjectFormat &requestFormat, bool strictSize) +{ + QGLFramebufferObject *chosen = 0; + QGLFramebufferObject *candidate = 0; + for (int i = 0; !chosen && i < m_fbos.size(); ++i) { + QGLFramebufferObject *fbo = m_fbos.at(i); + + if (strictSize) { + if (fbo->size() == requestSize && fbo->format() == requestFormat) { + chosen = fbo; + break; + } else { + continue; + } + } + + if (fbo->format() == requestFormat) { + // choose the fbo with a matching format and the closest size + if (!candidate || areaDiff(requestSize, candidate) > areaDiff(requestSize, fbo)) + candidate = fbo; + } + + if (candidate) { + m_fbos.removeOne(candidate); + + const QSize fboSize = candidate->size(); + QSize sz = fboSize; + + if (sz.width() < requestSize.width()) + sz.setWidth(qMax(requestSize.width(), qRound(sz.width() * 1.5))); + if (sz.height() < requestSize.height()) + sz.setHeight(qMax(requestSize.height(), qRound(sz.height() * 1.5))); + + // wasting too much space? + if (sz.width() * sz.height() > requestSize.width() * requestSize.height() * 4) + sz = requestSize; + + if (sz != fboSize) { + delete candidate; + candidate = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(sz), requestFormat); + } + + chosen = candidate; + } + } + + if (!chosen) { + if (strictSize) + chosen = new QGLFramebufferObject(requestSize, requestFormat); + else + chosen = new QGLFramebufferObject(maybeRoundToNextPowerOfTwo(requestSize), requestFormat); + } + + if (!chosen->isValid()) { + delete chosen; + chosen = 0; + } + + return chosen; +} + +void QGLFramebufferObjectPool::release(QGLFramebufferObject *fbo) +{ + if (fbo) + m_fbos << fbo; +} + + +QPaintEngine* QGLPixmapGLPaintDevice::paintEngine() const +{ + return data->paintEngine(); +} + +void QGLPixmapGLPaintDevice::beginPaint() +{ + if (!data->isValid()) + return; + + // QGLPaintDevice::beginPaint will store the current binding and replace + // it with m_thisFBO: + m_thisFBO = data->m_renderFbo->handle(); + QGLPaintDevice::beginPaint(); + + Q_ASSERT(data->paintEngine()->type() == QPaintEngine::OpenGL2); + + // QPixmap::fill() is deferred until now, where we actually need to do the fill: + if (data->needsFill()) { + const QColor &c = data->fillColor(); + float alpha = c.alphaF(); + glDisable(GL_SCISSOR_TEST); + glClearColor(c.redF() * alpha, c.greenF() * alpha, c.blueF() * alpha, alpha); + glClear(GL_COLOR_BUFFER_BIT); + } + else if (!data->isUninitialized()) { + // If the pixmap (GL Texture) has valid content (it has been + // uploaded from an image or rendered into before), we need to + // copy it from the texture to the render FBO. + + glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_BLEND); + +#if !defined(QT_OPENGL_ES_2) + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, data->width(), data->height(), 0, -999999, 999999); +#endif + + glViewport(0, 0, data->width(), data->height()); + + // Pass false to bind so it doesn't copy the FBO into the texture! + context()->drawTexture(QRect(0, 0, data->width(), data->height()), data->bind(false)); + } +} + +void QGLPixmapGLPaintDevice::endPaint() +{ + if (!data->isValid()) + return; + + data->copyBackFromRenderFbo(false); + + // Base's endPaint will restore the previous FBO binding + QGLPaintDevice::endPaint(); + + qgl_fbo_pool()->release(data->m_renderFbo); + data->m_renderFbo = 0; +} + +QGLContext* QGLPixmapGLPaintDevice::context() const +{ + data->ensureCreated(); + return data->m_ctx; +} + +QSize QGLPixmapGLPaintDevice::size() const +{ + return data->size(); +} + +bool QGLPixmapGLPaintDevice::alphaRequested() const +{ + return data->m_hasAlpha; +} + +void QGLPixmapGLPaintDevice::setPixmapData(QGLPixmapData* d) +{ + data = d; +} + +int qt_gl_pixmap_serial = 0; + +QGLPixmapData::QGLPixmapData(PixelType type) + : QPixmapData(type, OpenGLClass) + , m_renderFbo(0) + , m_engine(0) + , m_ctx(0) + , nativeImageHandleProvider(0) + , nativeImageHandle(0) + , m_dirty(false) + , m_hasFillColor(false) + , m_hasAlpha(false) + , inLRU(false) + , failedToAlloc(false) + , inTexturePool(false) +{ + setSerialNumber(++qt_gl_pixmap_serial); + m_glDevice.setPixmapData(this); + + qt_gl_register_pixmap(this); +} + +QGLPixmapData::~QGLPixmapData() +{ + delete m_engine; + + destroyTexture(); + qt_gl_unregister_pixmap(this); +} + +void QGLPixmapData::destroyTexture() +{ + if (inTexturePool) { + QGLTexturePool *pool = QGLTexturePool::instance(); + if (m_texture.id) + pool->releaseTexture(this, m_texture.id); + } else { + if (m_texture.id) { + QGLWidget *shareWidget = qt_gl_share_widget(); + if (shareWidget) { + QGLShareContextScope ctx(shareWidget->context()); + glDeleteTextures(1, &m_texture.id); + } + } + } + m_texture.id = 0; + inTexturePool = false; + + releaseNativeImageHandle(); +} + +QPixmapData *QGLPixmapData::createCompatiblePixmapData() const +{ + return new QGLPixmapData(pixelType()); +} + +bool QGLPixmapData::isValid() const +{ + return w > 0 && h > 0; +} + +bool QGLPixmapData::isValidContext(const QGLContext *ctx) const +{ + if (ctx == m_ctx) + return true; + + const QGLContext *share_ctx = qt_gl_share_widget()->context(); + return ctx == share_ctx || QGLContext::areSharing(ctx, share_ctx); +} + +void QGLPixmapData::resize(int width, int height) +{ + if (width == w && height == h) + return; + + if (width <= 0 || height <= 0) { + width = 0; + height = 0; + } + + w = width; + h = height; + is_null = (w <= 0 || h <= 0); + d = pixelType() == QPixmapData::PixmapType ? 32 : 1; + + destroyTexture(); + + m_source = QVolatileImage(); + m_dirty = isValid(); + setSerialNumber(++qt_gl_pixmap_serial); +} + +void QGLPixmapData::ensureCreated() const +{ + if (!m_dirty) + return; + + m_dirty = false; + + if (nativeImageHandleProvider && !nativeImageHandle) + const_cast<QGLPixmapData *>(this)->createFromNativeImageHandleProvider(); + + QGLShareContextScope ctx(qt_gl_share_widget()->context()); + m_ctx = ctx; + + const GLenum internal_format = m_hasAlpha ? GL_RGBA : GL_RGB; +#ifdef QT_OPENGL_ES_2 + const GLenum external_format = internal_format; +#else + const GLenum external_format = qt_gl_preferredTextureFormat(); +#endif + const GLenum target = GL_TEXTURE_2D; + + GLenum type = GL_UNSIGNED_BYTE; + // Avoid conversion when pixmap is created from CFbsBitmap of EColor64K. + if (!m_source.isNull() && m_source.format() == QImage::Format_RGB16) + type = GL_UNSIGNED_SHORT_5_6_5; + + m_texture.options &= ~QGLContext::MemoryManagedBindOption; + + if (!m_texture.id) { + m_texture.id = QGLTexturePool::instance()->createTextureForPixmap( + target, + 0, internal_format, + w, h, + external_format, + type, + const_cast<QGLPixmapData*>(this)); + if (!m_texture.id) { + failedToAlloc = true; + return; + } + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + inTexturePool = true; + } else if (inTexturePool) { + glBindTexture(target, m_texture.id); + QGLTexturePool::instance()->useTexture(const_cast<QGLPixmapData*>(this)); + } + + if (!m_source.isNull() && m_texture.id) { + if (external_format == GL_RGB) { + m_source.beginDataAccess(); + QImage tx; + if (type == GL_UNSIGNED_BYTE) + tx = m_source.imageRef().convertToFormat(QImage::Format_RGB888).mirrored(false, true); + else if (type == GL_UNSIGNED_SHORT_5_6_5) + tx = m_source.imageRef().mirrored(false, true); + m_source.endDataAccess(true); + + glBindTexture(target, m_texture.id); + if (!tx.isNull()) + glTexSubImage2D(target, 0, 0, 0, w, h, external_format, + type, tx.constBits()); + else + qWarning("QGLPixmapData: Failed to create GL_RGB image of size %dx%d", w, h); + } else { + // do byte swizzling ARGB -> RGBA + m_source.beginDataAccess(); + const QImage tx = ctx->d_func()->convertToGLFormat(m_source.imageRef(), true, external_format); + m_source.endDataAccess(true); + glBindTexture(target, m_texture.id); + if (!tx.isNull()) + glTexSubImage2D(target, 0, 0, 0, w, h, external_format, + type, tx.constBits()); + else + qWarning("QGLPixmapData: Failed to create GL_RGBA image of size %dx%d", w, h); + } + + if (useFramebufferObjects()) + m_source = QVolatileImage(); + } +} + + +void QGLPixmapData::fromImage(const QImage &image, + Qt::ImageConversionFlags flags) +{ + QImage img = image; + createPixmapForImage(img, flags, false); +} + +void QGLPixmapData::fromImageReader(QImageReader *imageReader, + Qt::ImageConversionFlags flags) +{ + QImage image = imageReader->read(); + if (image.isNull()) + return; + + createPixmapForImage(image, flags, true); +} + +bool QGLPixmapData::fromFile(const QString &filename, const char *format, + Qt::ImageConversionFlags flags) +{ + if (pixelType() == QPixmapData::BitmapType) + return QPixmapData::fromFile(filename, format, flags); + QFile file(filename); + if (file.open(QIODevice::ReadOnly)) { + QByteArray data = file.peek(64); + bool alpha; + if (m_texture.canBindCompressedTexture + (data.constData(), data.size(), format, &alpha)) { + resize(0, 0); + data = file.readAll(); + file.close(); + QGLShareContextScope ctx(qt_gl_share_widget()->context()); + QSize size = m_texture.bindCompressedTexture + (data.constData(), data.size(), format); + if (!size.isEmpty()) { + w = size.width(); + h = size.height(); + is_null = false; + d = 32; + m_hasAlpha = alpha; + m_source = QVolatileImage(); + m_dirty = isValid(); + return true; + } + return false; + } + } + + QImage image = QImageReader(filename, format).read(); + if (image.isNull()) + return false; + + createPixmapForImage(image, flags, true); + + return !isNull(); +} + +bool QGLPixmapData::fromData(const uchar *buffer, uint len, const char *format, + Qt::ImageConversionFlags flags) +{ + bool alpha; + const char *buf = reinterpret_cast<const char *>(buffer); + if (m_texture.canBindCompressedTexture(buf, int(len), format, &alpha)) { + resize(0, 0); + QGLShareContextScope ctx(qt_gl_share_widget()->context()); + QSize size = m_texture.bindCompressedTexture(buf, int(len), format); + if (!size.isEmpty()) { + w = size.width(); + h = size.height(); + is_null = false; + d = 32; + m_hasAlpha = alpha; + m_source = QVolatileImage(); + m_dirty = isValid(); + return true; + } + } + + QByteArray a = QByteArray::fromRawData(reinterpret_cast<const char *>(buffer), len); + QBuffer b(&a); + b.open(QIODevice::ReadOnly); + QImage image = QImageReader(&b, format).read(); + if (image.isNull()) + return false; + + createPixmapForImage(image, flags, true); + + return !isNull(); +} + +QImage::Format QGLPixmapData::idealFormat(QImage &image, Qt::ImageConversionFlags flags) +{ + QImage::Format format = QImage::Format_RGB32; + if (qApp->desktop()->depth() == 16) + format = QImage::Format_RGB16; + + if (image.hasAlphaChannel() + && ((flags & Qt::NoOpaqueDetection) + || const_cast<QImage &>(image).data_ptr()->checkForAlphaPixels())) + format = QImage::Format_ARGB32_Premultiplied; + + return format; +} + +void QGLPixmapData::createPixmapForImage(QImage &image, Qt::ImageConversionFlags flags, bool inPlace) +{ + if (image.size() == QSize(w, h)) + setSerialNumber(++qt_gl_pixmap_serial); + + resize(image.width(), image.height()); + + if (pixelType() == BitmapType) { + QImage convertedImage = image.convertToFormat(QImage::Format_MonoLSB); + if (image.format() == QImage::Format_MonoLSB) + convertedImage.detach(); + + m_source = QVolatileImage(convertedImage); + + } else { + QImage::Format format = idealFormat(image, flags); + + if (inPlace && image.data_ptr()->convertInPlace(format, flags)) { + m_source = QVolatileImage(image); + } else { + QImage convertedImage = image.convertToFormat(format); + + // convertToFormat won't detach the image if format stays the same. + if (image.format() == format) + convertedImage.detach(); + + m_source = QVolatileImage(convertedImage); + } + } + + m_dirty = true; + m_hasFillColor = false; + + m_hasAlpha = m_source.hasAlphaChannel(); + w = image.width(); + h = image.height(); + is_null = (w <= 0 || h <= 0); + d = m_source.depth(); + + destroyTexture(); +} + +bool QGLPixmapData::scroll(int dx, int dy, const QRect &rect) +{ + Q_UNUSED(dx); + Q_UNUSED(dy); + Q_UNUSED(rect); + return false; +} + +void QGLPixmapData::copy(const QPixmapData *data, const QRect &rect) +{ + if (data->classId() != QPixmapData::OpenGLClass || !static_cast<const QGLPixmapData *>(data)->useFramebufferObjects()) { + QPixmapData::copy(data, rect); + return; + } + + const QGLPixmapData *other = static_cast<const QGLPixmapData *>(data); + if (other->m_renderFbo) { + QGLShareContextScope ctx(qt_gl_share_widget()->context()); + + resize(rect.width(), rect.height()); + m_hasAlpha = other->m_hasAlpha; + ensureCreated(); + + if (!ctx->d_ptr->fbo) + glGenFramebuffers(1, &ctx->d_ptr->fbo); + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, ctx->d_ptr->fbo); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_2D, m_texture.id, 0); + + if (!other->m_renderFbo->isBound()) + glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, other->m_renderFbo->handle()); + + glDisable(GL_SCISSOR_TEST); + if (ctx->d_ptr->active_engine && ctx->d_ptr->active_engine->type() == QPaintEngine::OpenGL2) + static_cast<QGL2PaintEngineEx *>(ctx->d_ptr->active_engine)->invalidateState(); + + glBlitFramebufferEXT(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height(), + 0, 0, w, h, + GL_COLOR_BUFFER_BIT, + GL_NEAREST); + + glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo); + } else { + QPixmapData::copy(data, rect); + } +} + +void QGLPixmapData::fill(const QColor &color) +{ + if (!isValid()) + return; + + bool hasAlpha = color.alpha() != 255; + if (hasAlpha && !m_hasAlpha) { + if (m_texture.id) { + destroyTexture(); + m_dirty = true; + } + m_hasAlpha = color.alpha() != 255; + } + + if (useFramebufferObjects()) { + m_source = QVolatileImage(); + m_hasFillColor = true; + m_fillColor = color; + } else { + forceToImage(); + + if (m_source.depth() == 32) { + m_source.fill(PREMUL(color.rgba())); + + } else if (m_source.depth() == 1) { + if (color == Qt::color1) + m_source.fill(1); + else + m_source.fill(0); + } + } +} + +bool QGLPixmapData::hasAlphaChannel() const +{ + return m_hasAlpha; +} + +QImage QGLPixmapData::fillImage(const QColor &color) const +{ + QImage img; + if (pixelType() == BitmapType) { + img = QImage(w, h, QImage::Format_MonoLSB); + + img.setColorCount(2); + img.setColor(0, QColor(Qt::color0).rgba()); + img.setColor(1, QColor(Qt::color1).rgba()); + + if (color == Qt::color1) + img.fill(1); + else + img.fill(0); + } else { + img = QImage(w, h, + m_hasAlpha + ? QImage::Format_ARGB32_Premultiplied + : QImage::Format_RGB32); + img.fill(PREMUL(color.rgba())); + } + return img; +} + +extern QImage qt_gl_read_texture(const QSize &size, bool alpha_format, bool include_alpha); + +QImage QGLPixmapData::toImage() const +{ + if (!isValid()) + return QImage(); + + if (m_renderFbo) { + copyBackFromRenderFbo(true); + } else if (!m_source.isNull()) { + // QVolatileImage::toImage() will make a copy always so no check + // for active painting is needed. + QImage img = m_source.toImage(); + if (img.format() == QImage::Format_MonoLSB) { + img.setColorCount(2); + img.setColor(0, QColor(Qt::color0).rgba()); + img.setColor(1, QColor(Qt::color1).rgba()); + } + return img; + } else if (m_dirty || m_hasFillColor) { + return fillImage(m_fillColor); + } else { + ensureCreated(); + } + + QGLShareContextScope ctx(qt_gl_share_widget()->context()); + glBindTexture(GL_TEXTURE_2D, m_texture.id); + return qt_gl_read_texture(QSize(w, h), true, true); +} + +struct TextureBuffer +{ + QGLFramebufferObject *fbo; + QGL2PaintEngineEx *engine; +}; + +Q_GLOBAL_STATIC(QGLFramebufferObjectPool, _qgl_fbo_pool) +QGLFramebufferObjectPool* qgl_fbo_pool() +{ + return _qgl_fbo_pool(); +} + +void QGLPixmapData::copyBackFromRenderFbo(bool keepCurrentFboBound) const +{ + if (!isValid()) + return; + + m_hasFillColor = false; + + const QGLContext *share_ctx = qt_gl_share_widget()->context(); + QGLShareContextScope ctx(share_ctx); + + ensureCreated(); + + if (!ctx->d_ptr->fbo) + glGenFramebuffers(1, &ctx->d_ptr->fbo); + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, ctx->d_ptr->fbo); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_2D, m_texture.id, 0); + + const int x0 = 0; + const int x1 = w; + const int y0 = 0; + const int y1 = h; + + if (!m_renderFbo->isBound()) + glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, m_renderFbo->handle()); + + glDisable(GL_SCISSOR_TEST); + + glBlitFramebufferEXT(x0, y0, x1, y1, + x0, y0, x1, y1, + GL_COLOR_BUFFER_BIT, + GL_NEAREST); + + if (keepCurrentFboBound) { + glBindFramebuffer(GL_FRAMEBUFFER_EXT, ctx->d_ptr->current_fbo); + } else { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, m_renderFbo->handle()); + ctx->d_ptr->current_fbo = m_renderFbo->handle(); + } +} + +bool QGLPixmapData::useFramebufferObjects() const +{ +#ifdef Q_OS_SYMBIAN + // We don't want to use FBOs on Symbian + return false; +#else + return QGLFramebufferObject::hasOpenGLFramebufferObjects() + && QGLFramebufferObject::hasOpenGLFramebufferBlit() + && qt_gl_preferGL2Engine() + && (w * h > 32*32); // avoid overhead of FBOs for small pixmaps +#endif +} + +QPaintEngine* QGLPixmapData::paintEngine() const +{ + if (!isValid()) + return 0; + + if (m_renderFbo) + return m_engine; + + if (useFramebufferObjects()) { + extern QGLWidget* qt_gl_share_widget(); + + if (!QGLContext::currentContext()) + qt_gl_share_widget()->makeCurrent(); + QGLShareContextScope ctx(qt_gl_share_widget()->context()); + + QGLFramebufferObjectFormat format; + format.setAttachment(QGLFramebufferObject::CombinedDepthStencil); + format.setSamples(4); + format.setInternalTextureFormat(GLenum(m_hasAlpha ? GL_RGBA : GL_RGB)); + + m_renderFbo = qgl_fbo_pool()->acquire(size(), format); + + if (m_renderFbo) { + if (!m_engine) + m_engine = new QGL2PaintEngineEx; + return m_engine; + } + + qWarning() << "Failed to create pixmap texture buffer of size " << size() << ", falling back to raster paint engine"; + } + + // If the application wants to paint into the QPixmap, we first + // force it to QImage format and then paint into that. + // This is simpler than juggling multiple GL contexts. + const_cast<QGLPixmapData *>(this)->forceToImage(); + + if (m_hasFillColor) { + m_source.fill(PREMUL(m_fillColor.rgba())); + m_hasFillColor = false; + } + return m_source.paintEngine(); +} + +extern QRgb qt_gl_convertToGLFormat(QRgb src_pixel, GLenum texture_format); + +// If copyBack is true, bind will copy the contents of the render +// FBO to the texture (which is not bound to the texture, as it's +// a multisample FBO). +GLuint QGLPixmapData::bind(bool copyBack) const +{ + if (m_renderFbo && copyBack) { + copyBackFromRenderFbo(true); + } else { + ensureCreated(); + } + + GLuint id = m_texture.id; + glBindTexture(GL_TEXTURE_2D, id); + + if (m_hasFillColor) { + if (!useFramebufferObjects()) { + m_source = QVolatileImage(w, h, QImage::Format_ARGB32_Premultiplied); + m_source.fill(PREMUL(m_fillColor.rgba())); + } + + m_hasFillColor = false; + + GLenum format = qt_gl_preferredTextureFormat(); + QImage tx(w, h, QImage::Format_ARGB32_Premultiplied); + tx.fill(qt_gl_convertToGLFormat(m_fillColor.rgba(), format)); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, format, GL_UNSIGNED_BYTE, tx.constBits()); + } + + return id; +} + +QGLTexture* QGLPixmapData::texture() const +{ + return &m_texture; +} + +void QGLPixmapData::detachTextureFromPool() +{ + if (inTexturePool) { + QGLTexturePool::instance()->detachTexture(this); + inTexturePool = false; + } +} + +void QGLPixmapData::hibernate() +{ + // If the image was imported (e.g, from an SgImage under Symbian), then + // skip the hibernation, there is no sense in copying it back to main + // memory because the data is most likely shared between several processes. + bool skipHibernate = (m_texture.id && m_source.isNull()); +#if defined(Q_OS_SYMBIAN) + // However we have to proceed normally if the image was retrieved via + // a handle provider. + skipHibernate &= !nativeImageHandleProvider; +#endif + if (skipHibernate) + return; + + forceToImage(); + destroyTexture(); +} + +void QGLPixmapData::reclaimTexture() +{ + if (!inTexturePool) + return; + forceToImage(); + destroyTexture(); +} + +Q_GUI_EXPORT int qt_defaultDpiX(); +Q_GUI_EXPORT int qt_defaultDpiY(); + +int QGLPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const +{ + if (w == 0) + return 0; + + switch (metric) { + case QPaintDevice::PdmWidth: + return w; + case QPaintDevice::PdmHeight: + return h; + case QPaintDevice::PdmNumColors: + return 0; + case QPaintDevice::PdmDepth: + return d; + case QPaintDevice::PdmWidthMM: + return qRound(w * 25.4 / qt_defaultDpiX()); + case QPaintDevice::PdmHeightMM: + return qRound(h * 25.4 / qt_defaultDpiY()); + case QPaintDevice::PdmDpiX: + case QPaintDevice::PdmPhysicalDpiX: + return qt_defaultDpiX(); + case QPaintDevice::PdmDpiY: + case QPaintDevice::PdmPhysicalDpiY: + return qt_defaultDpiY(); + default: + qWarning("QGLPixmapData::metric(): Invalid metric"); + return 0; + } +} + +// Force the pixmap data to be backed by some valid data. +void QGLPixmapData::forceToImage() +{ + if (!isValid()) + return; + + if (m_source.isNull()) { + QImage::Format format = QImage::Format_ARGB32_Premultiplied; + if (pixelType() == BitmapType) + format = QImage::Format_MonoLSB; + m_source = QVolatileImage(w, h, format); + } + + m_dirty = true; +} + +QGLPaintDevice *QGLPixmapData::glDevice() const +{ + return &m_glDevice; +} + +QT_END_NAMESPACE diff --git a/src/opengl/qwindowsurface_gl.cpp b/src/opengl/qwindowsurface_gl.cpp index 0bffbda..ed541ce 100644 --- a/src/opengl/qwindowsurface_gl.cpp +++ b/src/opengl/qwindowsurface_gl.cpp @@ -181,16 +181,14 @@ QGLGraphicsSystem::QGLGraphicsSystem(bool useX11GL) // // QGLWindowSurface // - class QGLGlobalShareWidget { public: - QGLGlobalShareWidget() : widget(0), initializing(false) {} + QGLGlobalShareWidget() : firstPixmap(0), widgetRefCount(0), widget(0), initializing(false) {} QGLWidget *shareWidget() { if (!initializing && !widget && !cleanedUp) { initializing = true; - widget = new QGLWidget(QGLFormat(QGL::SingleBuffer | QGL::NoDepthBuffer | QGL::NoStencilBuffer)); widget->resize(1, 1); @@ -226,6 +224,9 @@ public: static bool cleanedUp; + QGLPixmapData *firstPixmap; + int widgetRefCount; + private: QGLWidget *widget; bool initializing; @@ -256,6 +257,43 @@ void qt_destroy_gl_share_widget() _qt_gl_share_widget()->destroy(); } +#ifdef QGL_USE_TEXTURE_POOL +void qt_gl_register_pixmap(QGLPixmapData *pd) +{ + QGLGlobalShareWidget *shared = _qt_gl_share_widget(); + pd->next = shared->firstPixmap; + pd->prev = 0; + if (shared->firstPixmap) + shared->firstPixmap->prev = pd; + shared->firstPixmap = pd; +} + +void qt_gl_unregister_pixmap(QGLPixmapData *pd) +{ + if (pd->next) + pd->next->prev = pd->prev; + if (pd->prev) { + pd->prev->next = pd->next; + } else { + QGLGlobalShareWidget *shared = _qt_gl_share_widget(); + if (shared) + shared->firstPixmap = pd->next; + } +} + +void qt_gl_hibernate_pixmaps() +{ + QGLGlobalShareWidget *shared = _qt_gl_share_widget(); + + // Scan all QGLPixmapData objects in the system and hibernate them. + QGLPixmapData *pd = shared->firstPixmap; + while (pd != 0) { + pd->hibernate(); + pd = pd->next; + } +} +#endif + struct QGLWindowSurfacePrivate { QGLFramebufferObject *fbo; @@ -333,6 +371,10 @@ QGLWindowSurface::QGLWindowSurface(QWidget *window) d_ptr->q_ptr = this; d_ptr->geometry_updated = false; d_ptr->did_paint = false; + +#ifdef QGL_NO_PRESERVED_SWAP + setPartialUpdateSupport(false); +#endif } QGLWindowSurface::~QGLWindowSurface() @@ -347,6 +389,27 @@ QGLWindowSurface::~QGLWindowSurface() delete d_ptr->pb; delete d_ptr->fbo; delete d_ptr; + + if (QGLGlobalShareWidget::cleanedUp) + return; + + --(_qt_gl_share_widget()->widgetRefCount); + +#ifdef QGL_USE_TEXTURE_POOL + if (_qt_gl_share_widget()->widgetRefCount <= 0) { + // All of the widget window surfaces have been destroyed + // but we still have GL pixmaps active. Ask them to hibernate + // to free up GPU resources until a widget is shown again. + // This may eventually cause the EGLContext to be destroyed + // because nothing in the system needs a context, which will + // free up even more GPU resources. + qt_gl_hibernate_pixmaps(); + + // Destroy the context if necessary. + if (!qt_gl_share_widget()->context()->isSharing()) + qt_destroy_gl_share_widget(); + } +#endif } void QGLWindowSurface::deleted(QObject *object) @@ -394,6 +457,9 @@ void QGLWindowSurface::hijackWindow(QWidget *widget) ctx->create(qt_gl_share_widget()->context()); + if (widget != qt_gl_share_widget()) + ++(_qt_gl_share_widget()->widgetRefCount); + #ifndef QT_NO_EGL static bool checkedForNOKSwapRegion = false; static bool haveNOKSwapRegion = false; @@ -406,8 +472,16 @@ void QGLWindowSurface::hijackWindow(QWidget *widget) qDebug() << "Found EGL_NOK_swap_region2 extension. Using partial updates."; } - if (ctx->d_func()->eglContext->configAttrib(EGL_SWAP_BEHAVIOR) != EGL_BUFFER_PRESERVED && - ! haveNOKSwapRegion) + bool swapBehaviourPreserved = ctx->d_func()->eglContext->configAttrib(EGL_SWAP_BEHAVIOR); + if (ctx->d_func()->eglContext->configAttrib(EGL_SURFACE_TYPE)&EGL_SWAP_BEHAVIOR_PRESERVED_BIT) { + EGLint swapBehavior; + if (eglQuerySurface(ctx->d_func()->eglContext->display(), ctx->d_func()->eglSurface + , EGL_SWAP_BEHAVIOR, &swapBehavior)) { + swapBehaviourPreserved = (swapBehavior == EGL_BUFFER_PRESERVED); + } + } + + if (!swapBehaviourPreserved && !haveNOKSwapRegion) setPartialUpdateSupport(false); // Force full-screen updates else setPartialUpdateSupport(true); @@ -421,7 +495,9 @@ void QGLWindowSurface::hijackWindow(QWidget *widget) voidPtr = &widgetPrivate->extraData()->glContext; d_ptr->contexts << ctxPtr; +#ifndef Q_OS_SYMBIAN qDebug() << "hijackWindow() context created for" << widget << d_ptr->contexts.size(); +#endif } QGLContext *QGLWindowSurface::context() const @@ -450,6 +526,8 @@ static void drawTexture(const QRectF &rect, GLuint tex_id, const QSize &texSize, void QGLWindowSurface::beginPaint(const QRegion &) { + updateGeometry(); + if (!context()) return; @@ -810,14 +888,22 @@ void QGLWindowSurface::updateGeometry() { ctx->d_func()->eglSurface = QEgl::createSurface(ctx->device(), ctx->d_func()->eglContext->config()); -#if !defined(QGL_NO_PRESERVED_SWAP) - eglGetError(); // Clear error state first. - eglSurfaceAttrib(QEgl::display(), ctx->d_func()->eglSurface, - EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); - if (eglGetError() != EGL_SUCCESS) { - qWarning("QGLWindowSurface: could not restore preserved swap behaviour"); + eglGetError(); // Clear error state. + if (hasPartialUpdateSupport()) { + eglSurfaceAttrib(ctx->d_func()->eglContext->display(), + ctx->d_func()->eglSurface, + EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); + + if (eglGetError() != EGL_SUCCESS) + qWarning("QGLWindowSurface: could not enable preserved swap behaviour"); + } else { + eglSurfaceAttrib(ctx->d_func()->eglContext->display(), + ctx->d_func()->eglSurface, + EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED); + + if (eglGetError() != EGL_SUCCESS) + qWarning("QGLWindowSurface: could not enable destroyed swap behaviour"); } -#endif } #endif @@ -908,8 +994,9 @@ void QGLWindowSurface::updateGeometry() { if (d_ptr->destructive_swap_buffers) initializeOffscreenTexture(surfSize); #endif - - qDebug() << "QGLWindowSurface: Using plain widget as window surface" << this;; +#ifndef Q_OS_SYMBIAN + qDebug() << "QGLWindowSurface: Using plain widget as window surface" << this; +#endif d_ptr->ctx = ctx; d_ptr->ctx->d_ptr->internal_context = true; } diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp index f0f198f..ebdfa5f 100644 --- a/src/openvg/qpaintengine_vg.cpp +++ b/src/openvg/qpaintengine_vg.cpp @@ -1024,9 +1024,11 @@ static VGImage toVGImage switch (img.format()) { case QImage::Format_Mono: img = image.convertToFormat(QImage::Format_MonoLSB, flags); + img.invertPixels(); format = VG_BW_1; break; case QImage::Format_MonoLSB: + img.invertPixels(); format = VG_BW_1; break; case QImage::Format_RGB32: @@ -2333,6 +2335,7 @@ bool QVGPaintEngine::isDefaultClipRect(const QRect& rect) void QVGPaintEngine::clipEnabledChanged() { #if defined(QVG_SCISSOR_CLIP) + vgSeti(VG_MASKING, VG_FALSE); // disable mask fallback updateScissor(); #else Q_D(QVGPaintEngine); @@ -3070,6 +3073,95 @@ static void drawVGImage(QVGPaintEnginePrivate *d, vgDrawImage(vgImg); } +static void drawImageTiled(QVGPaintEnginePrivate *d, + const QRectF &r, + const QImage &image, + const QRectF &sr = QRectF()) +{ + const int minTileSize = 16; + int tileWidth = 512; + int tileHeight = tileWidth; + + VGImageFormat tileFormat = qt_vg_image_to_vg_format(image.format()); + VGImage tile = VG_INVALID_HANDLE; + QVGImagePool *pool = QVGImagePool::instance(); + while (tile == VG_INVALID_HANDLE && tileWidth >= minTileSize) { + tile = pool->createPermanentImage(tileFormat, tileWidth, tileHeight, + VG_IMAGE_QUALITY_FASTER); + if (tile == VG_INVALID_HANDLE) { + tileWidth /= 2; + tileHeight /= 2; + } + } + if (tile == VG_INVALID_HANDLE) { + qWarning("drawImageTiled: Failed to create %dx%d tile, giving up", tileWidth, tileHeight); + return; + } + + VGfloat opacityMatrix[20] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, d->opacity, + 0.0f, 0.0f, 0.0f, 0.0f + }; + VGImage tileWithOpacity = VG_INVALID_HANDLE; + if (d->opacity != 1) { + tileWithOpacity = pool->createPermanentImage(VG_sARGB_8888_PRE, + tileWidth, tileHeight, VG_IMAGE_QUALITY_FASTER); + if (tileWithOpacity == VG_INVALID_HANDLE) + qWarning("drawImageTiled: Failed to create extra tile, ignoring opacity"); + } + + QRect sourceRect = sr.toRect(); + if (sourceRect.isNull()) + sourceRect = QRect(0, 0, image.width(), image.height()); + + VGfloat scaleX = r.width() / sourceRect.width(); + VGfloat scaleY = r.height() / sourceRect.height(); + + d->setImageOptions(); + + for (int y = sourceRect.y(); y < sourceRect.height(); y += tileHeight) { + int h = qMin(tileHeight, sourceRect.height() - y); + if (h < 1) + break; + for (int x = sourceRect.x(); x < sourceRect.width(); x += tileWidth) { + int w = qMin(tileWidth, sourceRect.width() - x); + if (w < 1) + break; + + int bytesPerPixel = image.depth() / 8; + const uchar *sptr = image.constBits() + x * bytesPerPixel + y * image.bytesPerLine(); + vgImageSubData(tile, sptr, image.bytesPerLine(), tileFormat, 0, 0, w, h); + + QTransform transform(d->imageTransform); + transform.translate(r.x() + x, r.y() + y); + transform.scale(scaleX, scaleY); + d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform); + + VGImage actualTile = tile; + if (tileWithOpacity != VG_INVALID_HANDLE) { + vgColorMatrix(tileWithOpacity, actualTile, opacityMatrix); + if (w < tileWidth || h < tileHeight) + actualTile = vgChildImage(tileWithOpacity, 0, 0, w, h); + else + actualTile = tileWithOpacity; + } else if (w < tileWidth || h < tileHeight) { + actualTile = vgChildImage(tile, 0, 0, w, h); + } + vgDrawImage(actualTile); + + if (actualTile != tile && actualTile != tileWithOpacity) + vgDestroyImage(actualTile); + } + } + + vgDestroyImage(tile); + if (tileWithOpacity != VG_INVALID_HANDLE) + vgDestroyImage(tileWithOpacity); +} + // Used by qpixmapfilter_vg.cpp to draw filtered VGImage's. void qt_vg_drawVGImage(QPainter *painter, const QPointF& pos, VGImage vgImg) { @@ -3099,6 +3191,19 @@ void qt_vg_drawVGImageStencil bool QVGPaintEngine::canVgWritePixels(const QImage &image) const { Q_D(const QVGPaintEngine); + + // qt_vg_image_to_vg_format returns VG_sARGB_8888 as + // fallback case if no matching VG format is found. + // If given image format is not Format_ARGB32 and returned + // format is VG_sARGB_8888, it means that no match was + // found. In that case vgWritePixels cannot be used. + // Also 1-bit formats cannot be used directly either. + if ((image.format() != QImage::Format_ARGB32 + && qt_vg_image_to_vg_format(image.format()) == VG_sARGB_8888) + || image.depth() == 1) { + return false; + } + // vgWritePixels ignores masking, blending and xforms so we can only use it if // ALL of the following conditions are true: // - It is a simple translate, or a scale of -1 on the y-axis (inverted) @@ -3169,7 +3274,7 @@ void QVGPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pm) vgpd->source.beginDataAccess(); drawImage(pos, vgpd->source.imageRef()); - vgpd->source.endDataAccess(); + vgpd->source.endDataAccess(true); } else { drawImage(pos, *(pd->buffer())); } @@ -3180,6 +3285,8 @@ void QVGPaintEngine::drawImage Qt::ImageConversionFlags flags) { Q_D(QVGPaintEngine); + if (image.isNull()) + return; VGImage vgImg; if (d->simpleTransform || d->opacity == 1.0f) vgImg = toVGImageSubRect(image, sr.toRect(), flags); @@ -3216,7 +3323,10 @@ void QVGPaintEngine::drawImage } else { // Monochrome images need to use the vgChildImage() path. vgImg = toVGImage(image, flags); - drawVGImage(d, r, vgImg, image.size(), sr); + if (vgImg == VG_INVALID_HANDLE) + drawImageTiled(d, r, image, sr); + else + drawVGImage(d, r, vgImg, image.size(), sr); } } vgDestroyImage(vgImg); @@ -3225,6 +3335,8 @@ void QVGPaintEngine::drawImage void QVGPaintEngine::drawImage(const QPointF &pos, const QImage &image) { Q_D(QVGPaintEngine); + if (image.isNull()) + return; VGImage vgImg; if (canVgWritePixels(image)) { // Optimization for straight blits, no blending @@ -3241,7 +3353,10 @@ void QVGPaintEngine::drawImage(const QPointF &pos, const QImage &image) } else { vgImg = toVGImageWithOpacity(image, d->opacity); } - drawVGImage(d, pos, vgImg); + if (vgImg == VG_INVALID_HANDLE) + drawImageTiled(d, QRectF(pos, image.size()), image); + else + drawVGImage(d, pos, vgImg); vgDestroyImage(vgImg); } @@ -4018,6 +4133,8 @@ VGImageFormat qt_vg_image_to_vg_format(QImage::Format format) switch (format) { case QImage::Format_MonoLSB: return VG_BW_1; + case QImage::Format_Indexed8: + return VG_sL_8; case QImage::Format_ARGB32_Premultiplied: return VG_sARGB_8888_PRE; case QImage::Format_RGB32: @@ -4028,7 +4145,8 @@ VGImageFormat qt_vg_image_to_vg_format(QImage::Format format) return VG_sRGB_565; case QImage::Format_ARGB4444_Premultiplied: return VG_sARGB_4444; - default: break; + default: + break; } return VG_sARGB_8888; // XXX } diff --git a/src/openvg/qpixmapdata_vg.cpp b/src/openvg/qpixmapdata_vg.cpp index 3f67c79..80f5b2f 100644 --- a/src/openvg/qpixmapdata_vg.cpp +++ b/src/openvg/qpixmapdata_vg.cpp @@ -458,7 +458,7 @@ void QVGPixmapData::hibernate() if (skipHibernate) return; - forceToImage(); + forceToImage(false); // no readback allowed here destroyImageAndContext(); } @@ -502,12 +502,13 @@ int QVGPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const // Ensures that the pixmap is backed by some valid data and forces the data to // be re-uploaded to the VGImage when toVGImage() is called next time. -void QVGPixmapData::forceToImage() +void QVGPixmapData::forceToImage(bool allowReadback) { if (!isValid()) return; - ensureReadback(false); + if (allowReadback) + ensureReadback(false); if (source.isNull()) source = QVolatileImage(w, h, sourceFormat()); diff --git a/src/openvg/qpixmapdata_vg_p.h b/src/openvg/qpixmapdata_vg_p.h index 15ff889..c284596 100644 --- a/src/openvg/qpixmapdata_vg_p.h +++ b/src/openvg/qpixmapdata_vg_p.h @@ -188,7 +188,7 @@ protected: QString nativeImageType; #endif - void forceToImage(); + void forceToImage(bool allowReadback = true); QImage::Format sourceFormat() const; QImage::Format idealFormat(QImage *image, Qt::ImageConversionFlags flags) const; void updateSerial(); diff --git a/src/openvg/qvg_symbian.cpp b/src/openvg/qvg_symbian.cpp index 5eb64bd..0d2ed9e 100644 --- a/src/openvg/qvg_symbian.cpp +++ b/src/openvg/qvg_symbian.cpp @@ -150,6 +150,20 @@ void QVGPixmapData::releaseNativeImageHandle() } } +static inline bool conversionLessFormat(QImage::Format format) +{ + switch (format) { + case QImage::Format_RGB16: // EColor64K + case QImage::Format_RGB32: // EColor16MU + case QImage::Format_ARGB32: // EColor16MA + case QImage::Format_ARGB32_Premultiplied: // EColor16MAP + case QImage::Format_Indexed8: // EGray256, EColor256 + return true; + default: + return false; + } +} + void QVGPixmapData::fromNativeType(void* pixmap, NativeType type) { if (type == QPixmapData::SgImage && pixmap) { @@ -178,15 +192,19 @@ void QVGPixmapData::fromNativeType(void* pixmap, NativeType type) source = QVolatileImage(bitmap); // duplicates only, if possible if (source.isNull()) return; - // Here we may need to copy if the formats do not match. - // (e.g. for display modes other than EColor16MAP and EColor16MU) - source.ensureFormat(idealFormat(&source.imageRef(), Qt::AutoColor)); + if (!conversionLessFormat(source.format())) { + // Here we may need to copy if the formats do not match. + // (e.g. for display modes other than EColor16MAP and EColor16MU) + source.beginDataAccess(); + QImage::Format format = idealFormat(&source.imageRef(), Qt::AutoColor); + source.endDataAccess(true); + source.ensureFormat(format); + } recreate = true; } else if (type == QPixmapData::VolatileImage && pixmap) { QVolatileImage *img = static_cast<QVolatileImage *>(pixmap); resize(img->width(), img->height()); source = *img; - source.ensureFormat(idealFormat(&source.imageRef(), Qt::AutoColor)); recreate = true; } else if (type == QPixmapData::NativeImageHandleProvider && pixmap) { destroyImages(); @@ -266,8 +284,6 @@ void* QVGPixmapData::toNativeType(NativeType type) } // Just duplicate the bitmap handle, no data copying happens. return source.duplicateNativeImage(); - } else if (type == QPixmapData::VolatileImage) { - return &source; } return 0; } diff --git a/src/plugins/audio/audio.pro b/src/plugins/audio/audio.pro deleted file mode 100644 index b7a775b..0000000 --- a/src/plugins/audio/audio.pro +++ /dev/null @@ -1,3 +0,0 @@ -TEMPLATE = subdirs -SUBDIRS = - diff --git a/src/plugins/bearer/icd/dbusdispatcher.cpp b/src/plugins/bearer/icd/dbusdispatcher.cpp index 13cd8a9..a317cb4 100644 --- a/src/plugins/bearer/icd/dbusdispatcher.cpp +++ b/src/plugins/bearer/icd/dbusdispatcher.cpp @@ -194,18 +194,21 @@ static bool appendVariantToDBusMessage(const QVariant& argument, &int32_data); break; - case QVariant::String: - str_data = argument.toString().toLatin1().data(); + case QVariant::String: { + QByteArray data = argument.toString().toLatin1(); + str_data = data.data(); dbus_message_iter_append_basic(dbus_iter, DBUS_TYPE_STRING, &str_data); break; + } case QVariant::StringList: str_list = argument.toStringList(); dbus_message_iter_open_container(dbus_iter, DBUS_TYPE_ARRAY, "s", &array_iter); for (idx = 0; idx < str_list.size(); idx++) { - str_data = str_list.at(idx).toLatin1().data(); + QByteArray data = str_list.at(idx).toLatin1(); + str_data = data.data(); dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_STRING, &str_data); diff --git a/src/plugins/bearer/icd/qnetworksession_impl.cpp b/src/plugins/bearer/icd/qnetworksession_impl.cpp index af5d85e..94a6c81 100644 --- a/src/plugins/bearer/icd/qnetworksession_impl.cpp +++ b/src/plugins/bearer/icd/qnetworksession_impl.cpp @@ -621,21 +621,21 @@ static QString get_network_interface() if (ret == 0) { /* No results */ #ifdef BEARER_MANAGEMENT_DEBUG - qDebug() << "Cannot get addrinfo from icd, are you connected or is icd running?"; + qDebug() << "Cannot get addrinfo from icd, are you connected or is icd running?"; #endif - return iface; + return iface; } if (addr_results.first().ip_info.isEmpty()) - return QString(); + return QString(); - const char *address = addr_results.first().ip_info.first().address.toAscii().constData(); + QByteArray data = addr_results.first().ip_info.first().address.toAscii(); struct in_addr addr; - if (inet_aton(address, &addr) == 0) { + if (inet_aton(data.constData(), &addr) == 0) { #ifdef BEARER_MANAGEMENT_DEBUG - qDebug() << "address" << address << "invalid"; + qDebug() << "address" << data.constData() << "invalid"; #endif - return iface; + return iface; } struct ifaddrs *ifaddr, *ifa; diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp index dc74c4e..6d6fb02 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp @@ -1025,11 +1025,10 @@ void QDirectFBPaintEnginePrivate::setCompositionMode(QPainter::CompositionMode m case QPainter::CompositionMode_DestinationOut: surface->SetPorterDuff(surface, DSPD_DST_OUT); break; -#if (Q_DIRECTFB_VERSION >= 0x010209) case QPainter::CompositionMode_Destination: - surface->SetPorterDuff(surface, DSPD_DST); + surface->SetSrcBlendFunction(surface, DSBF_ZERO); + surface->SetDstBlendFunction(surface, DSBF_ONE); break; -#endif #if (Q_DIRECTFB_VERSION >= 0x010000) case QPainter::CompositionMode_SourceAtop: surface->SetPorterDuff(surface, DSPD_SRC_ATOP); diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp index 3d8cf50..9a94c30 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp @@ -365,10 +365,12 @@ void QDirectFBWindowSurface::flush(QWidget *widget, const QRegion ®ion, if (!win) return; -#ifndef QT_NO_QWS_PROXYSCREEN +#if !defined(QT_NO_QWS_PROXYSCREEN) && !defined(QT_NO_GRAPHICSVIEW) QWExtra *extra = qt_widget_private(widget)->extraData(); if (extra && extra->proxyWidget) return; +#else + Q_UNUSED(widget); #endif const quint8 windowOpacity = quint8(win->windowOpacity() * 0xff); diff --git a/src/plugins/graphicssystems/meego/qmeegographicssystem.cpp b/src/plugins/graphicssystems/meego/qmeegographicssystem.cpp index 13eab7f..69a6922 100644 --- a/src/plugins/graphicssystems/meego/qmeegographicssystem.cpp +++ b/src/plugins/graphicssystems/meego/qmeegographicssystem.cpp @@ -59,10 +59,16 @@ #include "qmeegographicssystem.h" #include "qmeegoextensions.h" +#include <QTimer> + bool QMeeGoGraphicsSystem::surfaceWasCreated = false; QHash <Qt::HANDLE, QPixmap*> QMeeGoGraphicsSystem::liveTexturePixmaps; +QList<QMeeGoSwitchCallback> QMeeGoGraphicsSystem::switchCallbacks; + +QMeeGoGraphicsSystem::SwitchPolicy QMeeGoGraphicsSystem::switchPolicy = QMeeGoGraphicsSystem::AutomaticSwitch; + QMeeGoGraphicsSystem::QMeeGoGraphicsSystem() { qDebug("Using the meego graphics system"); @@ -74,6 +80,115 @@ QMeeGoGraphicsSystem::~QMeeGoGraphicsSystem() qt_destroy_gl_share_widget(); } +class QMeeGoGraphicsSystemSwitchHandler : public QObject +{ + Q_OBJECT +public: + QMeeGoGraphicsSystemSwitchHandler(); + + void addWidget(QWidget *widget); + bool eventFilter(QObject *, QEvent *); + + void handleMapNotify(); + +private slots: + void removeWidget(QObject *object); + void switchToRaster(); + void switchToMeeGo(); + +private: + int visibleWidgets() const; + +private: + QList<QWidget *> m_widgets; +}; + +typedef bool(*QX11FilterFunction)(XEvent *event); +Q_GUI_EXPORT void qt_installX11EventFilter(QX11FilterFunction func); + +static bool x11EventFilter(XEvent *event); + +QMeeGoGraphicsSystemSwitchHandler::QMeeGoGraphicsSystemSwitchHandler() +{ + qt_installX11EventFilter(x11EventFilter); +} + +void QMeeGoGraphicsSystemSwitchHandler::addWidget(QWidget *widget) +{ + if (widget != qt_gl_share_widget() && !m_widgets.contains(widget)) { + widget->installEventFilter(this); + connect(widget, SIGNAL(destroyed(QObject *)), this, SLOT(removeWidget(QObject *))); + m_widgets << widget; + } +} + +void QMeeGoGraphicsSystemSwitchHandler::handleMapNotify() +{ + if (m_widgets.isEmpty() && QMeeGoGraphicsSystem::switchPolicy == QMeeGoGraphicsSystem::AutomaticSwitch) + QTimer::singleShot(0, this, SLOT(switchToMeeGo())); +} + +void QMeeGoGraphicsSystemSwitchHandler::removeWidget(QObject *object) +{ + m_widgets.removeOne(static_cast<QWidget *>(object)); + if (m_widgets.isEmpty() && QMeeGoGraphicsSystem::switchPolicy == QMeeGoGraphicsSystem::AutomaticSwitch) + QTimer::singleShot(0, this, SLOT(switchToRaster())); +} + +void QMeeGoGraphicsSystemSwitchHandler::switchToRaster() +{ + QMeeGoGraphicsSystem::switchToRaster(); +} + +void QMeeGoGraphicsSystemSwitchHandler::switchToMeeGo() +{ + QMeeGoGraphicsSystem::switchToMeeGo(); +} + +int QMeeGoGraphicsSystemSwitchHandler::visibleWidgets() const +{ + int count = 0; + for (int i = 0; i < m_widgets.size(); ++i) + count += m_widgets.at(i)->isVisible() && !(m_widgets.at(i)->windowState() & Qt::WindowMinimized); + return count; +} + +bool QMeeGoGraphicsSystemSwitchHandler::eventFilter(QObject *object, QEvent *event) +{ + if (event->type() == QEvent::WindowStateChange + && QMeeGoGraphicsSystem::switchPolicy == QMeeGoGraphicsSystem::AutomaticSwitch) + { + QWindowStateChangeEvent *change = static_cast<QWindowStateChangeEvent *>(event); + QWidget *widget = static_cast<QWidget *>(object); + + Qt::WindowStates current = widget->windowState(); + Qt::WindowStates old = change->oldState(); + + // did minimized flag change? + if ((current ^ old) & Qt::WindowMinimized) { + if (current & Qt::WindowMinimized) { + if (visibleWidgets() == 0) + QMeeGoGraphicsSystem::switchToRaster(); + } else { + if (visibleWidgets() > 0) + QMeeGoGraphicsSystem::switchToMeeGo(); + } + } + } + + // resume processing of event + return false; +} + +Q_GLOBAL_STATIC(QMeeGoGraphicsSystemSwitchHandler, switch_handler) + +bool x11EventFilter(XEvent *event) +{ + if (event->type == MapNotify) + switch_handler()->handleMapNotify(); + return false; +} + QWindowSurface* QMeeGoGraphicsSystem::createWindowSurface(QWidget *widget) const { QGLWidget *shareWidget = qt_gl_share_widget(); @@ -83,6 +198,9 @@ QWindowSurface* QMeeGoGraphicsSystem::createWindowSurface(QWidget *widget) const QGLShareContextScope ctx(shareWidget->context()); + if (QApplicationPrivate::instance()->graphics_system_name == QLatin1String("runtime")) + switch_handler()->addWidget(widget); + QMeeGoGraphicsSystem::surfaceWasCreated = true; QWindowSurface *surface = new QGLWindowSurface(widget); return surface; @@ -203,18 +321,7 @@ QPixmapData *QMeeGoGraphicsSystem::pixmapDataWithGLTexture(int w, int h) bool QMeeGoGraphicsSystem::meeGoRunning() { - if (! QApplicationPrivate::instance()) { - qWarning("Application not running just yet... hard to know what system running!"); - return false; - } - - QString name = QApplicationPrivate::instance()->graphics_system_name; - if (name == "runtime") { - QRuntimeGraphicsSystem *rsystem = (QRuntimeGraphicsSystem *) QApplicationPrivate::instance()->graphics_system; - name = rsystem->graphicsSystemName(); - } - - return (name == "meego"); + return runningGraphicsSystemName() == "meego"; } QPixmapData* QMeeGoGraphicsSystem::pixmapDataWithNewLiveTexture(int w, int h, QImage::Format format) @@ -259,6 +366,69 @@ void QMeeGoGraphicsSystem::destroyFenceSync(void *fenceSync) QMeeGoExtensions::eglDestroySyncKHR(QEgl::display(), fenceSync); } +QString QMeeGoGraphicsSystem::runningGraphicsSystemName() +{ + if (!QApplicationPrivate::instance()) { + qWarning("Querying graphics system but application not running yet!"); + return QString(); + } + + QString name = QApplicationPrivate::instance()->graphics_system_name; + if (name == QLatin1String("runtime")) { + QRuntimeGraphicsSystem *rsystem = (QRuntimeGraphicsSystem *) QApplicationPrivate::instance()->graphics_system; + name = rsystem->graphicsSystemName(); + } + + return name; +} + +void QMeeGoGraphicsSystem::switchToMeeGo() +{ + if (switchPolicy == NoSwitch || meeGoRunning()) + return; + + if (QApplicationPrivate::instance()->graphics_system_name != QLatin1String("runtime")) + qWarning("Can't switch to meego - switching only supported with 'runtime' graphics system."); + else { + triggerSwitchCallbacks(0, "meego"); + + QApplication *app = static_cast<QApplication *>(QCoreApplication::instance()); + app->setGraphicsSystem(QLatin1String("meego")); + + triggerSwitchCallbacks(1, "meego"); + } +} + +void QMeeGoGraphicsSystem::switchToRaster() +{ + if (switchPolicy == NoSwitch || runningGraphicsSystemName() == QLatin1String("raster")) + return; + + if (QApplicationPrivate::instance()->graphics_system_name != QLatin1String("runtime")) + qWarning("Can't switch to raster - switching only supported with 'runtime' graphics system."); + else { + triggerSwitchCallbacks(0, "raster"); + + QApplication *app = static_cast<QApplication *>(QCoreApplication::instance()); + app->setGraphicsSystem(QLatin1String("raster")); + + QMeeGoLivePixmapData::invalidateSurfaces(); + + triggerSwitchCallbacks(1, "raster"); + } +} + +void QMeeGoGraphicsSystem::registerSwitchCallback(QMeeGoSwitchCallback callback) +{ + switchCallbacks << callback; +} + +void QMeeGoGraphicsSystem::triggerSwitchCallbacks(int type, const char *name) +{ + for (int i = 0; i < switchCallbacks.size(); ++i) + switchCallbacks.at(i)(type, name); +} + /* C API */ int qt_meego_image_to_egl_shared_image(const QImage &image) @@ -340,3 +510,25 @@ void qt_meego_invalidate_live_surfaces(void) { return QMeeGoLivePixmapData::invalidateSurfaces(); } + +void qt_meego_switch_to_raster(void) +{ + QMeeGoGraphicsSystem::switchToRaster(); +} + +void qt_meego_switch_to_meego(void) +{ + QMeeGoGraphicsSystem::switchToMeeGo(); +} + +void qt_meego_register_switch_callback(QMeeGoSwitchCallback callback) +{ + QMeeGoGraphicsSystem::registerSwitchCallback(callback); +} + +void qt_meego_set_switch_policy(int policy) +{ + QMeeGoGraphicsSystem::switchPolicy = QMeeGoGraphicsSystem::SwitchPolicy(policy); +} + +#include "qmeegographicssystem.moc" diff --git a/src/plugins/graphicssystems/meego/qmeegographicssystem.h b/src/plugins/graphicssystems/meego/qmeegographicssystem.h index 27a4e7a..3528425 100644 --- a/src/plugins/graphicssystems/meego/qmeegographicssystem.h +++ b/src/plugins/graphicssystems/meego/qmeegographicssystem.h @@ -47,9 +47,13 @@ #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> +extern "C" typedef void (*QMeeGoSwitchCallback)(int type, const char *name); + class QMeeGoGraphicsSystem : public QGraphicsSystem { public: + enum SwitchPolicy { AutomaticSwitch, ManualSwitch, NoSwitch }; + QMeeGoGraphicsSystem(); ~QMeeGoGraphicsSystem(); @@ -76,13 +80,23 @@ public: static void* createFenceSync(); static void destroyFenceSync(void* fenceSync); + static void switchToRaster(); + static void switchToMeeGo(); + static QString runningGraphicsSystemName(); + + static void registerSwitchCallback(QMeeGoSwitchCallback callback); + + static SwitchPolicy switchPolicy; + private: static bool meeGoRunning(); static EGLSurface getSurfaceForLiveTexturePixmap(QPixmap *pixmap); static void destroySurfaceForLiveTexturePixmap(QPixmapData* pmd); + static void triggerSwitchCallbacks(int type, const char *name); static bool surfaceWasCreated; - static QHash <Qt::HANDLE, QPixmap*> liveTexturePixmaps; + static QHash<Qt::HANDLE, QPixmap*> liveTexturePixmaps; + static QList<QMeeGoSwitchCallback> switchCallbacks; }; /* C api */ @@ -95,7 +109,7 @@ extern "C" { Q_DECL_EXPORT bool qt_meego_destroy_egl_shared_image(Qt::HANDLE handle); Q_DECL_EXPORT void qt_meego_set_surface_fixed_size(int width, int height); Q_DECL_EXPORT void qt_meego_set_surface_scaling(int x, int y, int width, int height); - Q_DECL_EXPORT void qt_meego_set_translucent(bool translucent); + Q_DECL_EXPORT void qt_meego_set_translucent(bool translucent); Q_DECL_EXPORT QPixmapData* qt_meego_pixmapdata_with_new_live_texture(int w, int h, QImage::Format format); Q_DECL_EXPORT QPixmapData* qt_meego_pixmapdata_from_live_texture_handle(Qt::HANDLE handle); Q_DECL_EXPORT QImage* qt_meego_live_texture_lock(QPixmap *pixmap, void *fenceSync); @@ -104,6 +118,10 @@ extern "C" { Q_DECL_EXPORT void* qt_meego_create_fence_sync(void); Q_DECL_EXPORT void qt_meego_destroy_fence_sync(void* fs); Q_DECL_EXPORT void qt_meego_invalidate_live_surfaces(void); + Q_DECL_EXPORT void qt_meego_switch_to_raster(void); + Q_DECL_EXPORT void qt_meego_switch_to_meego(void); + Q_DECL_EXPORT void qt_meego_register_switch_callback(QMeeGoSwitchCallback callback); + Q_DECL_EXPORT void qt_meego_set_switch_policy(int policy); } #endif diff --git a/src/plugins/graphicssystems/meego/qmeegolivepixmapdata.cpp b/src/plugins/graphicssystems/meego/qmeegolivepixmapdata.cpp index 2a2a098..b6ba7ec 100644 --- a/src/plugins/graphicssystems/meego/qmeegolivepixmapdata.cpp +++ b/src/plugins/graphicssystems/meego/qmeegolivepixmapdata.cpp @@ -194,6 +194,8 @@ QImage* QMeeGoLivePixmapData::lock(EGLSyncKHR fenceSync) void *data = 0; int pitch = 0; + int surfaceWidth = 0; + int surfaceHeight = 0; EGLSurface surface = 0; QImage::Format format; lockedImage = QImage(); @@ -206,9 +208,11 @@ QImage* QMeeGoLivePixmapData::lock(EGLSyncKHR fenceSync) eglQuerySurface(QEgl::display(), surface, EGL_BITMAP_POINTER_KHR, (EGLint*) &data); eglQuerySurface(QEgl::display(), surface, EGL_BITMAP_PITCH_KHR, (EGLint*) &pitch); + eglQuerySurface(QEgl::display(), surface, EGL_WIDTH, (EGLint*) &surfaceWidth); + eglQuerySurface(QEgl::display(), surface, EGL_HEIGHT, (EGLint*) &surfaceHeight); // Ok, here we know we just support those two formats. Real solution would be: - // uqery also the format. + // query also the format. if (backingX11Pixmap->depth() > 16) format = QImage::Format_ARGB32_Premultiplied; else @@ -219,7 +223,13 @@ QImage* QMeeGoLivePixmapData::lock(EGLSyncKHR fenceSync) return &lockedImage; } - lockedImage = QImage((uchar *) data, width(), height(), format); + if (width() != surfaceWidth || height() != surfaceHeight) { + qWarning("Live texture dimensions don't match!"); + QMeeGoExtensions::eglUnlockSurfaceKHR(QEgl::display(), surface); + return &lockedImage; + } + + lockedImage = QImage((uchar *) data, width(), height(), pitch, format); return &lockedImage; } diff --git a/src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp b/src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp index 1da58e1..4b4f677 100644 --- a/src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp +++ b/src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp @@ -43,7 +43,7 @@ #include <QtOpenVG/private/qpixmapdata_vg_p.h> #include <QtOpenVG/private/qwindowsurface_vg_p.h> #include <QtOpenVG/private/qvgimagepool_p.h> -#if defined(Q_OS_SYMBIAN) && !defined(Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE) +#if defined(Q_OS_SYMBIAN) #include <QtGui/private/qwidget_p.h> #endif #include <QtGui/private/qapplication_p.h> @@ -70,10 +70,12 @@ QPixmapData *QVGGraphicsSystem::createPixmapData(QPixmapData::PixelType type) co QWindowSurface *QVGGraphicsSystem::createWindowSurface(QWidget *widget) const { -#if defined(Q_OS_SYMBIAN) && !defined(Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE) - QWidgetPrivate *d = qt_widget_private(widget); - if (!d->isOpaque && widget->testAttribute(Qt::WA_TranslucentBackground)) - return d->createDefaultWindowSurface_sys(); +#if defined(Q_OS_SYMBIAN) + if (!QApplicationPrivate::instance()->useTranslucentEGLSurfaces) { + QWidgetPrivate *d = qt_widget_private(widget); + if (!d->isOpaque && widget->testAttribute(Qt::WA_TranslucentBackground)) + return d->createDefaultWindowSurface_sys(); + } #endif return new QVGWindowSurface(widget); } diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index afa0901..e778ab7 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -13,5 +13,4 @@ embedded:SUBDIRS *= gfxdrivers decorations mousedrivers kbddrivers !symbian:!contains(QT_CONFIG, no-gui):SUBDIRS += accessible symbian:SUBDIRS += s60 contains(QT_CONFIG, phonon): SUBDIRS *= phonon -contains(QT_CONFIG, multimedia): SUBDIRS *= audio contains(QT_CONFIG, declarative): SUBDIRS *= qmltooling diff --git a/src/plugins/qmltooling/qmldbg_ost/qmldbg_ost.pro b/src/plugins/qmltooling/qmldbg_ost/qmldbg_ost.pro new file mode 100644 index 0000000..2748889 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_ost/qmldbg_ost.pro @@ -0,0 +1,21 @@ +TARGET = qmldbg_ost +QT += declarative network + +include(../../qpluginbase.pri) + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/qmltooling +QTDIR_build:REQUIRES += "contains(QT_CONFIG, declarative)" + +SOURCES += \ + qmlostplugin.cpp \ + qostdevice.cpp + +HEADERS += \ + qmlostplugin.h \ + qostdevice.h \ + usbostcomm.h + +target.path += $$[QT_INSTALL_PLUGINS]/qmltooling +INSTALLS += target + +symbian:TARGET.UID3=0x20031E92 diff --git a/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.cpp b/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.cpp new file mode 100644 index 0000000..1c91c34 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.cpp @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlostplugin.h" +#include "qostdevice.h" + +#include <private/qdeclarativedebugserver_p.h> +#include <private/qpacketprotocol_p.h> + +QT_BEGIN_NAMESPACE + +static const TInt KQmlOstProtocolId = 0x94; + +class QmlOstPluginPrivate { +public: + QmlOstPluginPrivate(); + + QOstDevice *ost; + QPacketProtocol *protocol; + QDeclarativeDebugServer *debugServer; +}; + +QmlOstPluginPrivate::QmlOstPluginPrivate() : + ost(0), + protocol(0), + debugServer(0) +{ +} + +QmlOstPlugin::QmlOstPlugin() : + d_ptr(new QmlOstPluginPrivate) +{ +} + +QmlOstPlugin::~QmlOstPlugin() +{ + delete d_ptr; +} + +void QmlOstPlugin::setServer(QDeclarativeDebugServer *server) +{ + Q_D(QmlOstPlugin); + d->debugServer = server; +} + +bool QmlOstPlugin::isConnected() const +{ + Q_D(const QmlOstPlugin); + return d->ost && d->ost->isOpen(); +} + +void QmlOstPlugin::send(const QByteArray &message) +{ + Q_D(QmlOstPlugin); + + if (!isConnected()) + return; + + QPacket pack; + pack.writeRawData(message.data(), message.length()); + + d->protocol->send(pack); + //d->socket->flush(); +} + +void QmlOstPlugin::disconnect() +{ + Q_D(QmlOstPlugin); + + delete d->protocol; + d->protocol = 0; +} + +void QmlOstPlugin::setPort(int port, bool block) +{ + Q_UNUSED(port); + Q_UNUSED(block); + + Q_D(QmlOstPlugin); + + d->ost = new QOstDevice(this); + bool ok = d->ost->open(KQmlOstProtocolId); + if (!ok) { + if (d->ost->errorString().length()) + qDebug("Error from QOstDevice: %s", qPrintable(d->ost->errorString())); + qWarning("QDeclarativeDebugServer: Unable to listen on OST"); // This message is part of the signalling - do not change the format! + return; + } + d->protocol = new QPacketProtocol(d->ost, this); + QObject::connect(d->protocol, SIGNAL(readyRead()), this, SLOT(readyRead())); + qWarning("QDeclarativeDebugServer: Waiting for connection via OST"); // This message is part of the signalling - do not change the format! +} + +void QmlOstPlugin::readyRead() +{ + Q_D(QmlOstPlugin); + QPacket packet = d->protocol->read(); + + QByteArray content = packet.data(); + d->debugServer->receiveMessage(content); +} + +Q_EXPORT_PLUGIN2(qmlostplugin, QmlOstPlugin) + +QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.h b/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.h new file mode 100644 index 0000000..eee6ee1 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLOSTPLUGIN_H +#define QMLOSTPLUGIN_H + +#include <QtGui/QStylePlugin> +#include <QtDeclarative/private/qdeclarativedebugserverconnection_p.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeDebugServer; +class QmlOstPluginPrivate; + +class QmlOstPlugin : public QObject, public QDeclarativeDebugServerConnection +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QmlOstPlugin) + Q_DISABLE_COPY(QmlOstPlugin) + Q_INTERFACES(QDeclarativeDebugServerConnection) + + +public: + QmlOstPlugin(); + ~QmlOstPlugin(); + + void setServer(QDeclarativeDebugServer *server); + void setPort(int port, bool bock); + + bool isConnected() const; + void send(const QByteArray &message); + void disconnect(); + +private Q_SLOTS: + void readyRead(); + +private: + QmlOstPluginPrivate *d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QMLOSTPLUGIN_H diff --git a/src/plugins/qmltooling/qmldbg_ost/qostdevice.cpp b/src/plugins/qmltooling/qmldbg_ost/qostdevice.cpp new file mode 100644 index 0000000..21b0169 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_ost/qostdevice.cpp @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qostdevice.h" +#include <e32base.h> + +#include "usbostcomm.h" + +class QOstDevicePrivate : public CActive +{ + QOstDevice* q_ptr; + Q_DECLARE_PUBLIC(QOstDevice) + +public: + QOstDevicePrivate() : CActive(CActive::EPriorityStandard) { + CActiveScheduler::Add(this); + } + ~QOstDevicePrivate() { + Cancel(); + } + +private: + void RunL(); + void DoCancel(); + +private: + RUsbOstComm ost; + TBuf8<4096> readBuf; + QByteArray dataBuf; +}; + +QOstDevice::QOstDevice(QObject *parent) : + QIODevice(parent), d_ptr(new QOstDevicePrivate) +{ + d_ptr->q_ptr = this; +} + +QOstDevice::~QOstDevice() +{ + close(); + delete d_ptr; +} + +bool QOstDevice::open(int ostProtocolId) +{ + if (isOpen()) + return false; + + Q_D(QOstDevice); + TInt err = d->ost.Connect(); + if (!err) err = d->ost.Open(); + const TVersion KRequiredVersion(1,1,0); + TVersion version = d->ost.Version(); + if (version.iMajor < KRequiredVersion.iMajor || + (version.iMajor == KRequiredVersion.iMajor && version.iMinor < KRequiredVersion.iMinor)) { + setErrorString("CODA version too old. At least version 4.0.18 (without TRK) is required."); + return false; + } + + if (!err) err = d->ost.RegisterProtocolID((TOstProtIds)ostProtocolId, EFalse); + if (!err) { + d->ost.ReadMessage(d->iStatus, d->readBuf); + d->SetActive(); + return QIODevice::open(ReadWrite | Unbuffered); + } + return false; +} + +void QOstDevicePrivate::RunL() +{ + Q_Q(QOstDevice); + //qDebug("QOstDevice received %d bytes q=%x", readBuf.Size(), q); + if (iStatus == KErrNone) { + QByteArray data = QByteArray::fromRawData((const char*)readBuf.Ptr(), readBuf.Size()); + dataBuf.append(data); + + readBuf.Zero(); + ost.ReadMessage(iStatus, readBuf); + SetActive(); + + emit q->readyRead(); + } else { + q->setErrorString(QString("Error %1 from RUsbOstComm::ReadMessage()").arg(iStatus.Int())); + } + //qDebug("-QOstDevicePrivate RunL"); +} + +void QOstDevicePrivate::DoCancel() +{ + ost.ReadCancel(); +} + +void QOstDevice::close() +{ + Q_D(QOstDevice); + QIODevice::close(); + d->Cancel(); + // RDbgTrcComm::Close isn't safe to call when not open, sigh + if (d->ost.Handle()) { + d->ost.Close(); + } +} + +qint64 QOstDevice::readData(char *data, qint64 maxSize) +{ + Q_D(QOstDevice); + if (d->dataBuf.length() == 0 && !d->IsActive()) + return -1; + qint64 available = qMin(maxSize, (qint64)d->dataBuf.length()); + memcpy(data, d->dataBuf.constData(), available); + d->dataBuf.remove(0, available); + return available; +} + +static const TInt KMaxOstPacketLen = 4096; + +qint64 QOstDevice::writeData(const char *data, qint64 maxSize) +{ + Q_D(QOstDevice); + TPtrC8 ptr((const TUint8*)data, (TInt)maxSize); + while (ptr.Length()) { + TPtrC8 fragment = ptr.Left(qMin(ptr.Length(), KMaxOstPacketLen)); + //qDebug("QOstDevice writing %d bytes", fragment.Length()); + TRequestStatus stat; + d->ost.WriteMessage(stat, fragment); + User::WaitForRequest(stat); + if (stat.Int() != KErrNone) { + setErrorString(QString("Error %1 from RUsbOstComm::WriteMessage()").arg(stat.Int())); + return -1; + } + ptr.Set(ptr.Mid(fragment.Length())); + } + emit bytesWritten(maxSize); //TODO does it matter this is emitted synchronously? + //qDebug("QOstDevice wrote %d bytes", ptr.Size()); + return maxSize; +} + +qint64 QOstDevice::bytesAvailable() const +{ + Q_D(const QOstDevice); + return d->dataBuf.length(); +} diff --git a/src/plugins/qmltooling/qmldbg_ost/qostdevice.h b/src/plugins/qmltooling/qmldbg_ost/qostdevice.h new file mode 100644 index 0000000..ba1f443 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_ost/qostdevice.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOSTDEVICE_H +#define QOSTDEVICE_H + +#include <QIODevice.h> + +QT_BEGIN_NAMESPACE + +class QOstDevicePrivate; + +class QOstDevice : public QIODevice +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QOstDevice) + Q_DISABLE_COPY(QOstDevice) + +public: + explicit QOstDevice(QObject *parent=0); + ~QOstDevice(); + + bool open(int ostProtocolId); + void close(); + +protected: + qint64 readData(char *data, qint64 maxSize); + qint64 writeData(const char *data, qint64 maxSize); + qint64 bytesAvailable() const; + +private: + QOstDevicePrivate* d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QOSTDEVICE_H diff --git a/src/plugins/qmltooling/qmldbg_ost/usbostcomm.h b/src/plugins/qmltooling/qmldbg_ost/usbostcomm.h new file mode 100644 index 0000000..48ff7bf --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_ost/usbostcomm.h @@ -0,0 +1,191 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef USBHOSTCOMM_H +#define USBHOSTCOMM_H + +// Based on the official usbostrouter header, modified to remove dependancy on +// the client DLL + +#include <e32base.h> + +typedef int TOstProtIds; + +class RUsbOstComm : public RSessionBase +{ +public: + RUsbOstComm(); + TInt Connect(); + TInt Disconnect(); + TInt Open(); + TInt Close(); + TInt RegisterProtocolID(TOstProtIds aId, TBool aNeedHeader); + void ReadMessage(TRequestStatus& aStatus, TDes8& aDes); + TInt ReadCancel(); + void WriteMessage(TRequestStatus& aStatus, const TDesC8& aDes, TBool aHasHeader=EFalse); + TVersion Version() const; + +private: + enum TUsbOstCmdCode + { + EUsbOstCmdCodeFirst, + EUsbOstCmdConnect, + EUsbOstCmdDisconnect, + EUsbOstCmdCodeGetAcmConfig, + EUsbOstCmdCodeSetAcmConfig, + EUsbOstCmdCodeOpen, + EUsbOstCmdCodeClose, + EUsbOstCmdCodeRegisterId, + EUsbOstCmdCodeRegisterIds, + EUsbOstCmdCodeUnRegisterId, + EUsbOstCmdCodeUnRegisterIds, + EUsbOstCmdCodeReadMsg, + EUsbOstCmdCodeReadCancel, + EUsbOstCmdCodeWriteMsg, + EUsbOstCmdCodeWriteCancel, + EUsbOstCmdCodeLast + }; +}; + +RUsbOstComm::RUsbOstComm() +{ +} + +TInt RUsbOstComm::Connect() +{ + _LIT(KUsbOstServerName, "!UsbOstRouter"); + _LIT(KUsbOstServerImageName, "usbostrouter"); + const TUid KUsbOstServerUid = { 0x200170BE }; + TInt startupAttempts = 2; + for(;;) { + TInt ret = CreateSession(KUsbOstServerName, TVersion(1,0,0)); + if (ret != KErrNotFound && ret != KErrServerTerminated) { + return ret; + } + + if (startupAttempts-- == 0) { + return ret; + } + + RProcess server; + ret = server.Create(KUsbOstServerImageName, KNullDesC, KUsbOstServerUid); + if (ret != KErrNone) + return ret; + + TRequestStatus serverDiedRequestStatus; + server.Rendezvous(serverDiedRequestStatus); + + if (serverDiedRequestStatus != KRequestPending) { + // Abort startup + server.Kill(KErrNone); + } else { + // Logon OK - start the server + server.Resume(); + } + User::WaitForRequest(serverDiedRequestStatus); + ret = (server.ExitType() == EExitPanic) ? KErrGeneral : serverDiedRequestStatus.Int(); + server.Close(); + + if (ret != KErrNone && ret != KErrAlreadyExists) { + return ret; + } + } +} + +TInt RUsbOstComm::Disconnect() +{ + return SendReceive(EUsbOstCmdDisconnect); +} + +TInt RUsbOstComm::Open() +{ + return SendReceive(EUsbOstCmdCodeOpen); +} + +TInt RUsbOstComm::Close() +{ + TInt err = SendReceive(EUsbOstCmdCodeClose); + RHandleBase::Close(); + return err; +} + +TInt RUsbOstComm::RegisterProtocolID(const TOstProtIds aId, TBool aNeedHeader) +{ + TIpcArgs args(aId, aNeedHeader); + return SendReceive(EUsbOstCmdCodeRegisterId, args); +} + +void RUsbOstComm::ReadMessage(TRequestStatus& aStatus, TDes8& aDes) +{ + TIpcArgs args(aDes.MaxLength(), &aDes); + SendReceive(EUsbOstCmdCodeReadMsg, args, aStatus); +} + +TInt RUsbOstComm::ReadCancel() +{ + return SendReceive(EUsbOstCmdCodeReadCancel); +} + +void RUsbOstComm::WriteMessage(TRequestStatus& aStatus, const TDesC8& aDes, TBool aHasHeader) +{ + TIpcArgs args(aHasHeader, aDes.Length(), &aDes); + SendReceive(EUsbOstCmdCodeWriteMsg, args, aStatus); +} + +typedef TVersion (*TVersionFunction)(const RUsbOstComm*); +const TInt KVersionOrdinal = 17; + +TVersion RUsbOstComm::Version() const +{ + // This function has to go to the DLL, unfortunately + TVersion result; // Return 0.0.0 on any error + RLibrary lib; + TInt err = lib.Load(_L("usbostcomm")); + if (err) return result; + + TLibraryFunction fn = lib.Lookup(KVersionOrdinal); + if (fn) + result = ((TVersionFunction)fn)(this); + lib.Close(); + return result; +} + +#endif //USBHOSTCOMM_H diff --git a/src/plugins/qmltooling/tcpserver/tcpserver.pro b/src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro index f4f2666..e8ab962 100644 --- a/src/plugins/qmltooling/tcpserver/tcpserver.pro +++ b/src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro @@ -1,4 +1,4 @@ -TARGET = tcpserver +TARGET = qmldbg_tcp QT += declarative network include(../../qpluginbase.pri) @@ -15,4 +15,4 @@ HEADERS += \ target.path += $$[QT_INSTALL_PLUGINS]/qmltooling INSTALLS += target -symbian:TARGET.UID3=0x20031E90
\ No newline at end of file +symbian:TARGET.UID3=0x20031E90 diff --git a/src/plugins/qmltooling/tcpserver/qtcpserverconnection.cpp b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp index 69c1ef5..7db0db3 100644 --- a/src/plugins/qmltooling/tcpserver/qtcpserverconnection.cpp +++ b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp @@ -97,7 +97,8 @@ void QTcpServerConnection::send(const QByteArray &message) { Q_D(QTcpServerConnection); - if (!isConnected()) + if (!isConnected() + || !d->protocol || !d->socket) return; QPacket pack; @@ -111,9 +112,10 @@ void QTcpServerConnection::disconnect() { Q_D(QTcpServerConnection); - delete d->protocol; + // protocol might still be processing packages at this point + d->protocol->deleteLater(); d->protocol = 0; - delete d->socket; + d->socket->deleteLater(); d->socket = 0; } @@ -143,6 +145,9 @@ void QTcpServerConnection::listen() void QTcpServerConnection::readyRead() { Q_D(QTcpServerConnection); + if (!d->protocol) + return; + QPacket packet = d->protocol->read(); QByteArray content = packet.data(); diff --git a/src/plugins/qmltooling/tcpserver/qtcpserverconnection.h b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.h index a6e17e6..a6e17e6 100644 --- a/src/plugins/qmltooling/tcpserver/qtcpserverconnection.h +++ b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.h diff --git a/src/plugins/qmltooling/qmltooling.pro b/src/plugins/qmltooling/qmltooling.pro index 01cf1a9..9b3346f 100644 --- a/src/plugins/qmltooling/qmltooling.pro +++ b/src/plugins/qmltooling/qmltooling.pro @@ -1,4 +1,4 @@ TEMPLATE = subdirs -SUBDIRS = tcpserver - +SUBDIRS = qmldbg_tcp +symbian:SUBDIRS += qmldbg_ost diff --git a/src/plugins/qpluginbase.pri b/src/plugins/qpluginbase.pri index 3de5fdf..6c33e92 100644 --- a/src/plugins/qpluginbase.pri +++ b/src/plugins/qpluginbase.pri @@ -1,6 +1,6 @@ TEMPLATE = lib isEmpty(QT_MAJOR_VERSION) { - VERSION=4.7.3 + VERSION=4.7.4 } else { VERSION=$${QT_MAJOR_VERSION}.$${QT_MINOR_VERSION}.$${QT_PATCH_VERSION} } diff --git a/src/plugins/sqldrivers/sqlite_symbian/sqlite_symbian.pri b/src/plugins/sqldrivers/sqlite_symbian/sqlite_symbian.pri index 494c64c..b7a87f3 100644 --- a/src/plugins/sqldrivers/sqlite_symbian/sqlite_symbian.pri +++ b/src/plugins/sqldrivers/sqlite_symbian/sqlite_symbian.pri @@ -1,6 +1,12 @@ # We just want to include the sqlite3 binaries for Symbian for platforms that do not have them. !symbian-abld:!symbian-sbsv2 { !symbian_no_export_sqlite:!exists($${EPOCROOT}epoc32/release/armv5/lib/sqlite3.dso) { + contains(QMAKE_HOST.os,Windows) { + # Trick on Windows to do a touch on the file, since copy keeps the timestamp. + copyWithTouch = copy /y /b NUL+ + } else { + copyWithTouch = "$$QMAKE_COPY " + } symbian_sqlite3_zip_file = $$PWD/SQLite3_v9.2.zip # The QMAKE_COPY section is to update timestamp on the file. @@ -10,7 +16,7 @@ symbian_sqlite3_header.CONFIG = combine no_link symbian_sqlite3_header.dependency_type = TYPE_C symbian_sqlite3_header.commands = $$QMAKE_UNZIP -j ${QMAKE_FILE_NAME} epoc32/include/stdapis/${QMAKE_FILE_OUT_BASE}.h \ - && $$QMAKE_COPY ${QMAKE_FILE_OUT_BASE}.h ${QMAKE_FILE_OUT}.tmp \ + && $${copyWithTouch}${QMAKE_FILE_OUT_BASE}.h ${QMAKE_FILE_OUT}.tmp \ && $$QMAKE_DEL_FILE ${QMAKE_FILE_OUT_BASE}.h \ && $$QMAKE_MOVE ${QMAKE_FILE_OUT}.tmp ${QMAKE_FILE_OUT} silent:symbian_sqlite3_header.commands = @echo unzipping $@ && $$symbian_sqlite3_header.commands @@ -22,12 +28,18 @@ !isEmpty(OBJECTS_DIR):symbian_sqlite3_dso.output = $$OBJECTS_DIR/$$symbian_sqlite3_dso.output symbian_sqlite3_dso.CONFIG = combine no_link target_predeps symbian_sqlite3_dso.commands = $$QMAKE_UNZIP -j ${QMAKE_FILE_NAME} epoc32/release/armv5/lib/${QMAKE_FILE_OUT_BASE}.dso \ - && $$QMAKE_COPY ${QMAKE_FILE_OUT_BASE}.dso ${QMAKE_FILE_OUT}.tmp \ + && $${copyWithTouch}${QMAKE_FILE_OUT_BASE}.dso ${QMAKE_FILE_OUT}.tmp \ && $$QMAKE_DEL_FILE ${QMAKE_FILE_OUT_BASE}.dso \ && $$QMAKE_MOVE ${QMAKE_FILE_OUT}.tmp ${QMAKE_FILE_OUT} silent:symbian_sqlite3_dso.commands = @echo unzipping $@ && $$symbian_sqlite3_dso.commands QMAKE_EXTRA_COMPILERS += symbian_sqlite3_dso + # Workaround for the fact that make doesn't understand that sqlite3.dso + # is the same as $OBJECTS_DIR/sqlite3.dso + symbian_sqlite3_dso_standalone.target = sqlite3.dso + symbian_sqlite3_dso_standalone.depends = $$symbian_sqlite3_dso.output + QMAKE_EXTRA_TARGETS += symbian_sqlite3_dso_standalone + symbian_sqlite3_ver_dso.input = symbian_sqlite3_zip_file symbian_sqlite3_ver_dso.output = sqlite3{00060003}.dso !isEmpty(OBJECTS_DIR):symbian_sqlite3_ver_dso.output = $$OBJECTS_DIR/$$symbian_sqlite3_ver_dso.output diff --git a/src/qbase.pri b/src/qbase.pri index babea56..5d78336 100644 --- a/src/qbase.pri +++ b/src/qbase.pri @@ -4,7 +4,7 @@ INCLUDEPATH *= $$QMAKE_INCDIR_QT/$$TARGET #just for today to have some compat isEmpty(QT_ARCH):!isEmpty(ARCH):QT_ARCH=$$ARCH #another compat that will rot for change #215700 TEMPLATE = lib isEmpty(QT_MAJOR_VERSION) { - VERSION=4.7.3 + VERSION=4.7.4 } else { VERSION=$${QT_MAJOR_VERSION}.$${QT_MINOR_VERSION}.$${QT_PATCH_VERSION} } diff --git a/src/qt3support/tools/q3asciidict.qdoc b/src/qt3support/tools/q3asciidict.qdoc index e744633..c276682 100644 --- a/src/qt3support/tools/q3asciidict.qdoc +++ b/src/qt3support/tools/q3asciidict.qdoc @@ -43,7 +43,7 @@ performace as a Q3AsciiDict. Example: - \snippet doc/src/snippets/code/doc_src_q3asciidict.qdoc 0 + \snippet doc/src/snippets/code/doc_src_q3asciidict.cpp 0 In this example we use a dictionary to keep track of the line edits we're using. We insert each line edit into the dictionary with a unique name and then access the line edits via the @@ -164,7 +164,7 @@ \a item may not be 0. Equivalent to: - \snippet doc/src/snippets/code/doc_src_q3asciidict.qdoc 1 + \snippet doc/src/snippets/code/doc_src_q3asciidict.cpp 1 If there are two or more items with equal keys, then the most recently inserted item will be replaced. @@ -295,7 +295,7 @@ iterator that operates on Q3AsciiDict\<X\> (dictionary of X*). Example: - \snippet doc/src/snippets/code/doc_src_q3asciidict.qdoc 2 + \snippet doc/src/snippets/code/doc_src_q3asciidict.cpp 2 In the example we insert some line edits into a dictionary, then iterate over the dictionary printing the strings associated with those line edits. diff --git a/src/qt3support/tools/q3dict.qdoc b/src/qt3support/tools/q3dict.qdoc index 6b221f1..8fcbba4 100644 --- a/src/qt3support/tools/q3dict.qdoc +++ b/src/qt3support/tools/q3dict.qdoc @@ -192,7 +192,7 @@ \a item may not be 0. Equivalent to: - \snippet doc/src/snippets/code/doc_src_q3dict.qdoc 0 + \snippet doc/src/snippets/code/doc_src_q3dict.cpp 0 If there are two or more items with equal keys, then the last item that was inserted will be replaced. @@ -326,7 +326,7 @@ point to the next item in the (arbitrary) traversal order. Example: - \snippet doc/src/snippets/code/doc_src_q3dict.qdoc 1 + \snippet doc/src/snippets/code/doc_src_q3dict.cpp 1 In the example we insert some pointers to line edits into a dictionary, then iterate over the dictionary printing the strings associated with the line edits. diff --git a/src/qt3support/tools/q3intdict.qdoc b/src/qt3support/tools/q3intdict.qdoc index 684fc63..f108f30 100644 --- a/src/qt3support/tools/q3intdict.qdoc +++ b/src/qt3support/tools/q3intdict.qdoc @@ -39,7 +39,7 @@ pointer. Dictionaries provide very fast insertion and lookup. Example: - \snippet doc/src/snippets/code/doc_src_q3intdict.qdoc 0 + \snippet doc/src/snippets/code/doc_src_q3intdict.cpp 0 See Q3Dict for full details, including the choice of dictionary size, and how deletions are handled. @@ -145,7 +145,7 @@ \a item may not be 0. Equivalent to: - \snippet doc/src/snippets/code/doc_src_q3intdict.qdoc 1 + \snippet doc/src/snippets/code/doc_src_q3intdict.cpp 1 If there are two or more items with equal keys, then the most recently inserted item will be replaced. @@ -270,7 +270,7 @@ iterator that operates on Q3IntDict\<X\> (dictionary of X*). Example: - \snippet doc/src/snippets/code/doc_src_q3intdict.qdoc 2 + \snippet doc/src/snippets/code/doc_src_q3intdict.cpp 2 Note that the traversal order is arbitrary; you are not guaranteed the order shown above. diff --git a/src/qt3support/tools/q3memarray.qdoc b/src/qt3support/tools/q3memarray.qdoc index f05f433..5d6f9b2 100644 --- a/src/qt3support/tools/q3memarray.qdoc +++ b/src/qt3support/tools/q3memarray.qdoc @@ -51,7 +51,7 @@ and less copying of data. Example: - \snippet doc/src/snippets/code/doc_src_q3memarray.qdoc 0 + \snippet doc/src/snippets/code/doc_src_q3memarray.cpp 0 Program output: \snippet doc/src/snippets/code/doc_src_q3memarray.qdoc 1 @@ -63,7 +63,7 @@ the remaining bytes will typically be uninitialized, this can cause find() etc. to fail to find the element. Example: - \snippet doc/src/snippets/code/doc_src_q3memarray.qdoc 2 + \snippet doc/src/snippets/code/doc_src_q3memarray.cpp 2 To work around this, make sure that you use a struct where sizeof() returns the same as the sum of the sizes of the members @@ -352,10 +352,10 @@ allocating memory or copying data. Example I (intended use): - \snippet doc/src/snippets/code/doc_src_q3memarray.qdoc 3 + \snippet doc/src/snippets/code/doc_src_q3memarray.cpp 3 Example II (you don't want to do this): - \snippet doc/src/snippets/code/doc_src_q3memarray.qdoc 4 + \snippet doc/src/snippets/code/doc_src_q3memarray.cpp 4 \warning If you do not call resetRawData(), Q3MemArray will attempt to deallocate or reallocate the raw data, which might not be too diff --git a/src/qt3support/tools/q3ptrdict.qdoc b/src/qt3support/tools/q3ptrdict.qdoc index 8831a55..21dcdfd 100644 --- a/src/qt3support/tools/q3ptrdict.qdoc +++ b/src/qt3support/tools/q3ptrdict.qdoc @@ -39,7 +39,7 @@ pointer. Dictionaries provide very fast insertion and lookup. Example: - \snippet doc/src/snippets/code/doc_src_q3ptrdict.qdoc 0 + \snippet doc/src/snippets/code/doc_src_q3ptrdict.cpp 0 In this example we use a dictionary to add an extra property (a char*) to the line edits we're using. @@ -147,7 +147,7 @@ \a item may not be 0. Equivalent to - \snippet doc/src/snippets/code/doc_src_q3ptrdict.qdoc 1 + \snippet doc/src/snippets/code/doc_src_q3ptrdict.cpp 1 If there are two or more items with equal keys, then the most recently inserted item will be replaced. @@ -272,7 +272,7 @@ iterator that operates on Q3PtrDict\<X\> (dictionary of X*). Example: - \snippet doc/src/snippets/code/doc_src_q3ptrdict.qdoc 2 + \snippet doc/src/snippets/code/doc_src_q3ptrdict.cpp 2 In the example we insert some line edits into a dictionary, associating a string with each. We then iterate over the dictionary printing the associated strings. diff --git a/src/qt3support/tools/q3ptrlist.qdoc b/src/qt3support/tools/q3ptrlist.qdoc index 13e478e..e19d6bf 100644 --- a/src/qt3support/tools/q3ptrlist.qdoc +++ b/src/qt3support/tools/q3ptrlist.qdoc @@ -54,10 +54,10 @@ \target example Example: - \snippet doc/src/snippets/code/doc_src_q3ptrlist.qdoc 0 + \snippet doc/src/snippets/code/doc_src_q3ptrlist.cpp 0 The output is - \snippet doc/src/snippets/code/doc_src_q3ptrlist.qdoc 1 + \snippet doc/src/snippets/code/doc_src_q3ptrlist.cpp 1 Q3PtrList has several member functions for traversing the list, but using a Q3PtrListIterator can be more practical. Multiple list @@ -353,7 +353,7 @@ auto-deletion\endlink is enabled. Equivalent to: - \snippet doc/src/snippets/code/doc_src_q3ptrlist.qdoc 2 + \snippet doc/src/snippets/code/doc_src_q3ptrlist.cpp 2 The item after the removed item becomes the new current list item if the removed item is not the last item in the list. If the last @@ -785,10 +785,10 @@ but it uses Q3PtrListIterator. The class Employee is defined there. - \snippet doc/src/snippets/code/doc_src_q3ptrlist.qdoc 3 + \snippet doc/src/snippets/code/doc_src_q3ptrlist.cpp 3 The output is - \snippet doc/src/snippets/code/doc_src_q3ptrlist.qdoc 4 + \snippet doc/src/snippets/code/doc_src_q3ptrlist.cpp 4 Using a list iterator is a more robust way of traversing the list than using the Q3PtrList member functions \link Q3PtrList::first() diff --git a/src/qt3support/tools/q3valuelist.qdoc b/src/qt3support/tools/q3valuelist.qdoc index 99f1634..a5ebf60 100644 --- a/src/qt3support/tools/q3valuelist.qdoc +++ b/src/qt3support/tools/q3valuelist.qdoc @@ -71,7 +71,7 @@ prefer to use the STL-compatible functions. Example: - \snippet doc/src/snippets/code/doc_src_q3valuelist.qdoc 0 + \snippet doc/src/snippets/code/doc_src_q3valuelist.cpp 0 Notice that the latest changes to Mary's salary did not affect the @@ -99,7 +99,7 @@ (your application will crash or do unpredictable things). Use last() and first() with caution, for example: - \snippet doc/src/snippets/code/doc_src_q3valuelist.qdoc 1 + \snippet doc/src/snippets/code/doc_src_q3valuelist.cpp 1 Because Q3ValueList is value-based there is no need to be careful about deleting items in the list. The list holds its own copies @@ -352,7 +352,7 @@ Use the end() function instead. For example: - \snippet doc/src/snippets/code/doc_src_q3valuelist.qdoc 2 + \snippet doc/src/snippets/code/doc_src_q3valuelist.cpp 2 */ @@ -364,7 +364,7 @@ Use the end() function instead. For example: - \snippet doc/src/snippets/code/doc_src_q3valuelist.qdoc 3 + \snippet doc/src/snippets/code/doc_src_q3valuelist.cpp 3 */ @@ -443,7 +443,7 @@ iterator. Example (see Q3ValueList for the complete code): - \snippet doc/src/snippets/code/doc_src_q3valuelist.qdoc 4 + \snippet doc/src/snippets/code/doc_src_q3valuelist.cpp 4 Q3ValueList is highly optimized for performance and memory usage. This means that you must be careful: Q3ValueList does not know diff --git a/src/qt3support/tools/q3valuestack.qdoc b/src/qt3support/tools/q3valuestack.qdoc index 4ad0d7d..6c2c57b 100644 --- a/src/qt3support/tools/q3valuestack.qdoc +++ b/src/qt3support/tools/q3valuestack.qdoc @@ -44,7 +44,7 @@ without removing it. Example: - \snippet doc/src/snippets/code/doc_src_q3valuestack.qdoc 0 + \snippet doc/src/snippets/code/doc_src_q3valuestack.cpp 0 Q3ValueStack is a specialized Q3ValueList provided for convenience. All of Q3ValueList's functionality also applies to Q3PtrStack, for diff --git a/src/qt3support/tools/q3valuevector.qdoc b/src/qt3support/tools/q3valuevector.qdoc index 58bd8e3..960bbac 100644 --- a/src/qt3support/tools/q3valuevector.qdoc +++ b/src/qt3support/tools/q3valuevector.qdoc @@ -70,10 +70,10 @@ objects it contains. Example: - \snippet doc/src/snippets/code/doc_src_q3valuevector.qdoc 0 + \snippet doc/src/snippets/code/doc_src_q3valuevector.cpp 0 Program output: - \snippet doc/src/snippets/code/doc_src_q3valuevector.qdoc 1 + \snippet doc/src/snippets/code/doc_src_q3valuevector.cpp 1 As you can see, the most recent change to Joe's salary did not affect the value in the vector because the vector created a copy @@ -102,13 +102,13 @@ an element that does not exist (your application will probably crash). For example: - \snippet doc/src/snippets/code/doc_src_q3valuevector.qdoc 2 + \snippet doc/src/snippets/code/doc_src_q3valuevector.cpp 2 Whenever inserting, removing or referencing elements in a vector, always make sure you are referring to valid positions. For example: - \snippet doc/src/snippets/code/doc_src_q3valuevector.qdoc 3 + \snippet doc/src/snippets/code/doc_src_q3valuevector.cpp 3 The iterators provided by vector are random access iterators, therefore you can use them with many generic algorithms, for @@ -127,7 +127,7 @@ application will crash or do unpredictable things). Use back() and front() with caution, for example: - \snippet doc/src/snippets/code/doc_src_q3valuevector.qdoc 4 + \snippet doc/src/snippets/code/doc_src_q3valuevector.cpp 4 Because Q3ValueVector manages memory dynamically, it is recommended that you contruct a vector with an initial size. Inserting and diff --git a/src/s60installs/bwins/QtDeclarativeu.def b/src/s60installs/bwins/QtDeclarativeu.def index 8b23b63..5490f0d 100644 --- a/src/s60installs/bwins/QtDeclarativeu.def +++ b/src/s60installs/bwins/QtDeclarativeu.def @@ -1888,4 +1888,9 @@ EXPORTS ??1QDeclarativeRefCount@@UAE@XZ @ 1887 NONAME ; QDeclarativeRefCount::~QDeclarativeRefCount(void) ?addref@QDeclarativeRefCount@@QAEXXZ @ 1888 NONAME ; void QDeclarativeRefCount::addref(void) ?release@QDeclarativeRefCount@@QAEXXZ @ 1889 NONAME ; void QDeclarativeRefCount::release(void) + ?resolveLayoutMirror@QDeclarativeItemPrivate@@QAEXXZ @ 1890 NONAME ; void QDeclarativeItemPrivate::resolveLayoutMirror(void) + ?mirrorChange@QDeclarativeItemPrivate@@UAEXXZ @ 1891 NONAME ; void QDeclarativeItemPrivate::mirrorChange(void) + ?setLayoutMirror@QDeclarativeItemPrivate@@QAEX_N@Z @ 1892 NONAME ; void QDeclarativeItemPrivate::setLayoutMirror(bool) + ?setImplicitLayoutMirror@QDeclarativeItemPrivate@@QAEX_N0@Z @ 1893 NONAME ; void QDeclarativeItemPrivate::setImplicitLayoutMirror(bool, bool) + ?isMirrored@QDeclarativeItemPrivate@@QBE_NXZ @ 1894 NONAME ; bool QDeclarativeItemPrivate::isMirrored(void) const diff --git a/src/s60installs/bwins/QtOpenGLu.def b/src/s60installs/bwins/QtOpenGLu.def index 3eb1512..d7c8394 100644 --- a/src/s60installs/bwins/QtOpenGLu.def +++ b/src/s60installs/bwins/QtOpenGLu.def @@ -711,4 +711,15 @@ EXPORTS ?createPixmapForImage@QGLPixmapData@@AAEXAAVQImage@@V?$QFlags@W4ImageConversionFlag@Qt@@@@_N@Z @ 710 NONAME ; void QGLPixmapData::createPixmapForImage(class QImage &, class QFlags<enum Qt::ImageConversionFlag>, bool) ?fromImageReader@QGLPixmapData@@UAEXPAVQImageReader@@V?$QFlags@W4ImageConversionFlag@Qt@@@@@Z @ 711 NONAME ; void QGLPixmapData::fromImageReader(class QImageReader *, class QFlags<enum Qt::ImageConversionFlag>) ?setContext@QGLTextureGlyphCache@@QAEXPAVQGLContext@@@Z @ 712 NONAME ; void QGLTextureGlyphCache::setContext(class QGLContext *) + ?hibernate@QGLPixmapData@@QAEXXZ @ 713 NONAME ; void QGLPixmapData::hibernate(void) + ?detachTextureFromPool@QGLPixmapData@@QAEXXZ @ 714 NONAME ; void QGLPixmapData::detachTextureFromPool(void) + ?reclaimTexture@QGLPixmapData@@QAEXXZ @ 715 NONAME ; void QGLPixmapData::reclaimTexture(void) + ?destroyTexture@QGLPixmapData@@QAEXXZ @ 716 NONAME ; void QGLPixmapData::destroyTexture(void) + ?releaseCachedResources@QGLGraphicsSystem@@UAEXXZ @ 717 NONAME ; void QGLGraphicsSystem::releaseCachedResources(void) + ?serialNumber@QGLTextureGlyphCache@@QBEHXZ @ 718 NONAME ; int QGLTextureGlyphCache::serialNumber(void) const + ?forceToImage@QGLPixmapData@@QAEXXZ @ 719 NONAME ; void QGLPixmapData::forceToImage(void) + ?idealFormat@QGLPixmapData@@QAE?AW4Format@QImage@@AAV3@V?$QFlags@W4ImageConversionFlag@Qt@@@@@Z @ 720 NONAME ; enum QImage::Format QGLPixmapData::idealFormat(class QImage &, class QFlags<enum Qt::ImageConversionFlag>) + ?releaseNativeImageHandle@QGLPixmapData@@QAEXXZ @ 721 NONAME ; void QGLPixmapData::releaseNativeImageHandle(void) + ?createFromNativeImageHandleProvider@QGLPixmapData@@QAEXXZ @ 722 NONAME ; void QGLPixmapData::createFromNativeImageHandleProvider(void) + ?initFromNativeImageHandle@QGLPixmapData@@QAE_NPAXABVQString@@@Z @ 723 NONAME ; bool QGLPixmapData::initFromNativeImageHandle(void *, class QString const &) diff --git a/src/s60installs/bwins/QtOpenVGu.def b/src/s60installs/bwins/QtOpenVGu.def index 18f576b..f2433d6 100644 --- a/src/s60installs/bwins/QtOpenVGu.def +++ b/src/s60installs/bwins/QtOpenVGu.def @@ -134,7 +134,7 @@ EXPORTS ?drawTextItem@QVGPaintEngine@@UAEXABVQPointF@@ABVQTextItem@@@Z @ 133 NONAME ; void QVGPaintEngine::drawTextItem(class QPointF const &, class QTextItem const &) ?clearScissor@QVGCompositionHelper@@QAEXXZ @ 134 NONAME ; void QVGCompositionHelper::clearScissor(void) ?fill@QVGPaintEngine@@UAEXABVQVectorPath@@ABVQBrush@@@Z @ 135 NONAME ; void QVGPaintEngine::fill(class QVectorPath const &, class QBrush const &) - ?forceToImage@QVGPixmapData@@IAEXXZ @ 136 NONAME ; void QVGPixmapData::forceToImage(void) + ?forceToImage@QVGPixmapData@@IAEXXZ @ 136 NONAME ABSENT ; void QVGPixmapData::forceToImage(void) ?drawPoints@QVGPaintEngine@@UAEXPBVQPoint@@H@Z @ 137 NONAME ; void QVGPaintEngine::drawPoints(class QPoint const *, int) ??_EQVGPaintEngine@@UAE@I@Z @ 138 NONAME ; QVGPaintEngine::~QVGPaintEngine(unsigned int) ?clip@QVGPaintEngine@@UAEXABVQPainterPath@@W4ClipOperation@Qt@@@Z @ 139 NONAME ; void QVGPaintEngine::clip(class QPainterPath const &, enum Qt::ClipOperation) @@ -183,4 +183,5 @@ EXPORTS ?initFromNativeImageHandle@QVGPixmapData@@QAE_NPAXABVQString@@@Z @ 182 NONAME ; bool QVGPixmapData::initFromNativeImageHandle(void *, class QString const &) ?createFromNativeImageHandleProvider@QVGPixmapData@@QAEXXZ @ 183 NONAME ; void QVGPixmapData::createFromNativeImageHandleProvider(void) ?releaseNativeImageHandle@QVGPixmapData@@QAEXXZ @ 184 NONAME ; void QVGPixmapData::releaseNativeImageHandle(void) + ?forceToImage@QVGPixmapData@@IAEX_N@Z @ 185 NONAME ; void QVGPixmapData::forceToImage(bool) diff --git a/src/s60installs/eabi/QtDeclarativeu.def b/src/s60installs/eabi/QtDeclarativeu.def index 130e2d5..2849068 100644 --- a/src/s60installs/eabi/QtDeclarativeu.def +++ b/src/s60installs/eabi/QtDeclarativeu.def @@ -1930,4 +1930,7 @@ EXPORTS _ZN20QDeclarativeRefCountD2Ev @ 1929 NONAME _ZTI20QDeclarativeRefCount @ 1930 NONAME _ZTV20QDeclarativeRefCount @ 1931 NONAME + _ZN23QDeclarativeItemPrivate15setLayoutMirrorEb @ 1932 NONAME + _ZN23QDeclarativeItemPrivate19resolveLayoutMirrorEv @ 1933 NONAME + _ZN23QDeclarativeItemPrivate23setImplicitLayoutMirrorEbb @ 1934 NONAME diff --git a/src/s60installs/eabi/QtOpenGLu.def b/src/s60installs/eabi/QtOpenGLu.def index 33d40fd..488c6cd 100644 --- a/src/s60installs/eabi/QtOpenGLu.def +++ b/src/s60installs/eabi/QtOpenGLu.def @@ -714,4 +714,14 @@ EXPORTS _ZN16QGLWindowSurface12swapBehaviorE @ 713 NONAME DATA 4 _ZN20QGLTextureGlyphCache10setContextEP10QGLContext @ 714 NONAME _ZN20QGLTextureGlyphCache5clearEv @ 715 NONAME + _ZN13QGLPixmapData12forceToImageEv @ 716 NONAME + _ZN13QGLPixmapData14destroyTextureEv @ 717 NONAME + _ZN13QGLPixmapData14reclaimTextureEv @ 718 NONAME + _ZN13QGLPixmapData21detachTextureFromPoolEv @ 719 NONAME + _ZN13QGLPixmapData9hibernateEv @ 720 NONAME + _ZN17QGLGraphicsSystem22releaseCachedResourcesEv @ 721 NONAME + _ZN13QGLPixmapData11idealFormatER6QImage6QFlagsIN2Qt19ImageConversionFlagEE @ 722 NONAME + _ZN13QGLPixmapData24releaseNativeImageHandleEv @ 723 NONAME + _ZN13QGLPixmapData25initFromNativeImageHandleEPvRK7QString @ 724 NONAME + _ZN13QGLPixmapData35createFromNativeImageHandleProviderEv @ 725 NONAME diff --git a/src/s60installs/eabi/QtOpenVGu.def b/src/s60installs/eabi/QtOpenVGu.def index 25c53b8..08afd61 100644 --- a/src/s60installs/eabi/QtOpenVGu.def +++ b/src/s60installs/eabi/QtOpenVGu.def @@ -8,7 +8,7 @@ EXPORTS _Z25qt_vg_create_paint_enginev @ 7 NONAME _Z26qt_vg_destroy_paint_engineP14QVGPaintEngine @ 8 NONAME _Z28qt_vg_config_to_image_formatP11QEglContext @ 9 NONAME - _ZN13QVGPixmapData12forceToImageEv @ 10 NONAME + _ZN13QVGPixmapData12forceToImageEv @ 10 NONAME ABSENT _ZN13QVGPixmapData12toNativeTypeEN11QPixmapData10NativeTypeE @ 11 NONAME _ZN13QVGPixmapData14fromNativeTypeEPvN11QPixmapData10NativeTypeE @ 12 NONAME _ZN13QVGPixmapData15setAlphaChannelERK7QPixmap @ 13 NONAME @@ -213,4 +213,5 @@ EXPORTS _ZN13QVGPixmapData24releaseNativeImageHandleEv @ 212 NONAME _ZN13QVGPixmapData25initFromNativeImageHandleEPvRK7QString @ 213 NONAME _ZN13QVGPixmapData35createFromNativeImageHandleProviderEv @ 214 NONAME + _ZN13QVGPixmapData12forceToImageEb @ 215 NONAME diff --git a/src/s60installs/qt.iby b/src/s60installs/qt.iby index 4afbf05..d6b36e0 100644 --- a/src/s60installs/qt.iby +++ b/src/s60installs/qt.iby @@ -15,7 +15,6 @@ file=ABI_DIR\BUILD_DIR\QtXml.dll SHARED_LIB_DIR\QtXml.dll file=ABI_DIR\BUILD_DIR\QtNetwork.dll SHARED_LIB_DIR\QtNetwork.dll file=ABI_DIR\BUILD_DIR\QtScript.dll SHARED_LIB_DIR\QtScript.dll file=ABI_DIR\BUILD_DIR\QtTest.dll SHARED_LIB_DIR\QtTest.dll -file=ABI_DIR\BUILD_DIR\QtWebKit.dll SHARED_LIB_DIR\QtWebKit.dll file=ABI_DIR\BUILD_DIR\phonon.dll SHARED_LIB_DIR\phonon.dll file=ABI_DIR\BUILD_DIR\QtMultimedia.dll SHARED_LIB_DIR\QtMultimedia.dll file=ABI_DIR\BUILD_DIR\QtXmlPatterns.dll SHARED_LIB_DIR\QtXmlPatterns.dll @@ -40,14 +39,8 @@ file=ABI_DIR\BUILD_DIR\qtwcodecs.dll SHARED_LIB_DIR\qtwcodecs.dll file=ABI_DIR\BUILD_DIR\qsvgicon.dll SHARED_LIB_DIR\qsvgicon.dll // Phonon MMF backend -// This is commented out by default, as normally Helix backend will be used. -// If the Helix backend is present, it will override MMF backend, so make sure to remove it from -// image creation in addition to uncommenting the following lines if you want to use MMF backend. -//file=ABI_DIR\BUILD_DIR\phonon_mmf.dll SHARED_LIB_DIR\phonon_mmf.dll -//data=\epoc32\data\z\resource\qt\plugins\phonon_backend\phonon_mmf.qtplugin resource\qt\plugins\phonon_backend\phonon_mmf.qtplugin - -// QtMultimedia audio backend -file=ABI_DIR\BUILD_DIR\qaudio.dll SHARED_LIB_DIR\qaudio.dll +file=ABI_DIR\BUILD_DIR\phonon_mmf.dll SHARED_LIB_DIR\phonon_mmf.dll +data=\epoc32\data\z\resource\qt\plugins\phonon_backend\phonon_mmf.qtplugin resource\qt\plugins\phonon_backend\phonon_mmf.qtplugin // graphicssystems file=ABI_DIR\BUILD_DIR\qvggraphicssystem.dll SHARED_LIB_DIR\qvggraphicssystem.dll @@ -60,8 +53,6 @@ file=ABI_DIR\BUILD_DIR\qsymbianbearer.dll SHARED_LIB_DIR\qsymbianbearer.dll // so don't bother including those plugins file=ABI_DIR\BUILD_DIR\qts60plugin_5_0.dll SHARED_LIB_DIR\qts60plugin_5_0.dll -S60_APP_RESOURCE(s60main) - // imageformats stubs data=\epoc32\data\z\resource\qt\plugins\imageformats\qgif.qtplugin resource\qt\plugins\imageformats\qgif.qtplugin data=\epoc32\data\z\resource\qt\plugins\imageformats\qico.qtplugin resource\qt\plugins\imageformats\qico.qtplugin @@ -80,24 +71,18 @@ data=\epoc32\data\z\resource\qt\plugins\codecs\qtwcodecs.qtplugin resou data=\epoc32\data\z\resource\qt\plugins\iconengines\qsvgicon.qtplugin resource\qt\plugins\iconengines\qsvgicon.qtplugin // qml import plugins -file=ABI_DIR\BUILD_DIR\qmlwebkitplugin.dll SHARED_LIB_DIR\qmlwebkitplugin.dll file=ABI_DIR\BUILD_DIR\qmlfolderlistmodelplugin.dll SHARED_LIB_DIR\qmlfolderlistmodelplugin.dll file=ABI_DIR\BUILD_DIR\qmlgesturesplugin.dll SHARED_LIB_DIR\qmlgesturesplugin.dll file=ABI_DIR\BUILD_DIR\qmlparticlesplugin.dll SHARED_LIB_DIR\qmlparticlesplugin.dll -data=\epoc32\data\z\resource\qt\imports\QtWebKit\qmlwebkitplugin.qtplugin resource\qt\imports\QtWebKit\qmlwebkitplugin.qtplugin data=\epoc32\data\z\resource\qt\imports\Qt\labs\folderlistmodel\qmlfolderlistmodelplugin.qtplugin resource\qt\imports\Qt\labs\folderlistmodel\qmlfolderlistmodelplugin.qtplugin data=\epoc32\data\z\resource\qt\imports\Qt\labs\gestures\qmlgesturesplugin.qtplugin resource\qt\imports\Qt\labs\gestures\qmlgesturesplugin.qtplugin data=\epoc32\data\z\resource\qt\imports\Qt\labs\particles\qmlparticlesplugin.qtplugin resource\qt\imports\Qt\labs\particles\qmlparticlesplugin.qtplugin -data=\epoc32\data\z\resource\qt\imports\QtWebKit\qmldir resource\qt\imports\QtWebKit\qmldir data=\epoc32\data\z\resource\qt\imports\Qt\labs\folderlistmodel\qmldir resource\qt\imports\Qt\labs\folderlistmodel\qmldir data=\epoc32\data\z\resource\qt\imports\Qt\labs\gestures\qmldir resource\qt\imports\Qt\labs\gestures\qmldir data=\epoc32\data\z\resource\qt\imports\Qt\labs\particles\qmldir resource\qt\imports\Qt\labs\particles\qmldir -// QtMultimedia audio backend -data=\epoc32\data\qt\qtlibspluginstubs\qaudio.qtplugin resource\qt\plugins\audio\qaudio.qtplugin - // graphicssystems data=\epoc32\data\z\resource\qt\plugins\graphicssystems\qvggraphicssystem.qtplugin resource\qt\plugins\graphicssystems\qvggraphicssystem.qtplugin data=\epoc32\data\z\resource\qt\plugins\graphicssystems\qglgraphicssystem.qtplugin resource\qt\plugins\graphicssystems\qglgraphicssystem.qtplugin @@ -107,7 +92,6 @@ data=\epoc32\data\z\resource\qt\plugins\bearer\qsymbianbearer.qtplugin resource\ // Stub sis file data=ZSYSTEM\install\qt_stub.sis System\Install\qt_stub.sis -data=ZSYSTEM\install\qtwebkit_stub.sis System\Install\qtwebkit_stub.sis #endif // __QT_IBY__ diff --git a/src/s60installs/s60installs.pro b/src/s60installs/s60installs.pro index 1e5ce0f..d1bb48b 100644 --- a/src/s60installs/s60installs.pro +++ b/src/s60installs/s60installs.pro @@ -42,7 +42,7 @@ symbian: { contains(S60_VERSION, 3.1)|contains(S60_VERSION, 3.2)|contains(S60_VERSION, 5.0) { qts60plugindeployment = \ - "IF package(0x20022E6D)" \ + "IF package(0x2003A678) OR package(0x20022E6D)" \ " \"$$pluginLocations/qts60plugin_5_0$${QT_LIBINFIX}.dll\" - \"c:\\sys\\bin\\qts60plugin_5_0$${QT_LIBINFIX}.dll\"" \ " \"$$bearerPluginLocation/qsymbianbearer$${QT_LIBINFIX}.dll\" - \"c:\\sys\\bin\\qsymbianbearer$${QT_LIBINFIX}.dll\"" \ "ELSEIF package(0x1028315F)" \ @@ -58,7 +58,7 @@ symbian: { " \"$$pluginLocations/qts60plugin_5_0$${QT_LIBINFIX}.dll\" - \"c:\\sys\\bin\\qts60plugin_5_0$${QT_LIBINFIX}.dll\"" \ " \"$$bearerPluginLocation/qsymbianbearer$${QT_LIBINFIX}.dll\" - \"c:\\sys\\bin\\qsymbianbearer$${QT_LIBINFIX}.dll\"" \ "ENDIF" \ - " \"$$bearerStubZ\" - \"c:$$replace(QT_PLUGINS_BASE_DIR,/,\\)\\bearer\\qsymbianbearer$${QT_LIBINFIX}.qtplugin\" + " \"$$bearerStubZ\" - \"c:$$replace(QT_PLUGINS_BASE_DIR,/,\\)\\bearer\\qsymbianbearer$${QT_LIBINFIX}.qtplugin\"" } else { # No need to deploy plugins for older platform versions when building on Symbian3 or later qts60plugindeployment = \ diff --git a/src/s60main/s60main.pro b/src/s60main/s60main.pro index 8ab3bd3..1e3e06a 100644 --- a/src/s60main/s60main.pro +++ b/src/s60main/s60main.pro @@ -30,7 +30,7 @@ symbian { # Having MMP_RULES_DONT_EXPORT_ALL_CLASS_IMPEDIMENTA will cause s60main.lib be unlinkable # against GCCE apps, so remove it MMP_RULES -= $$MMP_RULES_DONT_EXPORT_ALL_CLASS_IMPEDIMENTA - linux-armcc:QMAKE_CXXFLAGS *= --export_all_vtbl + symbian-armcc:QMAKE_CXXFLAGS *= --export_all_vtbl # Flag if exports are not frozen to avoid lookup of qtcore allocator creation function by ordinal contains(CONFIG, def_files_disabled): DEFINES += QT_EXPORTS_NOT_FROZEN diff --git a/src/src.pro b/src/src.pro index 060f48b..868e22f 100644 --- a/src/src.pro +++ b/src/src.pro @@ -108,7 +108,7 @@ src_webkit_declarative.target = sub-webkitdeclarative src_phonon.depends = src_gui src_multimedia.depends = src_gui contains(QT_CONFIG, opengl):src_multimedia.depends += src_opengl - src_tools_activeqt.depends = src_tools_idc src_gui + src_activeqt.depends = src_tools_idc src_gui src_declarative.depends = src_gui src_script src_network src_plugins.depends = src_gui src_sql src_svg contains(QT_CONFIG, multimedia):src_plugins.depends += src_multimedia diff --git a/src/testlib/qsignalspy.qdoc b/src/testlib/qsignalspy.qdoc index 298b2b7..0c22868 100644 --- a/src/testlib/qsignalspy.qdoc +++ b/src/testlib/qsignalspy.qdoc @@ -38,7 +38,7 @@ The following example records all signal emissions for the \c clicked() signal of a QCheckBox: - \snippet doc/src/snippets/code/doc_src_qsignalspy.qdoc 0 + \snippet doc/src/snippets/code/doc_src_qsignalspy.cpp 0 \c{spy.takeFirst()} returns the arguments for the first emitted signal, as a list of QVariant objects. The \c clicked() signal has a single bool argument, @@ -46,17 +46,17 @@ The example below catches a signal from a custom object: - \snippet doc/src/snippets/code/doc_src_qsignalspy.qdoc 1 + \snippet doc/src/snippets/code/doc_src_qsignalspy.cpp 1 \bold {Note:} Non-standard data types need to be registered, using the qRegisterMetaType() function, before you can create a QSignalSpy. For example: - \snippet doc/src/snippets/code/doc_src_qsignalspy.qdoc 2 + \snippet doc/src/snippets/code/doc_src_qsignalspy.cpp 2 To retrieve the \c QModelIndex, you can use qvariant_cast: - \snippet doc/src/snippets/code/doc_src_qsignalspy.qdoc 3 + \snippet doc/src/snippets/code/doc_src_qsignalspy.cpp 3 */ /*! \fn QSignalSpy::QSignalSpy(QObject *object, const char *signal) @@ -65,7 +65,7 @@ from the QObject \a object. Neither \a signal nor \a object can be null. Example: - \snippet doc/src/snippets/code/doc_src_qsignalspy.qdoc 4 + \snippet doc/src/snippets/code/doc_src_qsignalspy.cpp 4 */ /*! \fn QSignalSpy::isValid() const diff --git a/src/testlib/qtestevent.qdoc b/src/testlib/qtestevent.qdoc index 84e874b..4c695c2 100644 --- a/src/testlib/qtestevent.qdoc +++ b/src/testlib/qtestevent.qdoc @@ -39,7 +39,7 @@ QWidget. Example: - \snippet doc/src/snippets/code/doc_src_qtestevent.qdoc 0 + \snippet doc/src/snippets/code/doc_src_qtestevent.cpp 0 The example above simulates the user entering the character \c a followed by a backspace, waiting for 200 milliseconds and |